diff --git a/jobs/rep/templates/bpm.yml.erb b/jobs/rep/templates/bpm.yml.erb index 1a324da857..3e1d39aed6 100644 --- a/jobs/rep/templates/bpm.yml.erb +++ b/jobs/rep/templates/bpm.yml.erb @@ -2,6 +2,9 @@ processes: - name: rep executable: /var/vcap/jobs/rep/bin/rep + # This is required to preserve the file capabilities of cf-pcap to allow the vcap user to capture + # packets inside the app container without root. + capabilities: [ "SETFCAP" ] limits: open_files: 100000 hooks: diff --git a/packages/buildpack_app_lifecycle/packaging b/packages/buildpack_app_lifecycle/packaging index 7aa9f7622b..66d2937e93 100644 --- a/packages/buildpack_app_lifecycle/packaging +++ b/packages/buildpack_app_lifecycle/packaging @@ -27,12 +27,16 @@ ldd $DEST/launcher && echo "launcher must be statically linked" && false cp /var/vcap/packages/diego-sshd/diego-sshd ${DEST}/diego-sshd cp /var/vcap/packages/diego-sshd/*.exe ${DEST} cp /var/vcap/packages/diego-sshd/winpty.dll ${DEST}/winpty.dll +cp /var/vcap/packages/cf-pcap/cf-pcap ${DEST}/cf-pcap cp /var/vcap/packages/healthcheck/healthcheck ${DEST}/healthcheck cp /var/vcap/packages/healthcheck/healthcheck.exe ${DEST}/healthcheck.exe +setcap cap_net_raw+ep ${DEST}/cf-pcap + tar -czf ${BOSH_INSTALL_TARGET}/buildpack_app_lifecycle.tgz \ + --xattrs --xattrs-include='*' \ -C ${DEST} \ - builder launcher shell healthcheck diego-sshd \ + builder launcher shell healthcheck diego-sshd cf-pcap \ builder.exe launcher.exe getenv.exe healthcheck.exe diego-sshd.exe \ winpty-agent.exe winpty.dll diff --git a/packages/buildpack_app_lifecycle/spec b/packages/buildpack_app_lifecycle/spec index 17c2b573ed..d953750c54 100644 --- a/packages/buildpack_app_lifecycle/spec +++ b/packages/buildpack_app_lifecycle/spec @@ -5,6 +5,7 @@ dependencies: - golang-1.25-linux - healthcheck - diego-sshd + - cf-pcap files: - code.cloudfoundry.org/go.mod diff --git a/packages/cf-pcap/packaging b/packages/cf-pcap/packaging new file mode 100644 index 0000000000..dab97610ef --- /dev/null +++ b/packages/cf-pcap/packaging @@ -0,0 +1,18 @@ +set -e + +pushd libpcap-1.10.5 + ./configure + make +popd + +source /var/vcap/packages/golang-*-linux/bosh/compile.env + +pushd code.cloudfoundry.org + # -I adds the local libpcap to the search path for the compiler + export CGO_CFLAGS="-I${BOSH_COMPILE_TARGET}/libpcap-1.10.5" + # -L adds the local libpcap to the search path for the linker + # -linkmode external: use an external linker: https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/cmd/cgo/doc.go;l=794 + # -extldflags -static: pass -static to ld, see man page for details + export CGO_LDFLAGS="-L${BOSH_COMPILE_TARGET}/libpcap-1.10.5 -static" + go build -ldflags '-linkmode external' -o ${BOSH_INSTALL_TARGET}/cf-pcap -a -installsuffix static code.cloudfoundry.org/cf-pcap +popd diff --git a/packages/cf-pcap/spec b/packages/cf-pcap/spec new file mode 100644 index 0000000000..fef8443aa5 --- /dev/null +++ b/packages/cf-pcap/spec @@ -0,0 +1,20 @@ +--- +name: cf-pcap +dependencies: + - golang-1.25-linux + +files: + - libpcap-1.10.5/**/* + - code.cloudfoundry.org/go.mod + - code.cloudfoundry.org/go.sum + - code.cloudfoundry.org/vendor/modules.txt + - code.cloudfoundry.org/cf-pcap/*.go # gosub + - code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/*.go # gosub + - code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/endian/*.go # gosub + - code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/*.go # gosub + - code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/*.go # gosub + - code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/net/bpf/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/sys/unix/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/sys/unix/*.s # gosub + - code.cloudfoundry.org/vendor/golang.org/x/sys/windows/*.go # gosub diff --git a/packages/cnb_app_lifecycle/packaging b/packages/cnb_app_lifecycle/packaging index 38f1b757d8..c97da54f27 100644 --- a/packages/cnb_app_lifecycle/packaging +++ b/packages/cnb_app_lifecycle/packaging @@ -20,8 +20,12 @@ ldd $DEST/builder && echo "builder must be statically linked" && false ldd $DEST/launcher && echo "launcher must be statically linked" && false cp /var/vcap/packages/diego-sshd/diego-sshd ${DEST}/diego-sshd +cp /var/vcap/packages/cf-pcap/cf-pcap ${DEST}/cf-pcap cp /var/vcap/packages/healthcheck/healthcheck ${DEST}/healthcheck +setcap cap_net_raw+ep ${DEST}/cf-pcap + tar -czf ${BOSH_INSTALL_TARGET}/cnb_app_lifecycle.tgz \ + --xattrs --xattrs-include='*' \ -C ${DEST} \ - builder launcher healthcheck diego-sshd + builder launcher healthcheck diego-sshd cf-pcap diff --git a/packages/cnb_app_lifecycle/spec b/packages/cnb_app_lifecycle/spec index 08909e31b1..3998621df8 100644 --- a/packages/cnb_app_lifecycle/spec +++ b/packages/cnb_app_lifecycle/spec @@ -5,6 +5,7 @@ dependencies: - golang-1.25-linux - healthcheck - diego-sshd + - cf-pcap files: - cnbapplifecycle/go.mod diff --git a/packages/docker_app_lifecycle/packaging b/packages/docker_app_lifecycle/packaging index 6cff22382d..e0976891ed 100644 --- a/packages/docker_app_lifecycle/packaging +++ b/packages/docker_app_lifecycle/packaging @@ -19,6 +19,11 @@ ldd ${DEST}/builder && echo "builder must be statically linked" && false ldd ${DEST}/launcher && echo "launcher must be statically linked" && false cp /var/vcap/packages/diego-sshd/diego-sshd ${DEST}/diego-sshd +cp /var/vcap/packages/cf-pcap/cf-pcap ${DEST}/cf-pcap cp /var/vcap/packages/healthcheck/healthcheck ${DEST}/healthcheck -tar -czf ${BOSH_INSTALL_TARGET}/docker_app_lifecycle.tgz -C ${DEST} builder launcher healthcheck diego-sshd +setcap cap_net_raw+ep ${DEST}/cf-pcap + +tar -czf ${BOSH_INSTALL_TARGET}/docker_app_lifecycle.tgz \ + --xattrs --xattrs-include='*' \ + -C ${DEST} builder launcher healthcheck diego-sshd cf-pcap diff --git a/packages/docker_app_lifecycle/spec b/packages/docker_app_lifecycle/spec index e2325cc28c..53628319b8 100644 --- a/packages/docker_app_lifecycle/spec +++ b/packages/docker_app_lifecycle/spec @@ -5,6 +5,7 @@ dependencies: - golang-1.25-linux - healthcheck - diego-sshd + - cf-pcap files: - code.cloudfoundry.org/go.mod diff --git a/src/code.cloudfoundry.org/cf-pcap/pcap.go b/src/code.cloudfoundry.org/cf-pcap/pcap.go new file mode 100644 index 0000000000..d155ffb9a0 --- /dev/null +++ b/src/code.cloudfoundry.org/cf-pcap/pcap.go @@ -0,0 +1,137 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log/slog" + "os" + "os/signal" + "syscall" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/pcap" + "github.com/gopacket/gopacket/pcapgo" +) + +var ( + interfaceName = flag.String("interface", "", "Network interface to capture from (e.g. eth0, any)") + snaplen = flag.Int("snaplen", 65535, "Snapshot length - max bytes to capture per packet") + filter = flag.String("filter", "", "BPF filter expression (e.g. 'tcp port 80')") + verbose = flag.Bool("v", false, "Verbose output") +) + +var ( + logLevel = &slog.LevelVar{} +) + +func init() { + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel}))) +} + +func main() { + os.Exit(Main()) +} + +func Main() int { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + flag.Parse() + + if *interfaceName == "" { + slog.Error("interface flag is required") + return 1 + } + + if *verbose { + logLevel.Set(slog.LevelDebug) + } + + slog.Debug("parsed flags", + "interface", *interfaceName, + "snaplen", *snaplen, + "filter", *filter, + ) + + errC := Capture(ctx, *interfaceName, *snaplen, *filter) + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + + select { + case err := <-errC: + if err != nil { + slog.Error("capture failed", "error", err) + return 1 + } + case sig := <-sigChan: + slog.Info("received signal, stopping capture", "signal", sig.String()) + cancel() + } + + // drain channel to ensure clean shutdown + for range errC { + } + + return 0 +} + +func Capture(ctx context.Context, interfaceName string, snaplen int, filter string) <-chan error { + errC := make(chan error, 1) + + handle, err := pcap.OpenLive(interfaceName, int32(snaplen), true, pcap.BlockForever) + if err != nil { + errC <- fmt.Errorf("failed to open device %s: %w", interfaceName, err) + return errC + } + + if filter != "" { + // TODO: we should somehow filter out our own SSH traffic. This is not as easy because the + // connection is broken off more than once and we'd have to know the diego-sshd server port + // which is probably configurable. + err = handle.SetBPFFilter(filter) + if err != nil { + handle.Close() + errC <- fmt.Errorf("failed to set BPF filter '%s': %w", filter, err) + return errC + } + } + + pcapWriter := pcapgo.NewWriter(os.Stdout) + err = pcapWriter.WriteFileHeader(uint32(snaplen), handle.LinkType()) + if err != nil { + handle.Close() + errC <- fmt.Errorf("failed to write pcap header: %w", err) + return errC + } + + go func(ctx context.Context, h *pcap.Handle, w *pcapgo.Writer, errC chan error) { + defer h.Close() + s := gopacket.NewPacketSource(h, h.LinkType()) + + var err error + packetLoop: + for { + select { + case <-ctx.Done(): + h.Close() + case packet, ok := <-s.Packets(): + if !ok { + break packetLoop + } else if packet == nil { + continue + } + + err = w.WritePacket(packet.Metadata().CaptureInfo, packet.Data()) + if err != nil { + break packetLoop + } + } + } + + errC <- err + }(ctx, handle, pcapWriter, errC) + + return errC +} diff --git a/src/code.cloudfoundry.org/go.mod b/src/code.cloudfoundry.org/go.mod index 7a332b31f2..6772f97f48 100644 --- a/src/code.cloudfoundry.org/go.mod +++ b/src/code.cloudfoundry.org/go.mod @@ -53,6 +53,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.2 github.com/golang/protobuf v1.5.4 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 + github.com/gopacket/gopacket v1.5.0 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/go-multierror v1.1.1 github.com/jackc/pgx/v5 v5.8.0 diff --git a/src/code.cloudfoundry.org/go.sum b/src/code.cloudfoundry.org/go.sum index ac2065a961..bba2318bd1 100644 --- a/src/code.cloudfoundry.org/go.sum +++ b/src/code.cloudfoundry.org/go.sum @@ -980,6 +980,8 @@ github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57Q github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M= +github.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/.gitignore b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/.gitignore new file mode 100644 index 0000000000..b79b2e2d32 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/.gitignore @@ -0,0 +1,39 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +#* +*~ + +# examples binaries +examples/synscan/synscan +examples/pfdump/pfdump +examples/pcapdump/pcapdump +examples/httpassembly/httpassembly +examples/statsassembly/statsassembly +examples/arpscan/arpscan +examples/bidirectional/bidirectional +examples/bytediff/bytediff +examples/reassemblydump/reassemblydump +layers/gen +macs/gen +pcap/pcap_tester +.idea/ \ No newline at end of file diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/AUTHORS b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/AUTHORS new file mode 100644 index 0000000000..24e834e451 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/AUTHORS @@ -0,0 +1,54 @@ +AUTHORS AND MAINTAINERS: + +MAIN DEVELOPERS: +Graeme Connell + +AUTHORS: +Nigel Tao +Cole Mickens +Ben Daglish +Luis Martinez +Remco Verhoef +Hiroaki Kawai +Lukas Lueg +Laurent Hausermann +Bill Green +Christian Mäder +Gernot Vormayr +Vitor Garcia Graveto +Elias Chavarria Reyes +Daniel Rittweiler + +CONTRIBUTORS: +Attila Oláh +Vittus Mikiassen +Matthias Radestock +Matthew Sackman +Loic Prylli +Alexandre Fiori +Adrian Tam +Satoshi Matsumoto +David Stainton +Jesse Ward +Kane Mathers +Jose Selvi +Yerden Zhumabekov +Jensen Hwa + +----------------------------------------------- +FORKED FROM github.com/akrennmair/gopcap +ALL THE FOLLOWING ARE FOR THAT PROJECT + +MAIN DEVELOPERS: +Andreas Krennmair + +CONTRIBUTORS: +Andrea Nall +Daniel Arndt +Dustin Sallings +Graeme Connell +Guillaume Savary +Mark Smith +Miek Gieben +Mike Bell +Trevor Strohman diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/CONTRIBUTING.md b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/CONTRIBUTING.md new file mode 100644 index 0000000000..ac32ea3d2c --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/CONTRIBUTING.md @@ -0,0 +1,215 @@ +Contributing To gopacket +======================== + +So you've got some code and you'd like it to be part of gopacket... wonderful! +We're happy to accept contributions, whether they're fixes to old protocols, new +protocols entirely, or anything else you think would improve the gopacket +library. This document is designed to help you to do just that. + +The first section deals with the plumbing: how to actually get a change +submitted. + +The second section deals with coding style... Go is great in that it +has a uniform style implemented by 'go fmt', but there's still some decisions +we've made that go above and beyond, and if you follow them, they won't come up +in your code review. + +The third section deals with some of the implementation decisions we've made, +which may help you to understand the current code and which we may ask you to +conform to (or provide compelling reasons for ignoring). + +Overall, we hope this document will help you to understand our system and write +great code which fits in, and help us to turn around on your code review quickly +so the code can make it into the master branch as quickly as possible. + + +How To Submit Code +------------------ + +We use github.com's Pull Request feature to receive code contributions from +external contributors. See +https://help.github.com/articles/creating-a-pull-request/ for details on +how to create a request. + +Also, there's a local script `gc` in the base directory of GoPacket that +runs a local set of checks, which should give you relatively high confidence +that your pull won't fail github pull checks. + +```sh +go get github.com/gopacket/gopacket +cd $GOROOT/src/pkg/github.com/gopacket/gopacket +git checkout -b # create a new branch to work from +... code code code ... +./gc # Run this to do local commits, it performs a number of checks +``` + +To sum up: + +* DO + + Pull down the latest version. + + Make a feature-specific branch. + + Code using the style and methods discussed in the rest of this document. + + Use the ./gc command to do local commits or check correctness. + + Push your new feature branch up to github.com, as a pull request. + + Handle comments and requests from reviewers, pushing new commits up to + your feature branch as problems are addressed. + + Put interesting comments and discussions into commit comments. +* DON'T + + Push to someone else's branch without their permission. + + +Coding Style +------------ + +* Go code must be run through `go fmt`, `go vet`, and `golint` +* Follow http://golang.org/doc/effective_go.html as much as possible. + + In particular, http://golang.org/doc/effective_go.html#mixed-caps. Enums + should be be CamelCase, with acronyms capitalized (TCPSourcePort, vs. + TcpSourcePort or TCP_SOURCE_PORT). +* Bonus points for giving enum types a String() field. +* Any exported types or functions should have commentary + (http://golang.org/doc/effective_go.html#commentary) + + +Coding Methods And Implementation Notes +--------------------------------------- + +### Error Handling + +Many times, you'll be decoding a protocol and run across something bad, a packet +corruption or the like. How do you handle this? First off, ALWAYS report the +error. You can do this either by returning the error from the decode() function +(most common), or if you're up for it you can implement and add an ErrorLayer +through the packet builder (the first method is a simple shortcut that does +exactly this, then stops any future decoding). + +Often, you'll already have decode some part of your protocol by the time you hit +your error. Use your own discretion to determine whether the stuff you've +already decoded should be returned to the caller or not: + +```go +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + prot := &MyProtocol{} + if len(data) < 10 { + // This error occurred before we did ANYTHING, so there's nothing in my + // protocol that the caller could possibly want. Just return the error. + return fmt.Errorf("Length %d less than 10", len(data)) + } + prot.ImportantField1 = data[:5] + prot.ImportantField2 = data[5:10] + // At this point, we've already got enough information in 'prot' to + // warrant returning it to the caller, so we'll add it now. + p.AddLayer(prot) + if len(data) < 15 { + // We encountered an error later in the packet, but the caller already + // has the important info we've gleaned so far. + return fmt.Errorf("Length %d less than 15", len(data)) + } + prot.ImportantField3 = data[10:15] + return nil // We've already added the layer, we can just return success. +} +``` + +In general, our code follows the approach of returning the first error it +encounters. In general, we don't trust any bytes after the first error we see. + +### What Is A Layer? + +The definition of a layer is up to the discretion of the coder. It should be +something important enough that it's actually useful to the caller (IE: every +TLV value should probably NOT be a layer). However, it can be more granular +than a single protocol... IPv6 and SCTP both implement many layers to handle the +various parts of the protocol. Use your best judgement, and prepare to defend +your decisions during code review. ;) + +### Performance + +We strive to make gopacket as fast as possible while still providing lots of +features. In general, this means: + +* Focus performance tuning on common protocols (IP4/6, TCP, etc), and optimize + others on an as-needed basis (tons of MPLS on your network? Time to optimize + MPLS!) +* Use fast operations. See the toplevel benchmark_test for benchmarks of some + of Go's underlying features and types. +* Test your performance changes! You should use the ./gc script's --benchmark + flag to submit any performance-related changes. Use pcap/gopacket_benchmark + to test your change against a PCAP file based on your traffic patterns. +* Don't be TOO hacky. Sometimes, removing an unused struct from a field causes + a huge performance hit, due to the way that Go currently handles its segmented + stack... don't be afraid to clean it up anyway. We'll trust the Go compiler + to get good enough over time to handle this. Also, this type of + compiler-specific optimization is very fragile; someone adding a field to an + entirely different struct elsewhere in the codebase could reverse any gains + you might achieve by aligning your allocations. +* Try to minimize memory allocations. If possible, use []byte to reference + pieces of the input, instead of using string, which requires copying the bytes + into a new memory allocation. +* Think hard about what should be evaluated lazily vs. not. In general, a + layer's struct should almost exactly mirror the layer's frame. Anything + that's more interesting should be a function. This may not always be + possible, but it's a good rule of thumb. +* Don't fear micro-optimizations. With the above in mind, we welcome + micro-optimizations that we think will have positive/neutral impacts on the + majority of workloads. A prime example of this is pre-allocating certain + structs within a larger one: + +```go +type MyProtocol struct { + // Most packets have 1-4 of VeryCommon, so we preallocate it here. + initialAllocation [4]uint32 + VeryCommon []uint32 +} + +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + prot := &MyProtocol{} + prot.VeryCommon = proto.initialAllocation[:0] + for len(data) > 4 { + field := binary.BigEndian.Uint32(data[:4]) + data = data[4:] + // Since we're using the underlying initialAllocation, we won't need to + // allocate new memory for the following append unless we more than 16 + // bytes of data, which should be the uncommon case. + prot.VeryCommon = append(prot.VeryCommon, field) + } + p.AddLayer(prot) + if len(data) > 0 { + return fmt.Errorf("MyProtocol packet has %d bytes left after decoding", len(data)) + } + return nil +} +``` + +### Slices And Data + +If you're pulling a slice from the data you're decoding, don't copy it. Just +use the slice itself. + +```go +type MyProtocol struct { + A, B net.IP +} +func decodeMyProtocol(data []byte, p gopacket.PacketBuilder) error { + p.AddLayer(&MyProtocol{ + A: data[:4], + B: data[4:8], + }) + return nil +} +``` + +The caller has already agreed, by using this library, that they won't modify the +set of bytes they pass in to the decoder, or the library has already copied the +set of bytes to a read-only location. See DecodeOptions.NoCopy for more +information. + +### Enums/Types + +If a protocol has an integer field (uint8, uint16, etc) with a couple of known +values that mean something special, make it a type. This allows us to do really +nice things like adding a String() function to them, so we can more easily +display those to users. Check out layers/enums.go for one example, as well as +layers/icmp.go for layer-specific enums. + +When naming things, try for descriptiveness over suscinctness. For example, +choose DNSResponseRecord over DNSRR. diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/INDUSTRIAL_PROTOCOLS_PATCH.md b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/INDUSTRIAL_PROTOCOLS_PATCH.md new file mode 100644 index 0000000000..8395c82221 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/INDUSTRIAL_PROTOCOLS_PATCH.md @@ -0,0 +1,97 @@ +# Patch Set Summary: Industrial Protocol Support (CIP, Ethernet/IP) + +## Overview + +This patch set ports the changes from [google/gopacket PR #758](https://github.com/google/gopacket/pull/758) to add support for industrial automation protocols: **CIP** (Common Industrial Protocol), and **ENIP** (Ethernet/IP). + +## New Protocol Implementations + +### 1. CIP (Common Industrial Protocol) +**File**: `layers/cip.go` + +- **Purpose**: Application-layer protocol used in industrial automation +- **Key Features**: + - Service code definitions (GetAttributesAll, SetAttributesAll, GetAttributeSingle, SetAttributeSingle, MultipleServicePacket) + - Status code handling (Success, ConnectionFailure, ResourceUnavailable, etc.) + - Path segment parsing for Class ID, Instance ID, and Attribute ID + - Request/Response differentiation + - Full decoder implementation following gopacket patterns + +### 2. ENIP (Ethernet/IP) +**File**: `layers/enip.go` + +- **Purpose**: Ethernet encapsulation protocol for CIP +- **Key Features**: + - 24-byte header parsing + - Command codes (NOP, ListServices, RegisterSession, UnregisterSession, SendRRData, SendUnitData, etc.) + - Status code handling + - Session management fields (SessionHandle, SenderContext) + - Automatic CIP payload decoding for SendRRData and SendUnitData commands + - Serialization support + - Little-endian encoding (as per ENIP specification) + +## Modified Files + +### Core Layer Registration + +#### `layers/layertypes.go` +- Added `LayerTypeENIP` (ID: 151) +- Added `LayerTypeCIP` (ID: 152) + +```go +LayerTypeENIP = gopacket.RegisterLayerType(151, gopacket.LayerTypeMetadata{ + Name: "ENIP", + Decoder: gopacket.DecodeFunc(decodeENIP) +}) +LayerTypeCIP = gopacket.RegisterLayerType(152, gopacket.LayerTypeMetadata{ + Name: "CIP", + Decoder: gopacket.DecodeFunc(decodeCIP) +}) +``` + +#### `layers/ports.go` +Added port mappings for automatic protocol detection: + +**TCP Ports**: +- Port 2222 → `LayerTypeENIP` (EtherNet/IP-1) +- Port 44818 → `LayerTypeENIP` (EtherNet/IP-2) + +**UDP Ports**: +- Port 2222 → `LayerTypeENIP` (EtherNet/IP-1) +- Port 44818 → `LayerTypeENIP` (EtherNet/IP-2) + +#### `layers/enums.go` +- Added missing `errors` import +- Added `EthernetTypeERSPAN` constant (0x88be) +- Added `EthernetTypeRaw` constant (0xFFFF) + +## Protocol Specifications + +### Port Numbers +| Protocol | TCP Port | UDP Port | Description | +|----------|----------|----------|-------------| +| ENIP | 2222 | 2222 | EtherNet/IP-1 (standard) | +| ENIP | 44818 | 44818 | EtherNet/IP-2 (alternate) | + +### Layer Hierarchy +``` +Ethernet + └── IPv4/IPv6 + └── TCP/UDP + └── ENIP (ports 2222, 44818) + └── CIP (for SendRRData/SendUnitData commands) + └── Payload +``` + +## Credits + +- Original implementation by @traetox in [PR #408](https://github.com/google/gopacket/pull/408) +- Reimplemented by @dreadl0ck in [PR #758](https://github.com/google/gopacket/pull/758) +- Ported to gopacket-community repository + +## References + +- **CIP**: ODVA Common Industrial Protocol specification +- **ENIP**: ODVA Ethernet/IP specification +- **IANA Ports**: Port 2222 (EtherNet-IP-1), Port 44818 (EtherNet-IP-2) + diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/LICENSE b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/LICENSE new file mode 100644 index 0000000000..2100d524d9 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 Google, Inc. All rights reserved. +Copyright (c) 2009-2011 Andreas Krennmair. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Andreas Krennmair, Google, nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/README.md b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/README.md new file mode 100644 index 0000000000..9794c3a8c7 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/README.md @@ -0,0 +1,17 @@ +![Build Status](https://img.shields.io/github/actions/workflow/status/gopacket/gopacket/push_pr.yaml?branch=master) +![Go Version](https://img.shields.io/github/go-mod/go-version/gopacket/gopacket/master?filename=go.mod&style=flat-square) +![Latest Version](https://img.shields.io/github/v/tag/gopacket/gopacket?label=latest&style=flat-square) +![License](https://img.shields.io/github/license/gopacket/gopacket?style=flat-square) +![Open Issues](https://img.shields.io/github/issues/gopacket/gopacket?style=flat-square) +[![GoDoc](https://godoc.org/github.com/gopacket/gopacket?status.svg)](https://godoc.org/github.com/gopacket/gopacket) + +# GoPacket + +This library provides packet decoding capabilities for Go. + +Forked from the popular gopacket [repo](https://github.com/google/gopacket) by Google, this fork was created to ensure the project doesn't become stale and bugfixes, new protocols and performance improvements can be merged into it. submit your PRs here :) + +See [godoc](https://godoc.org/github.com/gopacket/gopacket) for more details. + +Minimum Go supported is 1.24.0 + diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/SECURITY.md b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/SECURITY.md new file mode 100644 index 0000000000..b91f537550 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy for `gopacket/gopacket` Module + +## Supported Versions + +This section provides information about the versions of the `gopacket` module that are currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 1.x.x | :white_check_mark: | + +It is highly recommended to use the supported versions to ensure the security and stability of your projects. Unsupported versions will not receive security updates, and using them may expose your projects to vulnerabilities. + +## Reporting a Vulnerability + +If you discover a vulnerability in the `gopacket` module, please take the following steps to report it: + +1. **Contact**: please use the private fork and PR function to raise the issue. + +2. **Acknowledgment**: You can expect to receive an acknowledgment of your vulnerability report within a week of submission. + +3. **Updates**: The security team will keep you updated on the status of your report and the planned resolution timeline. Updates will be provided at least once a week until the issue is resolved. + +4. **Disclosure**: If the vulnerability is confirmed, the security team will work to promptly release a fix. Details about the vulnerability and the fix will be publicly disclosed after the release, allowing users to update and secure their systems. + +5. **Acceptance or Decline**: If your report is accepted, you will be credited for the discovery, and the details will be shared in the public disclosure. If the report is declined, the security team will provide an explanation for the decision. + +Your cooperation and responsible disclosure are greatly appreciated in helping to keep the `gopacket/gopacket` module and its users secure. + +Keep in mind that `gopacket` is maintained by only a few people, so if there are multiple bugs it might take a while for them to get fixed. diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/base.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/base.go new file mode 100644 index 0000000000..60fbd64108 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/base.go @@ -0,0 +1,185 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// Layer represents a single decoded packet layer (using either the +// OSI or TCP/IP definition of a layer). When decoding, a packet's data is +// broken up into a number of layers. The caller may call LayerType() to +// figure out which type of layer they've received from the packet. Optionally, +// they may then use a type assertion to get the actual layer type for deep +// inspection of the data. +type Layer interface { + // LayerType is the gopacket type for this layer. + LayerType() LayerType + // LayerContents returns the set of bytes that make up this layer. + LayerContents() []byte + // LayerPayload returns the set of bytes contained within this layer, not + // including the layer itself. + LayerPayload() []byte +} + +// LayerWithChecksum should be implemented by layers that contain a checksum +// that can be verified after a packet has been decoded. +type LayerWithChecksum interface { + // VerifyChecksum verifies the checksum and returns the result. + VerifyChecksum() (error, ChecksumVerificationResult) +} + +// Payload is a Layer containing the payload of a packet. The definition of +// what constitutes the payload of a packet depends on previous layers; for +// TCP and UDP, we stop decoding above layer 4 and return the remaining +// bytes as a Payload. Payload is an ApplicationLayer. +type Payload []byte + +// LayerType returns LayerTypePayload +func (p Payload) LayerType() LayerType { return LayerTypePayload } + +// LayerContents returns the bytes making up this layer. +func (p Payload) LayerContents() []byte { return []byte(p) } + +// LayerPayload returns the payload within this layer. +func (p Payload) LayerPayload() []byte { return nil } + +// Payload returns this layer as bytes. +func (p Payload) Payload() []byte { return []byte(p) } + +// String implements fmt.Stringer. +func (p Payload) String() string { return fmt.Sprintf("%d byte(s)", len(p)) } + +// GoString implements fmt.GoStringer. +func (p Payload) GoString() string { return LongBytesGoString([]byte(p)) } + +// CanDecode implements DecodingLayer. +func (p Payload) CanDecode() LayerClass { return LayerTypePayload } + +// NextLayerType implements DecodingLayer. +func (p Payload) NextLayerType() LayerType { return LayerTypeZero } + +// DecodeFromBytes implements DecodingLayer. +func (p *Payload) DecodeFromBytes(data []byte, df DecodeFeedback) error { + *p = Payload(data) + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p Payload) SerializeTo(b SerializeBuffer, opts SerializeOptions) error { + bytes, err := b.PrependBytes(len(p)) + if err != nil { + return err + } + copy(bytes, p) + return nil +} + +// decodePayload decodes data by returning it all in a Payload layer. +func decodePayload(data []byte, p PacketBuilder) error { + payload := &Payload{} + if err := payload.DecodeFromBytes(data, p); err != nil { + return err + } + p.AddLayer(payload) + p.SetApplicationLayer(payload) + return nil +} + +// Fragment is a Layer containing a fragment of a larger frame, used by layers +// like IPv4 and IPv6 that allow for fragmentation of their payloads. +type Fragment []byte + +// LayerType returns LayerTypeFragment +func (p *Fragment) LayerType() LayerType { return LayerTypeFragment } + +// LayerContents implements Layer. +func (p *Fragment) LayerContents() []byte { return []byte(*p) } + +// LayerPayload implements Layer. +func (p *Fragment) LayerPayload() []byte { return nil } + +// Payload returns this layer as a byte slice. +func (p *Fragment) Payload() []byte { return []byte(*p) } + +// String implements fmt.Stringer. +func (p *Fragment) String() string { return fmt.Sprintf("%d byte(s)", len(*p)) } + +// CanDecode implements DecodingLayer. +func (p *Fragment) CanDecode() LayerClass { return LayerTypeFragment } + +// NextLayerType implements DecodingLayer. +func (p *Fragment) NextLayerType() LayerType { return LayerTypeZero } + +// DecodeFromBytes implements DecodingLayer. +func (p *Fragment) DecodeFromBytes(data []byte, df DecodeFeedback) error { + *p = Fragment(data) + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p *Fragment) SerializeTo(b SerializeBuffer, opts SerializeOptions) error { + bytes, err := b.PrependBytes(len(*p)) + if err != nil { + return err + } + copy(bytes, *p) + return nil +} + +// decodeFragment decodes data by returning it all in a Fragment layer. +func decodeFragment(data []byte, p PacketBuilder) error { + payload := &Fragment{} + if err := payload.DecodeFromBytes(data, p); err != nil { + return err + } + p.AddLayer(payload) + p.SetApplicationLayer(payload) + return nil +} + +// These layers correspond to Internet Protocol Suite (TCP/IP) layers, and their +// corresponding OSI layers, as best as possible. + +// LinkLayer is the packet layer corresponding to TCP/IP layer 1 (OSI layer 2) +type LinkLayer interface { + Layer + LinkFlow() Flow +} + +// NetworkLayer is the packet layer corresponding to TCP/IP layer 2 (OSI +// layer 3) +type NetworkLayer interface { + Layer + NetworkFlow() Flow +} + +// TransportLayer is the packet layer corresponding to the TCP/IP layer 3 (OSI +// layer 4) +type TransportLayer interface { + Layer + TransportFlow() Flow +} + +// ApplicationLayer is the packet layer corresponding to the TCP/IP layer 4 (OSI +// layer 7), also known as the packet payload. +type ApplicationLayer interface { + Layer + Payload() []byte +} + +// ErrorLayer is a packet layer created when decoding of the packet has failed. +// Its payload is all the bytes that we were unable to decode, and the returned +// error details why the decoding failed. +type ErrorLayer interface { + Layer + Error() error +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/checksum.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/checksum.go new file mode 100644 index 0000000000..5d46c47670 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/checksum.go @@ -0,0 +1,58 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +// ChecksumVerificationResult provides information about a checksum verification. +// The checksums are represented using uint32 to fit even the largest checksums. +// If a checksum is optional and unset, Correct and Actual might mismatch even +// though Valid is true. In this case, Correct is the computed optional checksum +// and Actual is 0. +type ChecksumVerificationResult struct { + // Valid tells whether the checksum verification succeeded. + Valid bool + // Correct is the correct checksum that was expected to be found. + Correct uint32 + // Actual is the checksum that was found and which might be wrong. + Actual uint32 +} + +// ChecksumMismatch provides information about a failed checksum verification +// for a layer. +type ChecksumMismatch struct { + ChecksumVerificationResult + // Layer is the layer whose checksum is invalid. + Layer Layer + // LayerIndex is the index of the layer in the packet. + LayerIndex int +} + +// ComputeChecksum computes the internet checksum as defined in RFC1071. The +// passed-in csum is any initial checksum data that's already been computed. +func ComputeChecksum(data []byte, csum uint32) uint32 { + // to handle odd lengths, we loop to length - 1, incrementing by 2, then + // handle the last byte specifically by checking against the original + // length. + length := len(data) - 1 + for i := 0; i < length; i += 2 { + // For our test packet, doing this manually is about 25% faster + // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16. + csum += uint32(data[i]) << 8 + csum += uint32(data[i+1]) + } + if len(data)%2 == 1 { + csum += uint32(data[length]) << 8 + } + return csum +} + +// FoldChecksum folds a 32 bit checksum as defined in RFC1071. +func FoldChecksum(csum uint32) uint16 { + for csum > 0xffff { + csum = (csum >> 16) + (csum & 0xffff) + } + return ^uint16(csum) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/decode.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/decode.go new file mode 100644 index 0000000000..a53312d2a3 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/decode.go @@ -0,0 +1,158 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "errors" +) + +// DecodeFeedback is used by DecodingLayer layers to provide decoding metadata. +type DecodeFeedback interface { + // SetTruncated should be called if during decoding you notice that a packet + // is shorter than internal layer variables (HeaderLength, or the like) say it + // should be. It sets packet.Metadata().Truncated. + SetTruncated() +} + +type nilDecodeFeedback struct{} + +func (nilDecodeFeedback) SetTruncated() {} + +// NilDecodeFeedback implements DecodeFeedback by doing nothing. +var NilDecodeFeedback DecodeFeedback = nilDecodeFeedback{} + +// PacketBuilder is used by layer decoders to store the layers they've decoded, +// and to defer future decoding via NextDecoder. +// Typically, the pattern for use is: +// +// func (m *myDecoder) Decode(data []byte, p PacketBuilder) error { +// if myLayer, err := myDecodingLogic(data); err != nil { +// return err +// } else { +// p.AddLayer(myLayer) +// } +// // maybe do this, if myLayer is a LinkLayer +// p.SetLinkLayer(myLayer) +// return p.NextDecoder(nextDecoder) +// } +type PacketBuilder interface { + DecodeFeedback + // AddLayer should be called by a decoder immediately upon successful + // decoding of a layer. + AddLayer(l Layer) + // The following functions set the various specific layers in the final + // packet. Note that if many layers call SetX, the first call is kept and all + // other calls are ignored. + SetLinkLayer(LinkLayer) + SetNetworkLayer(NetworkLayer) + SetTransportLayer(TransportLayer) + SetApplicationLayer(ApplicationLayer) + SetErrorLayer(ErrorLayer) + // NextDecoder should be called by a decoder when they're done decoding a + // packet layer but not done with decoding the entire packet. The next + // decoder will be called to decode the last AddLayer's LayerPayload. + // Because of this, NextDecoder must only be called once all other + // PacketBuilder calls have been made. Set*Layer and AddLayer calls after + // NextDecoder calls will behave incorrectly. + NextDecoder(next Decoder) error + // DumpPacketData is used solely for decoding. If you come across an error + // you need to diagnose while processing a packet, call this and your packet's + // data will be dumped to stderr so you can create a test. This should never + // be called from a production decoder. + DumpPacketData() + // DecodeOptions returns the decode options + DecodeOptions() *DecodeOptions +} + +// Decoder is an interface for logic to decode a packet layer. Users may +// implement a Decoder to handle their own strange packet types, or may use one +// of the many decoders available in the 'layers' subpackage to decode things +// for them. +type Decoder interface { + // Decode decodes the bytes of a packet, sending decoded values and other + // information to PacketBuilder, and returning an error if unsuccessful. See + // the PacketBuilder documentation for more details. + Decode([]byte, PacketBuilder) error +} + +// DecodeFunc wraps a function to make it a Decoder. +type DecodeFunc func([]byte, PacketBuilder) error + +// Decode implements Decoder by calling itself. +func (d DecodeFunc) Decode(data []byte, p PacketBuilder) error { + // function, call thyself. + return d(data, p) +} + +// DecodePayload is a Decoder that returns a Payload layer containing all +// remaining bytes. +var DecodePayload Decoder = DecodeFunc(decodePayload) + +// DecodeUnknown is a Decoder that returns an Unknown layer containing all +// remaining bytes, useful if you run up against a layer that you're unable to +// decode yet. This layer is considered an ErrorLayer. +var DecodeUnknown Decoder = DecodeFunc(decodeUnknown) + +// DecodeFragment is a Decoder that returns a Fragment layer containing all +// remaining bytes. +var DecodeFragment Decoder = DecodeFunc(decodeFragment) + +// LayerTypeZero is an invalid layer type, but can be used to determine whether +// layer type has actually been set correctly. +var LayerTypeZero = RegisterLayerType(0, LayerTypeMetadata{Name: "Unknown", Decoder: DecodeUnknown}) + +// LayerTypeDecodeFailure is the layer type for the default error layer. +var LayerTypeDecodeFailure = RegisterLayerType(1, LayerTypeMetadata{Name: "DecodeFailure", Decoder: DecodeUnknown}) + +// LayerTypePayload is the layer type for a payload that we don't try to decode +// but treat as a success, IE: an application-level payload. +var LayerTypePayload = RegisterLayerType(2, LayerTypeMetadata{Name: "Payload", Decoder: DecodePayload}) + +// LayerTypeFragment is the layer type for a fragment of a layer transported +// by an underlying layer that supports fragmentation. +var LayerTypeFragment = RegisterLayerType(3, LayerTypeMetadata{Name: "Fragment", Decoder: DecodeFragment}) + +// DecodeFailure is a packet layer created if decoding of the packet data failed +// for some reason. It implements ErrorLayer. LayerContents will be the entire +// set of bytes that failed to parse, and Error will return the reason parsing +// failed. +type DecodeFailure struct { + data []byte + err error + stack []byte +} + +// Error returns the error encountered during decoding. +func (d *DecodeFailure) Error() error { return d.err } + +// LayerContents implements Layer. +func (d *DecodeFailure) LayerContents() []byte { return d.data } + +// LayerPayload implements Layer. +func (d *DecodeFailure) LayerPayload() []byte { return nil } + +// String implements fmt.Stringer. +func (d *DecodeFailure) String() string { + return "Packet decoding error: " + d.Error().Error() +} + +// Dump implements Dumper. +func (d *DecodeFailure) Dump() (s string) { + if d.stack != nil { + s = string(d.stack) + } + return +} + +// LayerType returns LayerTypeDecodeFailure +func (d *DecodeFailure) LayerType() LayerType { return LayerTypeDecodeFailure } + +// decodeUnknown "decodes" unsupported data types by returning an error. +// This decoder will thus always return a DecodeFailure layer. +func decodeUnknown(data []byte, p PacketBuilder) error { + return errors.New("Layer type not currently supported") +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/doc.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/doc.go new file mode 100644 index 0000000000..2927c4e4d4 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/doc.go @@ -0,0 +1,425 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +/* +Package gopacket provides packet decoding for the Go language. + +gopacket contains many sub-packages with additional functionality you may find +useful, including: + + - layers: You'll probably use this every time. This contains of the logic + built into gopacket for decoding packet protocols. Note that all example + code below assumes that you have imported both gopacket and + gopacket/layers. + - pcap: C bindings to use libpcap to read packets off the wire. + - pfring: C bindings to use PF_RING to read packets off the wire. + - afpacket: C bindings for Linux's AF_PACKET to read packets off the wire. + - tcpassembly: TCP stream reassembly + +Also, if you're looking to dive right into code, see the examples subdirectory +for numerous simple binaries built using gopacket libraries. + +Minimum go version required is 1.5 except for pcapgo/EthernetHandle, afpacket, +and bsdbpf which need at least 1.7 due to x/sys/unix dependencies. + +# Basic Usage + +gopacket takes in packet data as a []byte and decodes it into a packet with +a non-zero number of "layers". Each layer corresponds to a protocol +within the bytes. Once a packet has been decoded, the layers of the packet +can be requested from the packet. + + // Decode a packet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default) + // Get the TCP layer from this packet + if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { + fmt.Println("This is a TCP packet!") + // Get actual TCP data from this layer + tcp, _ := tcpLayer.(*layers.TCP) + fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) + } + // Iterate over all layers, printing out each layer type + for _, layer := range packet.Layers() { + fmt.Println("PACKET LAYER:", layer.LayerType()) + } + +Packets can be decoded from a number of starting points. Many of our base +types implement Decoder, which allow us to decode packets for which +we don't have full data. + + // Decode an ethernet packet + ethP := gopacket.NewPacket(p1, layers.LayerTypeEthernet, gopacket.Default) + // Decode an IPv6 header and everything it contains + ipP := gopacket.NewPacket(p2, layers.LayerTypeIPv6, gopacket.Default) + // Decode a TCP header and its payload + tcpP := gopacket.NewPacket(p3, layers.LayerTypeTCP, gopacket.Default) + +# Reading Packets From A Source + +Most of the time, you won't just have a []byte of packet data lying around. +Instead, you'll want to read packets in from somewhere (file, interface, etc) +and process them. To do that, you'll want to build a PacketSource. + +First, you'll need to construct an object that implements the PacketDataSource +interface. There are implementations of this interface bundled with gopacket +in the gopacket/pcap and gopacket/pfring subpackages... see their documentation +for more information on their usage. Once you have a PacketDataSource, you can +pass it into NewPacketSource, along with a Decoder of your choice, to create +a PacketSource. + +Once you have a PacketSource, you can read packets from it in multiple ways. +See the docs for PacketSource for more details. The easiest method is the +Packets function, which returns a channel, then asynchronously writes new +packets into that channel, closing the channel if the packetSource hits an +end-of-file. + + packetSource := ... // construct using pcap or pfring + for packet := range packetSource.Packets() { + handlePacket(packet) // do something with each packet + } + +You can change the decoding options of the packetSource by setting fields in +packetSource.DecodeOptions... see the following sections for more details. + +# Lazy Decoding + +gopacket optionally decodes packet data lazily, meaning it +only decodes a packet layer when it needs to handle a function call. + + // Create a packet, but don't actually decode anything yet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + // Now, decode the packet up to the first IPv4 layer found but no further. + // If no IPv4 layer was found, the whole packet will be decoded looking for + // it. + ip4 := packet.Layer(layers.LayerTypeIPv4) + // Decode all layers and return them. The layers up to the first IPv4 layer + // are already decoded, and will not require decoding a second time. + layers := packet.Layers() + +Lazily-decoded packets are not concurrency-safe. Since layers have not all been +decoded, each call to Layer() or Layers() has the potential to mutate the packet +in order to decode the next layer. If a packet is used +in multiple goroutines concurrently, don't use gopacket.Lazy. Then gopacket +will decode the packet fully, and all future function calls won't mutate the +object. + +# NoCopy Decoding + +By default, gopacket will copy the slice passed to NewPacket and store the +copy within the packet, so future mutations to the bytes underlying the slice +don't affect the packet and its layers. If you can guarantee that the +underlying slice bytes won't be changed, you can use NoCopy to tell +gopacket.NewPacket, and it'll use the passed-in slice itself. + + // This channel returns new byte slices, each of which points to a new + // memory location that's guaranteed immutable for the duration of the + // packet. + for data := range myByteSliceChannel { + p := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy) + doSomethingWithPacket(p) + } + +The fastest method of decoding is to use both Lazy and NoCopy, but note from +the many caveats above that for some implementations either or both may be +dangerous. + +# Pointers To Known Layers + +During decoding, certain layers are stored in the packet as well-known +layer types. For example, IPv4 and IPv6 are both considered NetworkLayer +layers, while TCP and UDP are both TransportLayer layers. We support 4 +layers, corresponding to the 4 layers of the TCP/IP layering scheme (roughly +anagalous to layers 2, 3, 4, and 7 of the OSI model). To access these, +you can use the packet.LinkLayer, packet.NetworkLayer, +packet.TransportLayer, and packet.ApplicationLayer functions. Each of +these functions returns a corresponding interface +(gopacket.{Link,Network,Transport,Application}Layer). The first three +provide methods for getting src/dst addresses for that particular layer, +while the final layer provides a Payload function to get payload data. +This is helpful, for example, to get payloads for all packets regardless +of their underlying data type: + + // Get packets from some source + for packet := range someSource { + if app := packet.ApplicationLayer(); app != nil { + if strings.Contains(string(app.Payload()), "magic string") { + fmt.Println("Found magic string in a packet!") + } + } + } + +A particularly useful layer is ErrorLayer, which is set whenever there's +an error parsing part of the packet. + + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default) + if err := packet.ErrorLayer(); err != nil { + fmt.Println("Error decoding some part of the packet:", err) + } + +Note that we don't return an error from NewPacket because we may have decoded +a number of layers successfully before running into our erroneous layer. You +may still be able to get your Ethernet and IPv4 layers correctly, even if +your TCP layer is malformed. + +# Flow And Endpoint + +gopacket has two useful objects, Flow and Endpoint, for communicating in a protocol +independent manner the fact that a packet is coming from A and going to B. +The general layer types LinkLayer, NetworkLayer, and TransportLayer all provide +methods for extracting their flow information, without worrying about the type +of the underlying Layer. + +A Flow is a simple object made up of a set of two Endpoints, one source and one +destination. It details the sender and receiver of the Layer of the Packet. + +An Endpoint is a hashable representation of a source or destination. For +example, for LayerTypeIPv4, an Endpoint contains the IP address bytes for a v4 +IP packet. A Flow can be broken into Endpoints, and Endpoints can be combined +into Flows: + + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + netFlow := packet.NetworkLayer().NetworkFlow() + src, dst := netFlow.Endpoints() + reverseFlow := gopacket.NewFlow(dst, src) + +Both Endpoint and Flow objects can be used as map keys, and the equality +operator can compare them, so you can easily group together all packets +based on endpoint criteria: + + flows := map[gopacket.Endpoint]chan gopacket.Packet + packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy) + // Send all TCP packets to channels based on their destination port. + if tcp := packet.Layer(layers.LayerTypeTCP); tcp != nil { + flows[tcp.TransportFlow().Dst()] <- packet + } + // Look for all packets with the same source and destination network address + if net := packet.NetworkLayer(); net != nil { + src, dst := net.NetworkFlow().Endpoints() + if src == dst { + fmt.Println("Fishy packet has same network source and dst: %s", src) + } + } + // Find all packets coming from UDP port 1000 to UDP port 500 + interestingFlow := gopacket.FlowFromEndpoints(layers.NewUDPPortEndpoint(1000), layers.NewUDPPortEndpoint(500)) + if t := packet.NetworkLayer(); t != nil && t.TransportFlow() == interestingFlow { + fmt.Println("Found that UDP flow I was looking for!") + } + +For load-balancing purposes, both Flow and Endpoint have FastHash() functions, +which provide quick, non-cryptographic hashes of their contents. Of particular +importance is the fact that Flow FastHash() is symmetric: A->B will have the same +hash as B->A. An example usage could be: + + channels := [8]chan gopacket.Packet + for i := 0; i < 8; i++ { + channels[i] = make(chan gopacket.Packet) + go packetHandler(channels[i]) + } + for packet := range getPackets() { + if net := packet.NetworkLayer(); net != nil { + channels[int(net.NetworkFlow().FastHash()) & 0x7] <- packet + } + } + +This allows us to split up a packet stream while still making sure that each +stream sees all packets for a flow (and its bidirectional opposite). + +# Implementing Your Own Decoder + +If your network has some strange encapsulation, you can implement your own +decoder. In this example, we handle Ethernet packets which are encapsulated +in a 4-byte header. + + // Create a layer type, should be unique and high, so it doesn't conflict, + // giving it a name and a decoder to use. + var MyLayerType = gopacket.RegisterLayerType(12345, gopacket.LayerTypeMetadata{Name: "MyLayerType", Decoder: gopacket.DecodeFunc(decodeMyLayer)}) + + // Implement my layer + type MyLayer struct { + StrangeHeader []byte + payload []byte + } + func (m MyLayer) LayerType() gopacket.LayerType { return MyLayerType } + func (m MyLayer) LayerContents() []byte { return m.StrangeHeader } + func (m MyLayer) LayerPayload() []byte { return m.payload } + + // Now implement a decoder... this one strips off the first 4 bytes of the + // packet. + func decodeMyLayer(data []byte, p gopacket.PacketBuilder) error { + // Create my layer + p.AddLayer(&MyLayer{data[:4], data[4:]}) + // Determine how to handle the rest of the packet + return p.NextDecoder(layers.LayerTypeEthernet) + } + + // Finally, decode your packets: + p := gopacket.NewPacket(data, MyLayerType, gopacket.Lazy) + +See the docs for Decoder and PacketBuilder for more details on how coding +decoders works, or look at RegisterLayerType and RegisterEndpointType to see how +to add layer/endpoint types to gopacket. + +# Fast Decoding With DecodingLayerParser + +TLDR: DecodingLayerParser takes about 10% of the time as NewPacket to decode +packet data, but only for known packet stacks. + +Basic decoding using gopacket.NewPacket or PacketSource.Packets is somewhat slow +due to its need to allocate a new packet and every respective layer. It's very +versatile and can handle all known layer types, but sometimes you really only +care about a specific set of layers regardless, so that versatility is wasted. + +DecodingLayerParser avoids memory allocation altogether by decoding packet +layers directly into preallocated objects, which you can then reference to get +the packet's information. A quick example: + + func main() { + var eth layers.Ethernet + var ip4 layers.IPv4 + var ip6 layers.IPv6 + var tcp layers.TCP + parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp) + decoded := []gopacket.LayerType{} + for packetData := range somehowGetPacketData() { + if err := parser.DecodeLayers(packetData, &decoded); err != nil { + fmt.Fprintf(os.Stderr, "Could not decode layers: %v\n", err) + continue + } + for _, layerType := range decoded { + switch layerType { + case layers.LayerTypeIPv6: + fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP) + case layers.LayerTypeIPv4: + fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP) + } + } + } + } + +The important thing to note here is that the parser is modifying the passed in +layers (eth, ip4, ip6, tcp) instead of allocating new ones, thus greatly +speeding up the decoding process. It's even branching based on layer type... +it'll handle an (eth, ip4, tcp) or (eth, ip6, tcp) stack. However, it won't +handle any other type... since no other decoders were passed in, an (eth, ip4, +udp) stack will stop decoding after ip4, and only pass back [LayerTypeEthernet, +LayerTypeIPv4] through the 'decoded' slice (along with an error saying it can't +decode a UDP packet). + +Unfortunately, not all layers can be used by DecodingLayerParser... only those +implementing the DecodingLayer interface are usable. Also, it's possible to +create DecodingLayers that are not themselves Layers... see +layers.IPv6ExtensionSkipper for an example of this. + +# Faster And Customized Decoding with DecodingLayerContainer + +By default, DecodingLayerParser uses native map to store and search for a layer +to decode. Though being versatile, in some cases this solution may be not so +optimal. For example, if you have only few layers faster operations may be +provided by sparse array indexing or linear array scan. + +To accomodate these scenarios, DecodingLayerContainer interface is introduced +along with its implementations: DecodingLayerSparse, DecodingLayerArray and +DecodingLayerMap. You can specify a container implementation to +DecodingLayerParser with SetDecodingLayerContainer method. Example: + + dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet) + dlp.SetDecodingLayerContainer(gopacket.DecodingLayerSparse(nil)) + var eth layers.Ethernet + dlp.AddDecodingLayer(ð) + // ... add layers and use DecodingLayerParser as usual... + +To skip one level of indirection (though sacrificing some capabilities) you may +also use DecodingLayerContainer as a decoding tool as it is. In this case you have to +handle unknown layer types and layer panics by yourself. Example: + + func main() { + var eth layers.Ethernet + var ip4 layers.IPv4 + var ip6 layers.IPv6 + var tcp layers.TCP + dlc := gopacket.DecodingLayerContainer(gopacket.DecodingLayerArray(nil)) + dlc = dlc.Put(ð) + dlc = dlc.Put(&ip4) + dlc = dlc.Put(&ip6) + dlc = dlc.Put(&tcp) + // you may specify some meaningful DecodeFeedback + decoder := dlc.LayersDecoder(LayerTypeEthernet, gopacket.NilDecodeFeedback) + decoded := make([]gopacket.LayerType, 0, 20) + for packetData := range somehowGetPacketData() { + lt, err := decoder(packetData, &decoded) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not decode layers: %v\n", err) + continue + } + if lt != gopacket.LayerTypeZero { + fmt.Fprintf(os.Stderr, "unknown layer type: %v\n", lt) + continue + } + for _, layerType := range decoded { + // examine decoded layertypes just as already shown above + } + } + } + +DecodingLayerSparse is the fastest but most effective when LayerType values +that layers in use can decode are not large because otherwise that would lead +to bigger memory footprint. DecodingLayerArray is very compact and primarily +usable if the number of decoding layers is not big (up to ~10-15, but please do +your own benchmarks). DecodingLayerMap is the most versatile one and used by +DecodingLayerParser by default. Please refer to tests and benchmarks in layers +subpackage to further examine usage examples and performance measurements. + +You may also choose to implement your own DecodingLayerContainer if you want to +make use of your own internal packet decoding logic. + +# Creating Packet Data + +As well as offering the ability to decode packet data, gopacket will allow you +to create packets from scratch, as well. A number of gopacket layers implement +the SerializableLayer interface; these layers can be serialized to a []byte in +the following manner: + + ip := &layers.IPv4{ + SrcIP: net.IP{1, 2, 3, 4}, + DstIP: net.IP{5, 6, 7, 8}, + // etc... + } + buf := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{} // See SerializeOptions for more details. + err := ip.SerializeTo(buf, opts) + if err != nil { panic(err) } + fmt.Println(buf.Bytes()) // prints out a byte slice containing the serialized IPv4 layer. + +SerializeTo PREPENDS the given layer onto the SerializeBuffer, and they treat +the current buffer's Bytes() slice as the payload of the serializing layer. +Therefore, you can serialize an entire packet by serializing a set of layers in +reverse order (Payload, then TCP, then IP, then Ethernet, for example). The +SerializeBuffer's SerializeLayers function is a helper that does exactly that. + +To generate a (empty and useless, because no fields are set) +Ethernet(IPv4(TCP(Payload))) packet, for example, you can run: + + buf := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{} + gopacket.SerializeLayers(buf, opts, + &layers.Ethernet{}, + &layers.IPv4{}, + &layers.TCP{}, + gopacket.Payload([]byte{1, 2, 3, 4})) + packetData := buf.Bytes() + +# A Final Note + +If you use gopacket, you'll almost definitely want to make sure gopacket/layers +is imported, since when imported it sets all the LayerType variables and fills +in a lot of interesting variables/maps (DecodersByLayerName, etc). Therefore, +it's recommended that even if you don't use any layers functions directly, you still import with: + + import ( + _ "github.com/gopacket/gopacket/layers" + ) +*/ +package gopacket diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/endian/endian.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/endian/endian.go new file mode 100644 index 0000000000..6e82369321 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/endian/endian.go @@ -0,0 +1,18 @@ +package endian + +import ( + "encoding/binary" + "math/bits" +) + +func isLittleEndian[Bo binary.ByteOrder](bo Bo) bool { + return bo.Uint16([]byte{0x12, 0x34}) == 0x3412 +} + +// Htons converts x from host to network byte order. +func Htons(v uint16) uint16 { + if isLittleEndian(binary.NativeEndian) { + return bits.ReverseBytes16(v) + } + return v +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/flows.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/flows.go new file mode 100644 index 0000000000..a00c88398e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/flows.go @@ -0,0 +1,236 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "bytes" + "fmt" + "strconv" +) + +// MaxEndpointSize determines the maximum size in bytes of an endpoint address. +// +// Endpoints/Flows have a problem: They need to be hashable. Therefore, they +// can't use a byte slice. The two obvious choices are to use a string or a +// byte array. Strings work great, but string creation requires memory +// allocation, which can be slow. Arrays work great, but have a fixed size. We +// originally used the former, now we've switched to the latter. Use of a fixed +// byte-array doubles the speed of constructing a flow (due to not needing to +// allocate). This is a huge increase... too much for us to pass up. +// +// The end result of this, though, is that an endpoint/flow can't be created +// using more than MaxEndpointSize bytes per address. +const MaxEndpointSize = 16 + +// Endpoint is the set of bytes used to address packets at various layers. +// See LinkLayer, NetworkLayer, and TransportLayer specifications. +// Endpoints are usable as map keys. +type Endpoint struct { + typ EndpointType + len int + raw [MaxEndpointSize]byte +} + +// EndpointType returns the endpoint type associated with this endpoint. +func (a Endpoint) EndpointType() EndpointType { return a.typ } + +// Raw returns the raw bytes of this endpoint. These aren't human-readable +// most of the time, but they are faster than calling String. +func (a Endpoint) Raw() []byte { return a.raw[:a.len] } + +// LessThan provides a stable ordering for all endpoints. It sorts first based +// on the EndpointType of an endpoint, then based on the raw bytes of that +// endpoint. +// +// For some endpoints, the actual comparison may not make sense, however this +// ordering does provide useful information for most Endpoint types. +// Ordering is based first on endpoint type, then on raw endpoint bytes. +// Endpoint bytes are sorted lexicographically. +func (a Endpoint) LessThan(b Endpoint) bool { + return a.typ < b.typ || (a.typ == b.typ && bytes.Compare(a.raw[:a.len], b.raw[:b.len]) < 0) +} + +// fnvHash is used by our FastHash functions, and implements the FNV hash +// created by Glenn Fowler, Landon Curt Noll, and Phong Vo. +// See http://isthe.com/chongo/tech/comp/fnv/. +func fnvHash(s []byte) (h uint64) { + h = fnvBasis + for i := 0; i < len(s); i++ { + h ^= uint64(s[i]) + h *= fnvPrime + } + return +} + +const fnvBasis = 14695981039346656037 +const fnvPrime = 1099511628211 + +// FastHash provides a quick hashing function for an endpoint, useful if you'd +// like to split up endpoints by modulos or other load-balancing techniques. +// It uses a variant of Fowler-Noll-Vo hashing. +// +// The output of FastHash is not guaranteed to remain the same through future +// code revisions, so should not be used to key values in persistent storage. +func (a Endpoint) FastHash() (h uint64) { + h = fnvHash(a.raw[:a.len]) + h ^= uint64(a.typ) + h *= fnvPrime + return +} + +// NewEndpoint creates a new Endpoint object. +// +// The size of raw must be less than MaxEndpointSize, otherwise this function +// will panic. +func NewEndpoint(typ EndpointType, raw []byte) (e Endpoint) { + e.len = len(raw) + if e.len > MaxEndpointSize { + panic("raw byte length greater than MaxEndpointSize") + } + e.typ = typ + copy(e.raw[:], raw) + return +} + +// EndpointTypeMetadata is used to register a new endpoint type. +type EndpointTypeMetadata struct { + // Name is the string returned by an EndpointType's String function. + Name string + // Formatter is called from an Endpoint's String function to format the raw + // bytes in an Endpoint into a human-readable string. + Formatter func([]byte) string +} + +// EndpointType is the type of a gopacket Endpoint. This type determines how +// the bytes stored in the endpoint should be interpreted. +type EndpointType int64 + +var endpointTypes = map[EndpointType]EndpointTypeMetadata{} + +// RegisterEndpointType creates a new EndpointType and registers it globally. +// It MUST be passed a unique number, or it will panic. Numbers 0-999 are +// reserved for gopacket's use. +func RegisterEndpointType(num int, meta EndpointTypeMetadata) EndpointType { + t := EndpointType(num) + if _, ok := endpointTypes[t]; ok { + panic("Endpoint type number already in use") + } + endpointTypes[t] = meta + return t +} + +func (e EndpointType) String() string { + if t, ok := endpointTypes[e]; ok { + return t.Name + } + return strconv.Itoa(int(e)) +} + +func (a Endpoint) String() string { + if t, ok := endpointTypes[a.typ]; ok && t.Formatter != nil { + return t.Formatter(a.raw[:a.len]) + } + return fmt.Sprintf("%v:%v", a.typ, a.raw) +} + +// Flow represents the direction of traffic for a packet layer, as a source and destination Endpoint. +// Flows are usable as map keys. +type Flow struct { + typ EndpointType + slen, dlen int + src, dst [MaxEndpointSize]byte +} + +// FlowFromEndpoints creates a new flow by pasting together two endpoints. +// The endpoints must have the same EndpointType, or this function will return +// an error. +func FlowFromEndpoints(src, dst Endpoint) (_ Flow, err error) { + if src.typ != dst.typ { + err = fmt.Errorf("Mismatched endpoint types: %v->%v", src.typ, dst.typ) + return + } + return Flow{src.typ, src.len, dst.len, src.raw, dst.raw}, nil +} + +// FastHash provides a quick hashing function for a flow, useful if you'd +// like to split up flows by modulos or other load-balancing techniques. +// It uses a variant of Fowler-Noll-Vo hashing, and is guaranteed to collide +// with its reverse flow. IE: the flow A->B will have the same hash as the flow +// B->A. +// +// The output of FastHash is not guaranteed to remain the same through future +// code revisions, so should not be used to key values in persistent storage. +func (f Flow) FastHash() (h uint64) { + // This combination must be commutative. We don't use ^, since that would + // give the same hash for all A->A flows. + h = fnvHash(f.src[:f.slen]) + fnvHash(f.dst[:f.dlen]) + h ^= uint64(f.typ) + h *= fnvPrime + return +} + +// String returns a human-readable representation of this flow, in the form +// "Src->Dst" +func (f Flow) String() string { + s, d := f.Endpoints() + return fmt.Sprintf("%v->%v", s, d) +} + +// EndpointType returns the EndpointType for this Flow. +func (f Flow) EndpointType() EndpointType { + return f.typ +} + +// Endpoints returns the two Endpoints for this flow. +func (f Flow) Endpoints() (src, dst Endpoint) { + return Endpoint{f.typ, f.slen, f.src}, Endpoint{f.typ, f.dlen, f.dst} +} + +// Src returns the source Endpoint for this flow. +func (f Flow) Src() (src Endpoint) { + src, _ = f.Endpoints() + return +} + +// Dst returns the destination Endpoint for this flow. +func (f Flow) Dst() (dst Endpoint) { + _, dst = f.Endpoints() + return +} + +// Reverse returns a new flow with endpoints reversed. +func (f Flow) Reverse() Flow { + return Flow{f.typ, f.dlen, f.slen, f.dst, f.src} +} + +// NewFlow creates a new flow. +// +// src and dst must have length <= MaxEndpointSize, otherwise NewFlow will +// panic. +func NewFlow(t EndpointType, src, dst []byte) (f Flow) { + f.slen = len(src) + f.dlen = len(dst) + if f.slen > MaxEndpointSize || f.dlen > MaxEndpointSize { + panic("flow raw byte length greater than MaxEndpointSize") + } + f.typ = t + copy(f.src[:], src) + copy(f.dst[:], dst) + return +} + +// EndpointInvalid is an endpoint type used for invalid endpoints, IE endpoints +// that are specified incorrectly during creation. +var EndpointInvalid = RegisterEndpointType(0, EndpointTypeMetadata{Name: "invalid", Formatter: func(b []byte) string { + return fmt.Sprintf("%v", b) +}}) + +// InvalidEndpoint is a singleton Endpoint of type EndpointInvalid. +var InvalidEndpoint = NewEndpoint(EndpointInvalid, nil) + +// InvalidFlow is a singleton Flow of type EndpointInvalid. +var InvalidFlow = NewFlow(EndpointInvalid, nil, nil) diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/gc b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/gc new file mode 100644 index 0000000000..b1d8d2e1f6 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/gc @@ -0,0 +1,288 @@ +#!/bin/bash +# Copyright 2012 Google, Inc. All rights reserved. + +# This script provides a simple way to run benchmarks against previous code and +# keep a log of how benchmarks change over time. When used with the --benchmark +# flag, it runs benchmarks from the current code and from the last commit run +# with --benchmark, then stores the results in the git commit description. We +# rerun the old benchmarks along with the new ones, since there's no guarantee +# that git commits will happen on the same machine, so machine differences could +# cause wildly inaccurate results. +# +# If you're making changes to 'gopacket' which could cause performance changes, +# you may be requested to use this commit script to make sure your changes don't +# have large detrimental effects (or to show off how awesome your performance +# improvements are). +# +# If not run with the --benchmark flag, this script is still very useful... it +# makes sure all the correct go formatting, building, and testing work as +# expected. + +function Usage { + cat < + +--benchmark: Run benchmark comparisons against last benchmark'd commit +--root: Run tests that require root priviledges +--gen: Generate code for MACs/ports by pulling down external data + +Note, some 'git commit' flags are necessary, if all else fails, pass in -a +EOF + exit 1 +} + +BENCH="" +GEN="" +ROOT="" +while [ ! -z "$1" ]; do + case "$1" in + "--benchmark") + BENCH="$2" + shift + shift + ;; + "--gen") + GEN="yes" + shift + ;; + "--root") + ROOT="yes" + shift + ;; + "--help") + Usage + ;; + "-h") + Usage + ;; + "help") + Usage + ;; + *) + break + ;; + esac +done + +function Root { + if [ ! -z "$ROOT" ]; then + local exec="$1" + # Some folks (like me) keep source code in places inaccessible by root (like + # NFS), so to make sure things run smoothly we copy them to a /tmp location. + local tmpfile="$(mktemp -t gopacket_XXXXXXXX)" + echo "Running root test executable $exec as $tmpfile" + cp "$exec" "$tmpfile" + chmod a+x "$tmpfile" + shift + sudo "$tmpfile" "$@" + fi +} + +if [ "$#" -eq "0" ]; then + Usage +fi + +cd $(dirname $0) + +# Check for copyright notices. +for filename in $(find ./ -type f -name '*.go'); do + if ! head -n 1 "$filename" | grep -q Copyright; then + echo "File '$filename' may not have copyright notice" + exit 1 + fi +done + +set -e +set -x + +if [ ! -z "$ROOT" ]; then + echo "Running SUDO to get root priviledges for root tests" + sudo echo "have root" +fi + +if [ ! -z "$GEN" ]; then + pushd macs + go run gen.go | gofmt > valid_mac_prefixes.go + popd + pushd layers + go run gen.go | gofmt > iana_ports.go + go run gen2.go | gofmt > enums_generated.go + popd +fi + +# Make sure everything is formatted, compiles, and tests pass. +go fmt ./... +go test -i ./... 2>/dev/null >/dev/null || true +go test +go build +pushd examples/bytediff +go build +popd +if [ -f /usr/include/pcap.h ]; then + pushd pcap + go test ./... + go build ./... + go build pcap_tester.go + Root pcap_tester --mode=basic + Root pcap_tester --mode=filtered + Root pcap_tester --mode=timestamp || echo "You might not support timestamp sources" + popd + pushd examples/afpacket + go build + popd + pushd examples/pcapdump + go build + popd + pushd examples/arpscan + go build + popd + pushd examples/bidirectional + go build + popd + pushd examples/synscan + go build + popd + pushd examples/httpassembly + go build + popd + pushd examples/statsassembly + go build + popd +fi +pushd macs +go test ./... +gofmt -w gen.go +go build gen.go +popd +pushd tcpassembly +go test ./... +popd +pushd reassembly +go test ./... +popd +pushd layers +gofmt -w gen.go +go build gen.go +go test ./... +popd +pushd pcapgo +go test ./... +go build ./... +popd +if [ -f /usr/include/linux/if_packet.h ]; then + if grep -q TPACKET_V3 /usr/include/linux/if_packet.h; then + pushd afpacket + go build ./... + go test ./... + popd + fi +fi +if [ -f /usr/include/pfring.h ]; then + pushd pfring + go test ./... + go build ./... + popd + pushd examples/pfdump + go build + popd +fi +pushd ip4defrag +go test ./... +popd +pushd defrag +go test ./... +popd + +for travis_script in `ls .travis.*.sh`; do + ./$travis_script +done + +# Run our initial commit +git commit "$@" + +if [ -z "$BENCH" ]; then + set +x + echo "We're not benchmarking and we've committed... we're done!" + exit +fi + +### If we get here, we want to run benchmarks from current commit, and compare +### then to benchmarks from the last --benchmark commit. + +# Get our current branch. +BRANCH="$(git branch | grep '^*' | awk '{print $2}')" + +# File we're going to build our commit description in. +COMMIT_FILE="$(mktemp /tmp/tmp.XXXXXXXX)" + +# Add the word "BENCH" to the start of the git commit. +echo -n "BENCH " > $COMMIT_FILE + +# Get the current description... there must be an easier way. +git log -n 1 | grep '^ ' | sed 's/^ //' >> $COMMIT_FILE + +# Get the commit sha for the last benchmark commit +PREV=$(git log -n 1 --grep='BENCHMARK_MARKER_DO_NOT_CHANGE' | head -n 1 | awk '{print $2}') + +## Run current benchmarks + +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +pushd layers +go test --test.bench="$BENCH" 2>&1 | tee -a $COMMIT_FILE +popd +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +fi + + + +## Reset to last benchmark commit, run benchmarks + +git checkout $PREV + +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +pushd layers +go test --test.bench="$BENCH" 2>&1 | tee -a $COMMIT_FILE +popd +cat >> $COMMIT_FILE <&1 | tee -a $COMMIT_FILE +fi + + + +## Reset back to the most recent commit, edit the commit message by appending +## benchmark results. +git checkout $BRANCH +git commit --amend -F $COMMIT_FILE diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layerclass.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layerclass.go new file mode 100644 index 0000000000..775cd09877 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layerclass.go @@ -0,0 +1,107 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +// LayerClass is a set of LayerTypes, used for grabbing one of a number of +// different types from a packet. +type LayerClass interface { + // Contains returns true if the given layer type should be considered part + // of this layer class. + Contains(LayerType) bool + // LayerTypes returns the set of all layer types in this layer class. + // Note that this may not be a fast operation on all LayerClass + // implementations. + LayerTypes() []LayerType +} + +// Contains implements LayerClass. +func (l LayerType) Contains(a LayerType) bool { + return l == a +} + +// LayerTypes implements LayerClass. +func (l LayerType) LayerTypes() []LayerType { + return []LayerType{l} +} + +// LayerClassSlice implements a LayerClass with a slice. +type LayerClassSlice []bool + +// Contains returns true if the given layer type should be considered part +// of this layer class. +func (s LayerClassSlice) Contains(t LayerType) bool { + return int(t) < len(s) && s[t] +} + +// LayerTypes returns all layer types in this LayerClassSlice. +// Because of LayerClassSlice's implementation, this could be quite slow. +func (s LayerClassSlice) LayerTypes() (all []LayerType) { + for i := 0; i < len(s); i++ { + if s[i] { + all = append(all, LayerType(i)) + } + } + return +} + +// NewLayerClassSlice creates a new LayerClassSlice by creating a slice of +// size max(types) and setting slice[t] to true for each type t. Note, if +// you implement your own LayerType and give it a high value, this WILL create +// a very large slice. +func NewLayerClassSlice(types []LayerType) LayerClassSlice { + var max LayerType + for _, typ := range types { + if typ > max { + max = typ + } + } + t := make([]bool, int(max+1)) + for _, typ := range types { + t[typ] = true + } + return t +} + +// LayerClassMap implements a LayerClass with a map. +type LayerClassMap map[LayerType]bool + +// Contains returns true if the given layer type should be considered part +// of this layer class. +func (m LayerClassMap) Contains(t LayerType) bool { + return m[t] +} + +// LayerTypes returns all layer types in this LayerClassMap. +func (m LayerClassMap) LayerTypes() (all []LayerType) { + for t := range m { + all = append(all, t) + } + return +} + +// NewLayerClassMap creates a LayerClassMap and sets map[t] to true for each +// type in types. +func NewLayerClassMap(types []LayerType) LayerClassMap { + m := LayerClassMap{} + for _, typ := range types { + m[typ] = true + } + return m +} + +// NewLayerClass creates a LayerClass, attempting to be smart about which type +// it creates based on which types are passed in. +func NewLayerClass(types []LayerType) LayerClass { + for _, typ := range types { + if typ > maxLayerType { + // NewLayerClassSlice could create a very large object, so instead create + // a map. + return NewLayerClassMap(types) + } + } + return NewLayerClassSlice(types) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/.lint_blacklist b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/.lint_blacklist new file mode 100644 index 0000000000..1950bc7070 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/.lint_blacklist @@ -0,0 +1,40 @@ +dot11.go +eap.go +endpoints.go +enums_generated.go +enums.go +ethernet.go +geneve.go +icmp4.go +icmp6.go +igmp.go +ip4.go +ip6.go +layertypes.go +linux_sll.go +llc.go +lldp.go +mpls.go +multipathtcp.go +ndp.go +ntp.go +ospf.go +pflog.go +pppoe.go +prism.go +radiotap.go +rudp.go +sctp.go +sflow.go +tcp.go +tcpip.go +tls.go +tls_alert.go +tls_appdata.go +tls_cipherspec.go +tls_hanshake.go +tls_test.go +udp.go +udplite.go +usb.go +vrrp.go diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var0.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var0.go new file mode 100644 index 0000000000..ea25687820 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var0.go @@ -0,0 +1,108 @@ +// Copyright 2025 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. +// Copyright 2025 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. +package layers + +import ( + "errors" + + "github.com/gopacket/gopacket" +) + +// AGUEVar0 represents a packet encoded with Generic UDP Encapsulation. +// It should sit "under" a UDP layer with dest port 666. +// +// For more information about the meaning of the fields, see +// https://tools.ietf.org/html/draft-ietf-intarea-gue-04#section-3.1 +type AGUEVar0 struct { + Version uint8 + C bool + Protocol IPProtocol + Flags uint16 + Extensions []byte + Data []byte +} + +// LayerType returns this pseudo-header's type as defined in layertypes.go +func (l AGUEVar0) LayerType() gopacket.LayerType { + return LayerTypeAGUEVar0 +} + +// LayerContents returns a byte array containing our serialized header. +func (l AGUEVar0) LayerContents() []byte { + b := make([]byte, 4, 4+len(l.Extensions)) + hlen := uint8(len(l.Extensions)) + b[0] = l.Version<<6 | hlen + if l.C { + b[0] |= 0x20 + } + b[0] |= hlen + b[1] = byte(l.Protocol) + b[2] = byte(l.Flags >> 8) + b[3] = byte(l.Flags & 0xff) + b = append(b, l.Extensions...) + return b +} + +// LayerPayload returns an IPv4 or IPv6 packet in serialized form. +func (l AGUEVar0) LayerPayload() []byte { + return l.Data +} + +// SerializeTo writes our header into SerializeBuffer. +func (l AGUEVar0) SerializeTo(buf gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { + b := l.LayerContents() + writeTo, err := buf.PrependBytes(len(b)) + if err != nil { + return err + } + copy(writeTo, b) + return nil +} + +// CanDecode returns the type of layer we can decode. +func (l AGUEVar0) CanDecode() gopacket.LayerClass { + return LayerTypeAGUEVar0 +} + +// DecodeFromBytes extracts our header data from a serialized packet. +func (l *AGUEVar0) DecodeFromBytes(data []byte, _ gopacket.DecodeFeedback) error { + l.Version = data[0] >> 6 + l.C = data[0]&0x20 != 0 + l.Protocol = IPProtocol(data[1]) + l.Flags = (uint16(data[2]) << 8) | uint16(data[3]) + hlen := data[0] & 0x1f + l.Extensions = data[4 : 4+hlen] + l.Data = data[4+hlen:] + return nil +} + +// NextLayerType returns the next layer type, e.g. LayerTypeIPv4 +func (l AGUEVar0) NextLayerType() gopacket.LayerType { + return l.Protocol.LayerType() +} + +// decodeAGUE decodes AGUEVar0 or AGUEVar1, depending on the first data byte. +// If AGUEVar1, it refers the packet to AGUEVar1 for decoding. +// Else it adds AGUEVar0 layer info to the packet object, recursively decodes +// remaining layers, and returns the next-layer type (IPv4 or IPv6). +func decodeAGUE(data []byte, p gopacket.PacketBuilder) error { + if len(data) == 0 { + return errors.New("decodeAGUE() failed, no data") + } + if data[0]>>6 == 1 { + return decodeAGUEVar1(data, p) + } + l := AGUEVar0{} + if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil { + return err + } + p.AddLayer(l) + return p.NextDecoder(l.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var1.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var1.go new file mode 100644 index 0000000000..0e1c6c911d --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ague_var1.go @@ -0,0 +1,87 @@ +// Copyright 2025 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. +// Copyright 2025 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. +package layers + +import ( + "errors" + + "github.com/gopacket/gopacket" +) + +// An AGUEVar1 header is mostly imaginary, having a length of 0 in its serialized form. +// IPProtocol value is either IPProtocolIPv4 or IPProtocolIPv6, depending on the encapped +// IP header contained in Data, which must begin with the high-order bits 01. +type AGUEVar1 struct { + Protocol IPProtocol + Data []byte +} + +// LayerType returns this pseudo-header's type as defined in layertypes.go +func (l AGUEVar1) LayerType() gopacket.LayerType { + return LayerTypeAGUEVar1 +} + +// LayerContents returns an empty byte array, because this header has no length. +func (l AGUEVar1) LayerContents() []byte { + b := make([]byte, 0) + return b +} + +// LayerPayload returns an IPv4 or IPv6 packet in serialized form. +func (l AGUEVar1) LayerPayload() []byte { + return l.Data +} + +// SerializeTo writes our imaginary header into SerializeBuffer. This amount to a noop. +func (l AGUEVar1) SerializeTo(_ gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { + return nil +} + +// CanDecode returns the type of layer we can decode. +func (l AGUEVar1) CanDecode() gopacket.LayerClass { + return LayerTypeAGUEVar1 +} + +// DecodeFromBytes extracts our pseudo-header data from a serialized packet. +// There's only one thing, the next header type, which is either IPv4 or IPv6. +// They are crafted to keep their own header type in the first nibble. +// So we peek into the IP header to get the next-layer protocol type. +func (l *AGUEVar1) DecodeFromBytes(data []byte, _ gopacket.DecodeFeedback) error { + if len(data) < 1 { + return errors.New("DecodeFromBytes() failed, no data") + } + ipVersion := data[0] >> 4 + if ipVersion == 4 { + l.Protocol = IPProtocolIPv4 + } else if ipVersion == 6 { + l.Protocol = IPProtocolIPv6 + } else { + return errors.New("DecodeFromBytes() failed, unknown IP version") + } + l.Data = data + return nil +} + +// NextLayerType returns the next layer type, e.g. LayerTypeIPv4 +func (l AGUEVar1) NextLayerType() gopacket.LayerType { + return l.Protocol.LayerType() +} + +// decodeAGUEVar1 decodes packet data to figure out the next-layer IP type, +// then adds AGUEVar1 layer info to the packet object, recursively decodes +// remaining layers, and returns the next-layer type. +func decodeAGUEVar1(data []byte, p gopacket.PacketBuilder) error { + l := AGUEVar1{} + if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil { + return err + } + p.AddLayer(l) + return p.NextDecoder(l.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/apsp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/apsp.go new file mode 100644 index 0000000000..9201bfe653 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/apsp.go @@ -0,0 +1,129 @@ +// Copyright 2025 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. +// Copyright 2025 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 implements the Andromeda PSP header, a specialized version of the PSP header. + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// APSP represents a packet encrypted with the Andromeda Paddywhack Security Protocol. +// It should sit "under" a UDP layer with dest port 1000. +// For more information about the meaning of the fields, +// see go/andromeda-psp-format +// This is a remix and extension of the basic PSP header, see go/psp-format +// Field order and packing don't really matter, because we serialize explicitly, +// in SerializeTo() +type APSP struct { + BaseLayer + NextHeader uint8 + HdrExtLen uint8 + CryptOffset uint8 // lower 6 bits are offset, 2 high bits are reserved + SDVersVirt uint8 // see go/andromeda-psp-format for bitfield breakdown + SecParamIdx uint32 + InitVector uint64 + SecTokenV2 uint32 + VirtKey uint32 + SrcEndpointID uint64 + DstEndpointID uint64 +} + +// ApspLen is the sum of the header fields above, by length +const ApspLen = 40 + +// CanDecode returns the type of layer we can decode. +func (l APSP) CanDecode() gopacket.LayerClass { + return LayerTypeAPSP +} + +// DecodeFromBytes extracts our header data from a serialized packet. +func (l *APSP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < ApspLen { + df.SetTruncated() + return fmt.Errorf("invalid APSP header. Length %d less than %d", len(data), ApspLen) + } + l.NextHeader = data[0] + l.HdrExtLen = data[1] + l.CryptOffset = data[2] + l.SDVersVirt = data[3] + l.SecParamIdx = binary.BigEndian.Uint32(data[4:8]) + l.InitVector = binary.BigEndian.Uint64(data[8:16]) + l.SecTokenV2 = binary.BigEndian.Uint32(data[16:20]) + l.VirtKey = binary.BigEndian.Uint32(data[20:24]) + l.SrcEndpointID = binary.BigEndian.Uint64(data[24:32]) + l.DstEndpointID = binary.BigEndian.Uint64(data[32:40]) + l.BaseLayer = BaseLayer{Contents: data[:ApspLen]} + l.Payload = data[ApspLen:] + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (l APSP) SerializeTo(buf gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { + b := l.LayerContents() + writeTo, err := buf.PrependBytes(len(b)) + if err != nil { + return err + } + copy(writeTo, b) + return nil +} + +// LayerContents returns a byte array containing our serialized header. +func (l APSP) LayerContents() []byte { + bytes := make([]byte, ApspLen) + bytes[0] = l.NextHeader + bytes[1] = l.HdrExtLen + bytes[2] = l.CryptOffset + bytes[3] = l.SDVersVirt + binary.BigEndian.PutUint32(bytes[4:], l.SecParamIdx) + binary.BigEndian.PutUint64(bytes[8:], l.InitVector) + binary.BigEndian.PutUint32(bytes[16:], l.SecTokenV2) + binary.BigEndian.PutUint32(bytes[20:], l.VirtKey) + binary.BigEndian.PutUint64(bytes[24:], l.SrcEndpointID) + binary.BigEndian.PutUint64(bytes[32:], l.DstEndpointID) + return bytes +} + +// LayerPayload returns an IPv4 or IPv6 packet in serialized form. +func (l APSP) LayerPayload() []byte { + return l.Payload +} + +// NextLayerType returns the next layer type, either IPv4 or IPv6. +func (l APSP) NextLayerType() gopacket.LayerType { + // TODO: check for IPv6 + return LayerTypeIPv4 +} + +// LayerType returns LayerTypeAPSP. +func (l APSP) LayerType() gopacket.LayerType { + return LayerTypeAPSP +} + +func decodeAPSP(data []byte, p gopacket.PacketBuilder) error { + if len(data) == 0 { + return errors.New("decodeAPSP() failed, no data") + } + l := APSP{} + if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil { + return err + } + p.AddLayer(l) + return p.NextDecoder(l.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/arp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/arp.go new file mode 100644 index 0000000000..64120253a2 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/arp.go @@ -0,0 +1,118 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// Potential values for ARP.Operation. +const ( + ARPRequest = 1 + ARPReply = 2 +) + +// ARP is a ARP packet header. +type ARP struct { + BaseLayer + AddrType LinkType + Protocol EthernetType + HwAddressSize uint8 + ProtAddressSize uint8 + Operation uint16 + SourceHwAddress []byte + SourceProtAddress []byte + DstHwAddress []byte + DstProtAddress []byte +} + +// LayerType returns LayerTypeARP +func (arp *ARP) LayerType() gopacket.LayerType { return LayerTypeARP } + +// DecodeFromBytes decodes the given bytes into this layer. +func (arp *ARP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return fmt.Errorf("ARP length %d too short", len(data)) + } + arp.AddrType = LinkType(binary.BigEndian.Uint16(data[0:2])) + arp.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) + arp.HwAddressSize = data[4] + arp.ProtAddressSize = data[5] + arp.Operation = binary.BigEndian.Uint16(data[6:8]) + arpLength := 8 + 2*arp.HwAddressSize + 2*arp.ProtAddressSize + if len(data) < int(arpLength) { + df.SetTruncated() + return fmt.Errorf("ARP length %d too short, %d expected", len(data), arpLength) + } + arp.SourceHwAddress = data[8 : 8+arp.HwAddressSize] + arp.SourceProtAddress = data[8+arp.HwAddressSize : 8+arp.HwAddressSize+arp.ProtAddressSize] + arp.DstHwAddress = data[8+arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+arp.ProtAddressSize] + arp.DstProtAddress = data[8+2*arp.HwAddressSize+arp.ProtAddressSize : 8+2*arp.HwAddressSize+2*arp.ProtAddressSize] + + arp.Contents = data[:arpLength] + arp.Payload = data[arpLength:] + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (arp *ARP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + size := 8 + len(arp.SourceHwAddress) + len(arp.SourceProtAddress) + len(arp.DstHwAddress) + len(arp.DstProtAddress) + bytes, err := b.PrependBytes(size) + if err != nil { + return err + } + if opts.FixLengths { + if len(arp.SourceHwAddress) != len(arp.DstHwAddress) { + return errors.New("mismatched hardware address sizes") + } + arp.HwAddressSize = uint8(len(arp.SourceHwAddress)) + if len(arp.SourceProtAddress) != len(arp.DstProtAddress) { + return errors.New("mismatched prot address sizes") + } + arp.ProtAddressSize = uint8(len(arp.SourceProtAddress)) + } + binary.BigEndian.PutUint16(bytes, uint16(arp.AddrType)) + binary.BigEndian.PutUint16(bytes[2:], uint16(arp.Protocol)) + bytes[4] = arp.HwAddressSize + bytes[5] = arp.ProtAddressSize + binary.BigEndian.PutUint16(bytes[6:], arp.Operation) + start := 8 + for _, addr := range [][]byte{ + arp.SourceHwAddress, + arp.SourceProtAddress, + arp.DstHwAddress, + arp.DstProtAddress, + } { + copy(bytes[start:], addr) + start += len(addr) + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (arp *ARP) CanDecode() gopacket.LayerClass { + return LayerTypeARP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (arp *ARP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func decodeARP(data []byte, p gopacket.PacketBuilder) error { + + arp := &ARP{} + return decodingLayerDecoder(arp, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf.go new file mode 100644 index 0000000000..c714e9f4eb --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf.go @@ -0,0 +1,166 @@ +// 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. + +package layers + +// This file implements the ASF RMCP payload specified in section 3.2.2.3 of +// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +const ( + // ASFRMCPEnterprise is the IANA-assigned Enterprise Number of the ASF-RMCP. + ASFRMCPEnterprise uint32 = 4542 +) + +// ASFDataIdentifier encapsulates fields used to uniquely identify the format of +// the data block. +// +// While the enterprise number is almost always 4542 (ASF-RMCP), we support +// registering layers using structs of this type as a key in case any users are +// using OEM-extensions. +type ASFDataIdentifier struct { + + // Enterprise is the IANA Enterprise Number associated with the entity that + // defines the message type. A list can be found at + // https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers. + // This can be thought of as the namespace for the message type. + Enterprise uint32 + + // Type is the message type, defined by the entity associated with the + // enterprise above. No pressure, but in the context of EN 4542, 1 byte is + // the difference between sending a ping and telling a machine to do an + // unconditional power down (0x80 and 0x12 respectively). + Type uint8 +} + +// LayerType returns the payload layer type corresponding to an ASF message +// type. +func (a ASFDataIdentifier) LayerType() gopacket.LayerType { + if lt := asfDataLayerTypes[a]; lt != 0 { + return lt + } + + // some layer types don't have a payload, e.g. ASF-RMCP Presence Ping. + return gopacket.LayerTypePayload +} + +// RegisterASFLayerType allows specifying that the data block of ASF packets +// with a given enterprise number and type should be processed by a given layer +// type. This overrides any existing registrations, including defaults. +func RegisterASFLayerType(a ASFDataIdentifier, l gopacket.LayerType) { + asfDataLayerTypes[a] = l +} + +var ( + // ASFDataIdentifierPresencePong is the message type of the response to a + // Presence Ping message. It indicates the sender is ASF-RMCP-aware. + ASFDataIdentifierPresencePong = ASFDataIdentifier{ + Enterprise: ASFRMCPEnterprise, + Type: 0x40, + } + + // ASFDataIdentifierPresencePing is a message type sent to a managed client + // to solicit a Presence Pong response. Clients may ignore this if the RMCP + // version is unsupported. Sending this message with a sequence number <255 + // is the recommended way of finding out whether an implementation sends + // RMCP ACKs (e.g. iDRAC does, Super Micro does not). + // + // Systems implementing IPMI must respond to this ping to conform to the + // spec, so it is a good substitute for an ICMP ping. + ASFDataIdentifierPresencePing = ASFDataIdentifier{ + Enterprise: ASFRMCPEnterprise, + Type: 0x80, + } + + // asfDataLayerTypes is used to find the next layer for a given ASF header. + asfDataLayerTypes = map[ASFDataIdentifier]gopacket.LayerType{ + ASFDataIdentifierPresencePong: LayerTypeASFPresencePong, + } +) + +// ASF defines ASF's generic RMCP message Data block format. See section +// 3.2.2.3. +type ASF struct { + BaseLayer + ASFDataIdentifier + + // Tag is used to match request/response pairs. The tag of a response is set + // to that of the message it is responding to. If a message is + // unidirectional, i.e. not part of a request/response pair, this is set to + // 255. + Tag uint8 + + // 1 byte reserved, set to 0x00. + + // Length is the length of this layer's payload in bytes. + Length uint8 +} + +// LayerType returns LayerTypeASF. It partially satisfies Layer and +// SerializableLayer. +func (*ASF) LayerType() gopacket.LayerType { + return LayerTypeASF +} + +// CanDecode returns LayerTypeASF. It partially satisfies DecodingLayer. +func (a *ASF) CanDecode() gopacket.LayerClass { + return a.LayerType() +} + +// DecodeFromBytes makes the layer represent the provided bytes. It partially +// satisfies DecodingLayer. +func (a *ASF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return fmt.Errorf("invalid ASF data header, length %v less than 8", + len(data)) + } + + a.BaseLayer.Contents = data[:8] + a.BaseLayer.Payload = data[8:] + + a.Enterprise = binary.BigEndian.Uint32(data[:4]) + a.Type = uint8(data[4]) + a.Tag = uint8(data[5]) + // 1 byte reserved + a.Length = uint8(data[7]) + return nil +} + +// NextLayerType returns the layer type corresponding to the message type of +// this ASF data layer. This partially satisfies DecodingLayer. +func (a *ASF) NextLayerType() gopacket.LayerType { + return a.ASFDataIdentifier.LayerType() +} + +// SerializeTo writes the serialized fom of this layer into the SerializeBuffer, +// partially satisfying SerializableLayer. +func (a *ASF) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + payload := b.Bytes() + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + binary.BigEndian.PutUint32(bytes[:4], a.Enterprise) + bytes[4] = uint8(a.Type) + bytes[5] = a.Tag + bytes[6] = 0x00 + if opts.FixLengths { + a.Length = uint8(len(payload)) + } + bytes[7] = a.Length + return nil +} + +// decodeASF decodes the byte slice into an RMCP-ASF data struct. +func decodeASF(data []byte, p gopacket.PacketBuilder) error { + return decodingLayerDecoder(&ASF{}, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf_presencepong.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf_presencepong.go new file mode 100644 index 0000000000..526cca4b99 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/asf_presencepong.go @@ -0,0 +1,194 @@ +// 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. + +package layers + +// This file implements the RMCP ASF Presence Pong message, specified in section +// 3.2.4.3 of +// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf. It +// also contains non-competing elements from IPMI v2.0, specified in section +// 13.2.4 of +// https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf. + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +type ( + // ASFEntity is the type of individual entities that a Presence Pong + // response can indicate support of. The entities currently implemented by + // the spec are IPMI and ASFv1. + ASFEntity uint8 + + // ASFInteraction is the type of individual interactions that a Presence + // Pong response can indicate support for. The interactions currently + // implemented by the spec are RMCP security extensions. Although not + // specified, IPMI uses this field to indicate support for DASH, which is + // supported as well. + ASFInteraction uint8 +) + +const ( + // ASFDCMIEnterprise is the IANA-assigned Enterprise Number of the Data + // Center Manageability Interface Forum. The Presence Pong response's + // Enterprise field being set to this value indicates support for DCMI. The + // DCMI spec regards the OEM field as reserved, so these should be null. + ASFDCMIEnterprise uint32 = 36465 + + // ASFPresencePongEntityIPMI ANDs with Presence Pong's supported entities + // field if the managed system supports IPMI. + ASFPresencePongEntityIPMI ASFEntity = 1 << 7 + + // ASFPresencePongEntityASFv1 ANDs with Presence Pong's supported entities + // field if the managed system supports ASF v1.0. + ASFPresencePongEntityASFv1 ASFEntity = 1 + + // ASFPresencePongInteractionSecurityExtensions ANDs with Presence Pong's + // supported interactions field if the managed system supports RMCP v2.0 + // security extensions. See section 3.2.3. + ASFPresencePongInteractionSecurityExtensions ASFInteraction = 1 << 7 + + // ASFPresencePongInteractionDASH ANDs with Presence Pong's supported + // interactions field if the managed system supports DMTF DASH. See + // https://www.dmtf.org/standards/dash. + ASFPresencePongInteractionDASH ASFInteraction = 1 << 5 +) + +// ASFPresencePong defines the structure of a Presence Pong message's payload. +// See section 3.2.4.3. +type ASFPresencePong struct { + BaseLayer + + // Enterprise is the IANA Enterprise Number of an entity that has defined + // OEM-specific capabilities for the managed client. If no such capabilities + // exist, this is set to ASF's IANA Enterprise Number. + Enterprise uint32 + + // OEM identifies OEM-specific capabilities. Its structure is defined by the + // OEM. This is set to 0s if no OEM-specific capabilities exist. This + // implementation does not change byte order from the wire for this field. + OEM [4]byte + + // We break out entities and interactions into separate booleans as + // discovery is the entire point of this type of message, so we assume they + // are accessed. It also makes gopacket's default layer printing more + // useful. + + // IPMI is true if IPMI is supported by the managed system. There is no + // explicit version in the specification, however given the dates, this is + // assumed to be IPMI v1.0. Support for IPMI is contained in the "supported + // entities" field of the presence pong payload. + IPMI bool + + // ASFv1 indicates support for ASF v1.0. This seems somewhat redundant as + // ASF must be supported in order to receive a response. This is contained + // in the "supported entities" field of the presence pong payload. + ASFv1 bool + + // SecurityExtensions indicates support for RMCP Security Extensions, + // specified in ASF v2.0. This will always be false for v1.x + // implementations. This is contained in the "supported interactions" field + // of the presence pong payload. This field is defined in ASF v1.0, but has + // no useful value. + SecurityExtensions bool + + // DASH is true if DMTF DASH is supported. This is not specified in ASF + // v2.0, but in IPMI v2.0, however the former does not preclude it, so we + // support it. + DASH bool + + // 6 bytes reserved after the entities and interactions fields, set to 0s. +} + +// SupportsDCMI returns whether the Presence Pong message indicates support for +// the Data Center Management Interface, which is an extension of IPMI v2.0. +func (a *ASFPresencePong) SupportsDCMI() bool { + return a.Enterprise == ASFDCMIEnterprise && a.IPMI && a.ASFv1 +} + +// LayerType returns LayerTypeASFPresencePong. It partially satisfies Layer and +// SerializableLayer. +func (*ASFPresencePong) LayerType() gopacket.LayerType { + return LayerTypeASFPresencePong +} + +// CanDecode returns LayerTypeASFPresencePong. It partially satisfies +// DecodingLayer. +func (a *ASFPresencePong) CanDecode() gopacket.LayerClass { + return a.LayerType() +} + +// DecodeFromBytes makes the layer represent the provided bytes. It partially +// satisfies DecodingLayer. +func (a *ASFPresencePong) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 16 { + df.SetTruncated() + return fmt.Errorf("invalid ASF presence pong payload, length %v less than 16", + len(data)) + } + + a.BaseLayer.Contents = data[:16] + a.BaseLayer.Payload = data[16:] + + a.Enterprise = binary.BigEndian.Uint32(data[:4]) + copy(a.OEM[:], data[4:8]) // N.B. no byte order change + a.IPMI = data[8]&uint8(ASFPresencePongEntityIPMI) != 0 + a.ASFv1 = data[8]&uint8(ASFPresencePongEntityASFv1) != 0 + a.SecurityExtensions = data[9]&uint8(ASFPresencePongInteractionSecurityExtensions) != 0 + a.DASH = data[9]&uint8(ASFPresencePongInteractionDASH) != 0 + // ignore remaining 6 bytes; should be set to 0s + return nil +} + +// NextLayerType returns LayerTypePayload, as there are no further layers to +// decode. This partially satisfies DecodingLayer. +func (a *ASFPresencePong) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// SerializeTo writes the serialized fom of this layer into the SerializeBuffer, +// partially satisfying SerializableLayer. +func (a *ASFPresencePong) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(16) + if err != nil { + return err + } + + binary.BigEndian.PutUint32(bytes[:4], a.Enterprise) + + copy(bytes[4:8], a.OEM[:]) + + bytes[8] = 0 + if a.IPMI { + bytes[8] |= uint8(ASFPresencePongEntityIPMI) + } + if a.ASFv1 { + bytes[8] |= uint8(ASFPresencePongEntityASFv1) + } + + bytes[9] = 0 + if a.SecurityExtensions { + bytes[9] |= uint8(ASFPresencePongInteractionSecurityExtensions) + } + if a.DASH { + bytes[9] |= uint8(ASFPresencePongInteractionDASH) + } + + // zero-out remaining 6 bytes + for i := 10; i < len(bytes); i++ { + bytes[i] = 0x00 + } + + return nil +} + +// decodeASFPresencePong decodes the byte slice into an RMCP-ASF Presence Pong +// struct. +func decodeASFPresencePong(data []byte, p gopacket.PacketBuilder) error { + return decodingLayerDecoder(&ASFPresencePong{}, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/base.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/base.go new file mode 100644 index 0000000000..6a8b52daba --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/base.go @@ -0,0 +1,52 @@ +// 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 layers + +import ( + "github.com/gopacket/gopacket" +) + +// BaseLayer is a convenience struct which implements the LayerData and +// LayerPayload functions of the Layer interface. +type BaseLayer struct { + // Contents is the set of bytes that make up this layer. IE: for an + // Ethernet packet, this would be the set of bytes making up the + // Ethernet frame. + Contents []byte + // Payload is the set of bytes contained by (but not part of) this + // Layer. Again, to take Ethernet as an example, this would be the + // set of bytes encapsulated by the Ethernet protocol. + Payload []byte +} + +// LayerContents returns the bytes of the packet layer. +func (b *BaseLayer) LayerContents() []byte { return b.Contents } + +// LayerPayload returns the bytes contained within the packet layer. +func (b *BaseLayer) LayerPayload() []byte { return b.Payload } + +type layerDecodingLayer interface { + gopacket.Layer + DecodeFromBytes([]byte, gopacket.DecodeFeedback) error + NextLayerType() gopacket.LayerType +} + +func decodingLayerDecoder(d layerDecodingLayer, data []byte, p gopacket.PacketBuilder) error { + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(d) + next := d.NextLayerType() + if next == gopacket.LayerTypeZero { + return nil + } + return p.NextDecoder(next) +} + +// hacky way to zero out memory... there must be a better way? +var lotsOfZeros [1024]byte diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bfd.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bfd.go new file mode 100644 index 0000000000..e66fd1ee04 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bfd.go @@ -0,0 +1,484 @@ +// Copyright 2017 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// BFD Control Packet Format +// ------------------------- +// The current version of BFD's RFC (RFC 5880) contains the following +// diagram for the BFD Control packet format: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Vers | Diag |Sta|P|F|C|A|D|M| Detect Mult | Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | My Discriminator | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Your Discriminator | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Desired Min TX Interval | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Required Min RX Interval | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Required Min Echo RX Interval | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// An optional Authentication Section MAY be present: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Type | Auth Len | Authentication Data... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +// Simple Password Authentication Section Format +// --------------------------------------------- +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Type | Auth Len | Auth Key ID | Password... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +// Keyed MD5 and Meticulous Keyed MD5 Authentication Section Format +// ---------------------------------------------------------------- +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Type | Auth Len | Auth Key ID | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Key/Digest... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// +// Keyed SHA1 and Meticulous Keyed SHA1 Authentication Section Format +// ------------------------------------------------------------------ +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Type | Auth Len | Auth Key ID | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Auth Key/Hash... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// From https://tools.ietf.org/rfc/rfc5880.txt +const bfdMinimumRecordSizeInBytes int = 24 + +// BFDVersion represents the version as decoded from the BFD control message +type BFDVersion uint8 + +// BFDDiagnostic represents diagnostic infomation about a BFD session +type BFDDiagnostic uint8 + +// constants that define BFDDiagnostic flags +const ( + BFDDiagnosticNone BFDDiagnostic = 0 // No Diagnostic + BFDDiagnosticTimeExpired BFDDiagnostic = 1 // Control Detection Time Expired + BFDDiagnosticEchoFailed BFDDiagnostic = 2 // Echo Function Failed + BFDDiagnosticNeighborSignalDown BFDDiagnostic = 3 // Neighbor Signaled Session Down + BFDDiagnosticForwardPlaneReset BFDDiagnostic = 4 // Forwarding Plane Reset + BFDDiagnosticPathDown BFDDiagnostic = 5 // Path Down + BFDDiagnosticConcatPathDown BFDDiagnostic = 6 // Concatenated Path Down + BFDDiagnosticAdminDown BFDDiagnostic = 7 // Administratively Down + BFDDiagnosticRevConcatPathDown BFDDiagnostic = 8 // Reverse Concatenated Path Dow +) + +// String returns a string version of BFDDiagnostic +func (bd BFDDiagnostic) String() string { + switch bd { + default: + return "Unknown" + case BFDDiagnosticNone: + return "None" + case BFDDiagnosticTimeExpired: + return "Control Detection Time Expired" + case BFDDiagnosticEchoFailed: + return "Echo Function Failed" + case BFDDiagnosticNeighborSignalDown: + return "Neighbor Signaled Session Down" + case BFDDiagnosticForwardPlaneReset: + return "Forwarding Plane Reset" + case BFDDiagnosticPathDown: + return "Path Down" + case BFDDiagnosticConcatPathDown: + return "Concatenated Path Down" + case BFDDiagnosticAdminDown: + return "Administratively Down" + case BFDDiagnosticRevConcatPathDown: + return "Reverse Concatenated Path Down" + } +} + +// BFDState represents the state of a BFD session +type BFDState uint8 + +// constants that define BFDState +const ( + BFDStateAdminDown BFDState = 0 + BFDStateDown BFDState = 1 + BFDStateInit BFDState = 2 + BFDStateUp BFDState = 3 +) + +// String returns a string version of BFDState +func (s BFDState) String() string { + switch s { + default: + return "Unknown" + case BFDStateAdminDown: + return "Admin Down" + case BFDStateDown: + return "Down" + case BFDStateInit: + return "Init" + case BFDStateUp: + return "Up" + } +} + +// BFDDetectMultiplier represents the negotiated transmit interval, +// multiplied by this value, provides the Detection Time for the +// receiving system in Asynchronous mode. +type BFDDetectMultiplier uint8 + +// BFDDiscriminator is a unique, nonzero discriminator value used +// to demultiplex multiple BFD sessions between the same pair of systems. +type BFDDiscriminator uint32 + +// BFDTimeInterval represents a time interval in microseconds +type BFDTimeInterval uint32 + +// BFDAuthType represents the authentication used in the BFD session +type BFDAuthType uint8 + +// constants that define the BFDAuthType +const ( + BFDAuthTypeNone BFDAuthType = 0 // No Auth + BFDAuthTypePassword BFDAuthType = 1 // Simple Password + BFDAuthTypeKeyedMD5 BFDAuthType = 2 // Keyed MD5 + BFDAuthTypeMeticulousKeyedMD5 BFDAuthType = 3 // Meticulous Keyed MD5 + BFDAuthTypeKeyedSHA1 BFDAuthType = 4 // Keyed SHA1 + BFDAuthTypeMeticulousKeyedSHA1 BFDAuthType = 5 // Meticulous Keyed SHA1 +) + +// String returns a string version of BFDAuthType +func (at BFDAuthType) String() string { + switch at { + default: + return "Unknown" + case BFDAuthTypeNone: + return "No Authentication" + case BFDAuthTypePassword: + return "Simple Password" + case BFDAuthTypeKeyedMD5: + return "Keyed MD5" + case BFDAuthTypeMeticulousKeyedMD5: + return "Meticulous Keyed MD5" + case BFDAuthTypeKeyedSHA1: + return "Keyed SHA1" + case BFDAuthTypeMeticulousKeyedSHA1: + return "Meticulous Keyed SHA1" + } +} + +// BFDAuthKeyID represents the authentication key ID in use for +// this packet. This allows multiple keys to be active simultaneously. +type BFDAuthKeyID uint8 + +// BFDAuthSequenceNumber represents the sequence number for this packet. +// For Keyed Authentication, this value is incremented occasionally. For +// Meticulous Keyed Authentication, this value is incremented for each +// successive packet transmitted for a session. This provides protection +// against replay attacks. +type BFDAuthSequenceNumber uint32 + +// BFDAuthData represents the authentication key or digest +type BFDAuthData []byte + +// BFDAuthHeader represents authentication data used in the BFD session +type BFDAuthHeader struct { + AuthType BFDAuthType + KeyID BFDAuthKeyID + SequenceNumber BFDAuthSequenceNumber + Data BFDAuthData +} + +// Length returns the data length of the BFDAuthHeader based on the +// authentication type +func (h *BFDAuthHeader) Length() int { + switch h.AuthType { + case BFDAuthTypePassword: + return 3 + len(h.Data) + case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: + return 8 + len(h.Data) + case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: + return 8 + len(h.Data) + default: + return 0 + } +} + +// BFD represents a BFD control message packet whose payload contains +// the control information required to for a BFD session. +// +// References +// ---------- +// +// Wikipedia's BFD entry: +// +// https://en.wikipedia.org/wiki/Bidirectional_Forwarding_Detection +// This is the best place to get an overview of BFD. +// +// RFC 5880 "Bidirectional Forwarding Detection (BFD)" (2010) +// +// https://tools.ietf.org/html/rfc5880 +// This is the original BFD specification. +// +// RFC 5881 "Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop)" (2010) +// +// https://tools.ietf.org/html/rfc5881 +// Describes the use of the Bidirectional Forwarding Detection (BFD) +// protocol over IPv4 and IPv6 for single IP hops. +type BFD struct { + BaseLayer // Stores the packet bytes and payload bytes. + + Version BFDVersion // Version of the BFD protocol. + Diagnostic BFDDiagnostic // Diagnostic code for last state change + State BFDState // Current state + Poll bool // Requesting verification + Final bool // Responding to a received BFD Control packet that had the Poll (P) bit set. + ControlPlaneIndependent bool // BFD implementation does not share fate with its control plane + AuthPresent bool // Authentication Section is present and the session is to be authenticated + Demand bool // Demand mode is active + Multipoint bool // For future point-to-multipoint extensions. Must always be zero + DetectMultiplier BFDDetectMultiplier // Detection time multiplier + MyDiscriminator BFDDiscriminator // A unique, nonzero discriminator value + YourDiscriminator BFDDiscriminator // discriminator received from the remote system. + DesiredMinTxInterval BFDTimeInterval // Minimum interval, in microseconds, the local system would like to use when transmitting BFD Control packets + RequiredMinRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Control packets that this system is capable of supporting + RequiredMinEchoRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Echo packets that this system is capable of supporting + AuthHeader *BFDAuthHeader // Authentication data, variable length. +} + +// Length returns the data length of a BFD Control message which +// changes based on the presence and type of authentication +// contained in the message +func (d *BFD) Length() int { + if d.AuthPresent && (d.AuthHeader != nil) { + return bfdMinimumRecordSizeInBytes + d.AuthHeader.Length() + } + + return bfdMinimumRecordSizeInBytes +} + +// LayerType returns the layer type of the BFD object, which is LayerTypeBFD. +func (d *BFD) LayerType() gopacket.LayerType { + return LayerTypeBFD +} + +// decodeBFD analyses a byte slice and attempts to decode it as a BFD +// control packet +// +// If it succeeds, it loads p with information about the packet and returns nil. +// If it fails, it returns an error (non nil). +// +// This function is employed in layertypes.go to register the BFD layer. +func decodeBFD(data []byte, p gopacket.PacketBuilder) error { + + // Attempt to decode the byte slice. + d := &BFD{} + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + + // If the decoding worked, add the layer to the packet and set it + // as the application layer too, if there isn't already one. + p.AddLayer(d) + p.SetApplicationLayer(d) + + return nil +} + +// DecodeFromBytes analyses a byte slice and attempts to decode it as a BFD +// control packet. +// +// Upon succeeds, it loads the BFD object with information about the packet +// and returns nil. +// Upon failure, it returns an error (non nil). +func (d *BFD) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + + // If the data block is too short to be a BFD record, then return an error. + if len(data) < bfdMinimumRecordSizeInBytes { + df.SetTruncated() + return errors.New("BFD packet too short") + } + + pLen := uint8(data[3]) + if len(data) != int(pLen) { + return errors.New("BFD packet length does not match") + } + + // BFD type embeds type BaseLayer which contains two fields: + // Contents is supposed to contain the bytes of the data at this level. + // Payload is supposed to contain the payload of this level. + // Here we set the baselayer to be the bytes of the BFD record. + d.BaseLayer = BaseLayer{Contents: data[:len(data)]} + + // Extract the fields from the block of bytes. + // To make sense of this, refer to the packet diagram + // above and the section on endian conventions. + + // The first few fields are all packed into the first 32 bits. Unpack them. + d.Version = BFDVersion(((data[0] & 0xE0) >> 5)) + d.Diagnostic = BFDDiagnostic(data[0] & 0x1F) + data = data[1:] + + d.State = BFDState((data[0] & 0xC0) >> 6) + d.Poll = data[0]&0x20 != 0 + d.Final = data[0]&0x10 != 0 + d.ControlPlaneIndependent = data[0]&0x08 != 0 + d.AuthPresent = data[0]&0x04 != 0 + d.Demand = data[0]&0x02 != 0 + d.Multipoint = data[0]&0x01 != 0 + data = data[1:] + + data, d.DetectMultiplier = data[1:], BFDDetectMultiplier(data[0]) + data, _ = data[1:], uint8(data[0]) // Consume length + + // The remaining fields can just be copied in big endian order. + data, d.MyDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4])) + data, d.YourDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4])) + data, d.DesiredMinTxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) + data, d.RequiredMinRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) + data, d.RequiredMinEchoRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) + + if d.AuthPresent && (len(data) > 2) { + d.AuthHeader = &BFDAuthHeader{} + data, d.AuthHeader.AuthType = data[1:], BFDAuthType(data[0]) + data, _ = data[1:], uint8(data[0]) // Consume length + data, d.AuthHeader.KeyID = data[1:], BFDAuthKeyID(data[0]) + + switch d.AuthHeader.AuthType { + case BFDAuthTypePassword: + d.AuthHeader.Data = BFDAuthData(data) + case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: + // Skipped reserved byte + data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5])) + d.AuthHeader.Data = BFDAuthData(data) + case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: + // Skipped reserved byte + data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5])) + d.AuthHeader.Data = BFDAuthData(data) + } + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (d *BFD) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + data, err := b.PrependBytes(bfdMinimumRecordSizeInBytes) + if err != nil { + return err + } + + // Pack the first few fields into the first 32 bits. + data[0] = byte(byte(d.Version<<5) | byte(d.Diagnostic)) + h := uint8(0) + h |= (uint8(d.State) << 6) + h |= (uint8(bool2uint8(d.Poll)) << 5) + h |= (uint8(bool2uint8(d.Final)) << 4) + h |= (uint8(bool2uint8(d.ControlPlaneIndependent)) << 3) + h |= (uint8(bool2uint8(d.AuthPresent)) << 2) + h |= (uint8(bool2uint8(d.Demand)) << 1) + h |= uint8(bool2uint8(d.Multipoint)) + data[1] = byte(h) + data[2] = byte(d.DetectMultiplier) + data[3] = byte(d.Length()) + + // The remaining fields can just be copied in big endian order. + binary.BigEndian.PutUint32(data[4:], uint32(d.MyDiscriminator)) + binary.BigEndian.PutUint32(data[8:], uint32(d.YourDiscriminator)) + binary.BigEndian.PutUint32(data[12:], uint32(d.DesiredMinTxInterval)) + binary.BigEndian.PutUint32(data[16:], uint32(d.RequiredMinRxInterval)) + binary.BigEndian.PutUint32(data[20:], uint32(d.RequiredMinEchoRxInterval)) + + if d.AuthPresent && (d.AuthHeader != nil) { + auth, err := b.AppendBytes(int(d.AuthHeader.Length())) + if err != nil { + return err + } + + auth[0] = byte(d.AuthHeader.AuthType) + auth[1] = byte(d.AuthHeader.Length()) + auth[2] = byte(d.AuthHeader.KeyID) + + switch d.AuthHeader.AuthType { + case BFDAuthTypePassword: + copy(auth[3:], d.AuthHeader.Data) + case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: + auth[3] = byte(0) + binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber)) + copy(auth[8:], d.AuthHeader.Data) + case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: + auth[3] = byte(0) + binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber)) + copy(auth[8:], d.AuthHeader.Data) + } + } + + return nil +} + +// CanDecode returns a set of layers that BFD objects can decode. +// As BFD objects can only decide the BFD layer, we can return just that layer. +// Apparently a single layer type implements LayerClass. +func (d *BFD) CanDecode() gopacket.LayerClass { + return LayerTypeBFD +} + +// NextLayerType specifies the next layer that GoPacket should attempt to +// analyse after this (BFD) layer. As BFD packets do not contain any payload +// bytes, there are no further layers to analyse. +func (d *BFD) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// Payload returns an empty byte slice as BFD packets do not carry a payload +func (d *BFD) Payload() []byte { + return nil +} + +// bool2uint8 converts a bool to uint8 +func bool2uint8(b bool) uint8 { + if b { + return 1 + } + return 0 +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bitfield.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bitfield.go new file mode 100644 index 0000000000..7d54acf07e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/bitfield.go @@ -0,0 +1,18 @@ +// Copyright 2021 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. + +package layers + +type bitfield [1024]uint64 + +// set sets bit i in bitfield b to 1. +func (b *bitfield) set(i uint16) { + b[i>>6] |= (1 << (i & 0x3f)) +} + +// has reports whether bit i is set to 1 in bitfield b. +func (b *bitfield) has(i uint16) bool { + return b[i>>6]&(1<<(i&0x3f)) != 0 +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cdp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cdp.go new file mode 100644 index 0000000000..a920112e95 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cdp.go @@ -0,0 +1,659 @@ +// 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. + +// Enum types courtesy of... +// http://search.cpan.org/~mchapman/Net-CDP-0.09/lib/Net/CDP.pm +// https://code.google.com/p/ladvd/ +// http://anonsvn.wireshark.org/viewvc/releases/wireshark-1.8.6/epan/dissectors/packet-cdp.c + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// CDPTLVType is the type of each TLV value in a CiscoDiscovery packet. +type CDPTLVType uint16 + +// CDPTLVType values. +const ( + CDPTLVDevID CDPTLVType = 0x0001 + CDPTLVAddress CDPTLVType = 0x0002 + CDPTLVPortID CDPTLVType = 0x0003 + CDPTLVCapabilities CDPTLVType = 0x0004 + CDPTLVVersion CDPTLVType = 0x0005 + CDPTLVPlatform CDPTLVType = 0x0006 + CDPTLVIPPrefix CDPTLVType = 0x0007 + CDPTLVHello CDPTLVType = 0x0008 + CDPTLVVTPDomain CDPTLVType = 0x0009 + CDPTLVNativeVLAN CDPTLVType = 0x000a + CDPTLVFullDuplex CDPTLVType = 0x000b + CDPTLVVLANReply CDPTLVType = 0x000e + CDPTLVVLANQuery CDPTLVType = 0x000f + CDPTLVPower CDPTLVType = 0x0010 + CDPTLVMTU CDPTLVType = 0x0011 + CDPTLVExtendedTrust CDPTLVType = 0x0012 + CDPTLVUntrustedCOS CDPTLVType = 0x0013 + CDPTLVSysName CDPTLVType = 0x0014 + CDPTLVSysOID CDPTLVType = 0x0015 + CDPTLVMgmtAddresses CDPTLVType = 0x0016 + CDPTLVLocation CDPTLVType = 0x0017 + CDPTLVExternalPortID CDPTLVType = 0x0018 + CDPTLVPowerRequested CDPTLVType = 0x0019 + CDPTLVPowerAvailable CDPTLVType = 0x001a + CDPTLVPortUnidirectional CDPTLVType = 0x001b + CDPTLVEnergyWise CDPTLVType = 0x001d + CDPTLVSparePairPOE CDPTLVType = 0x001f +) + +// CiscoDiscoveryValue is a TLV value inside a CiscoDiscovery packet layer. +type CiscoDiscoveryValue struct { + Type CDPTLVType + Length uint16 + Value []byte +} + +// CiscoDiscovery is a packet layer containing the Cisco Discovery Protocol. +// See http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#31885 +type CiscoDiscovery struct { + BaseLayer + Version byte + TTL byte + Checksum uint16 + Values []CiscoDiscoveryValue +} + +// CDPCapability is the set of capabilities advertised by a CDP device. +type CDPCapability uint32 + +// CDPCapability values. +const ( + CDPCapMaskRouter CDPCapability = 0x0001 + CDPCapMaskTBBridge CDPCapability = 0x0002 + CDPCapMaskSPBridge CDPCapability = 0x0004 + CDPCapMaskSwitch CDPCapability = 0x0008 + CDPCapMaskHost CDPCapability = 0x0010 + CDPCapMaskIGMPFilter CDPCapability = 0x0020 + CDPCapMaskRepeater CDPCapability = 0x0040 + CDPCapMaskPhone CDPCapability = 0x0080 + CDPCapMaskRemote CDPCapability = 0x0100 +) + +// CDPCapabilities represents the capabilities of a device +type CDPCapabilities struct { + L3Router bool + TBBridge bool + SPBridge bool + L2Switch bool + IsHost bool + IGMPFilter bool + L1Repeater bool + IsPhone bool + RemotelyManaged bool +} + +// CDP Power-over-Ethernet values. +const ( + CDPPoEFourWire byte = 0x01 + CDPPoEPDArch byte = 0x02 + CDPPoEPDRequest byte = 0x04 + CDPPoEPSE byte = 0x08 +) + +// CDPSparePairPoE provides information on PoE. +type CDPSparePairPoE struct { + PSEFourWire bool // Supported / Not supported + PDArchShared bool // Shared / Independent + PDRequestOn bool // On / Off + PSEOn bool // On / Off +} + +// CDPVLANDialogue encapsulates a VLAN Query/Reply +type CDPVLANDialogue struct { + ID uint8 + VLAN uint16 +} + +// CDPPowerDialogue encapsulates a Power Query/Reply +type CDPPowerDialogue struct { + ID uint16 + MgmtID uint16 + Values []uint32 +} + +// CDPLocation provides location information for a CDP device. +type CDPLocation struct { + Type uint8 // Undocumented + Location string +} + +// CDPHello is a Cisco Hello message (undocumented, hence the "Unknown" fields) +type CDPHello struct { + OUI []byte + ProtocolID uint16 + ClusterMaster net.IP + Unknown1 net.IP + Version byte + SubVersion byte + Status byte + Unknown2 byte + ClusterCommander net.HardwareAddr + SwitchMAC net.HardwareAddr + Unknown3 byte + ManagementVLAN uint16 +} + +// CDPEnergyWiseSubtype is used within CDP to define TLV values. +type CDPEnergyWiseSubtype uint32 + +// CDPEnergyWiseSubtype values. +const ( + CDPEnergyWiseRole CDPEnergyWiseSubtype = 0x00000007 + CDPEnergyWiseDomain CDPEnergyWiseSubtype = 0x00000008 + CDPEnergyWiseName CDPEnergyWiseSubtype = 0x00000009 + CDPEnergyWiseReplyTo CDPEnergyWiseSubtype = 0x00000017 +) + +// CDPEnergyWise is used by CDP to monitor and control power usage. +type CDPEnergyWise struct { + EncryptedData []byte + Unknown1 uint32 + SequenceNumber uint32 + ModelNumber string + Unknown2 uint16 + HardwareID string + SerialNum string + Unknown3 []byte + Role string + Domain string + Name string + ReplyUnknown1 []byte + ReplyPort []byte + ReplyAddress []byte + ReplyUnknown2 []byte + ReplyUnknown3 []byte +} + +// CiscoDiscoveryInfo represents the decoded details for a set of CiscoDiscoveryValues +type CiscoDiscoveryInfo struct { + BaseLayer + CDPHello + DeviceID string + Addresses []net.IP + PortID string + Capabilities CDPCapabilities + Version string + Platform string + IPPrefixes []net.IPNet + VTPDomain string + NativeVLAN uint16 + FullDuplex bool + VLANReply CDPVLANDialogue + VLANQuery CDPVLANDialogue + PowerConsumption uint16 + MTU uint32 + ExtendedTrust uint8 + UntrustedCOS uint8 + SysName string + SysOID string + MgmtAddresses []net.IP + Location CDPLocation + PowerRequest CDPPowerDialogue + PowerAvailable CDPPowerDialogue + SparePairPoe CDPSparePairPoE + EnergyWise CDPEnergyWise + Unknown []CiscoDiscoveryValue +} + +// LayerType returns gopacket.LayerTypeCiscoDiscovery. +func (c *CiscoDiscovery) LayerType() gopacket.LayerType { + return LayerTypeCiscoDiscovery +} + +func decodeCiscoDiscovery(data []byte, p gopacket.PacketBuilder) error { + c := &CiscoDiscovery{ + Version: data[0], + TTL: data[1], + Checksum: binary.BigEndian.Uint16(data[2:4]), + } + if c.Version != 1 && c.Version != 2 { + return fmt.Errorf("Invalid CiscoDiscovery version number %d", c.Version) + } + var err error + c.Values, err = decodeCiscoDiscoveryTLVs(data[4:], p) + if err != nil { + return err + } + c.Contents = data[0:4] + c.Payload = data[4:] + p.AddLayer(c) + return p.NextDecoder(gopacket.DecodeFunc(decodeCiscoDiscoveryInfo)) +} + +// LayerType returns gopacket.LayerTypeCiscoDiscoveryInfo. +func (c *CiscoDiscoveryInfo) LayerType() gopacket.LayerType { + return LayerTypeCiscoDiscoveryInfo +} + +func decodeCiscoDiscoveryTLVs(data []byte, p gopacket.PacketBuilder) (values []CiscoDiscoveryValue, err error) { + for len(data) > 0 { + if len(data) < 4 { + p.SetTruncated() + return nil, errors.New("CDP TLV < 4 bytes") + } + val := CiscoDiscoveryValue{ + Type: CDPTLVType(binary.BigEndian.Uint16(data[:2])), + Length: binary.BigEndian.Uint16(data[2:4]), + } + if val.Length < 4 { + err = fmt.Errorf("Invalid CiscoDiscovery value length %d", val.Length) + break + } else if len(data) < int(val.Length) { + p.SetTruncated() + return nil, fmt.Errorf("CDP TLV < length %d", val.Length) + } + val.Value = data[4:val.Length] + values = append(values, val) + data = data[val.Length:] + } + return +} + +func decodeCiscoDiscoveryInfo(data []byte, p gopacket.PacketBuilder) error { + var err error + info := &CiscoDiscoveryInfo{BaseLayer: BaseLayer{Contents: data}} + p.AddLayer(info) + values, err := decodeCiscoDiscoveryTLVs(data, p) + if err != nil { // Unlikely, as parent decode will fail, but better safe... + return err + } + for _, val := range values { + switch val.Type { + case CDPTLVDevID: + info.DeviceID = string(val.Value) + case CDPTLVAddress: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + info.Addresses, err = decodeAddresses(val.Value) + if err != nil { + return err + } + case CDPTLVPortID: + info.PortID = string(val.Value) + case CDPTLVCapabilities: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + val := CDPCapability(binary.BigEndian.Uint32(val.Value[0:4])) + info.Capabilities.L3Router = (val&CDPCapMaskRouter > 0) + info.Capabilities.TBBridge = (val&CDPCapMaskTBBridge > 0) + info.Capabilities.SPBridge = (val&CDPCapMaskSPBridge > 0) + info.Capabilities.L2Switch = (val&CDPCapMaskSwitch > 0) + info.Capabilities.IsHost = (val&CDPCapMaskHost > 0) + info.Capabilities.IGMPFilter = (val&CDPCapMaskIGMPFilter > 0) + info.Capabilities.L1Repeater = (val&CDPCapMaskRepeater > 0) + info.Capabilities.IsPhone = (val&CDPCapMaskPhone > 0) + info.Capabilities.RemotelyManaged = (val&CDPCapMaskRemote > 0) + case CDPTLVVersion: + info.Version = string(val.Value) + case CDPTLVPlatform: + info.Platform = string(val.Value) + case CDPTLVIPPrefix: + v := val.Value + l := len(v) + if l%5 == 0 && l >= 5 { + for len(v) > 0 { + _, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", v[0], v[1], v[2], v[3], v[4])) + info.IPPrefixes = append(info.IPPrefixes, *ipnet) + v = v[5:] + } + } else { + return fmt.Errorf("Invalid TLV %v length %d", val.Type, len(val.Value)) + } + case CDPTLVHello: + if err = checkCDPTLVLen(val, 32); err != nil { + return err + } + v := val.Value + info.CDPHello.OUI = v[0:3] + info.CDPHello.ProtocolID = binary.BigEndian.Uint16(v[3:5]) + info.CDPHello.ClusterMaster = v[5:9] + info.CDPHello.Unknown1 = v[9:13] + info.CDPHello.Version = v[13] + info.CDPHello.SubVersion = v[14] + info.CDPHello.Status = v[15] + info.CDPHello.Unknown2 = v[16] + info.CDPHello.ClusterCommander = v[17:23] + info.CDPHello.SwitchMAC = v[23:29] + info.CDPHello.Unknown3 = v[29] + info.CDPHello.ManagementVLAN = binary.BigEndian.Uint16(v[30:32]) + case CDPTLVVTPDomain: + info.VTPDomain = string(val.Value) + case CDPTLVNativeVLAN: + if err = checkCDPTLVLen(val, 2); err != nil { + return err + } + info.NativeVLAN = binary.BigEndian.Uint16(val.Value[0:2]) + case CDPTLVFullDuplex: + if err = checkCDPTLVLen(val, 1); err != nil { + return err + } + info.FullDuplex = (val.Value[0] == 1) + case CDPTLVVLANReply: + if err = checkCDPTLVLen(val, 3); err != nil { + return err + } + info.VLANReply.ID = uint8(val.Value[0]) + info.VLANReply.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) + case CDPTLVVLANQuery: + if err = checkCDPTLVLen(val, 3); err != nil { + return err + } + info.VLANQuery.ID = uint8(val.Value[0]) + info.VLANQuery.VLAN = binary.BigEndian.Uint16(val.Value[1:3]) + case CDPTLVPower: + if err = checkCDPTLVLen(val, 2); err != nil { + return err + } + info.PowerConsumption = binary.BigEndian.Uint16(val.Value[0:2]) + case CDPTLVMTU: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + info.MTU = binary.BigEndian.Uint32(val.Value[0:4]) + case CDPTLVExtendedTrust: + if err = checkCDPTLVLen(val, 1); err != nil { + return err + } + info.ExtendedTrust = uint8(val.Value[0]) + case CDPTLVUntrustedCOS: + if err = checkCDPTLVLen(val, 1); err != nil { + return err + } + info.UntrustedCOS = uint8(val.Value[0]) + case CDPTLVSysName: + info.SysName = string(val.Value) + case CDPTLVSysOID: + info.SysOID = string(val.Value) + case CDPTLVMgmtAddresses: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + info.MgmtAddresses, err = decodeAddresses(val.Value) + if err != nil { + return err + } + case CDPTLVLocation: + if err = checkCDPTLVLen(val, 2); err != nil { + return err + } + info.Location.Type = uint8(val.Value[0]) + info.Location.Location = string(val.Value[1:]) + + // case CDPTLVLExternalPortID: + // Undocumented + case CDPTLVPowerRequested: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + info.PowerRequest.ID = binary.BigEndian.Uint16(val.Value[0:2]) + info.PowerRequest.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) + for n := 4; n < len(val.Value); n += 4 { + info.PowerRequest.Values = append(info.PowerRequest.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) + } + case CDPTLVPowerAvailable: + if err = checkCDPTLVLen(val, 4); err != nil { + return err + } + info.PowerAvailable.ID = binary.BigEndian.Uint16(val.Value[0:2]) + info.PowerAvailable.MgmtID = binary.BigEndian.Uint16(val.Value[2:4]) + for n := 4; n < len(val.Value); n += 4 { + info.PowerAvailable.Values = append(info.PowerAvailable.Values, binary.BigEndian.Uint32(val.Value[n:n+4])) + } + // case CDPTLVPortUnidirectional + // Undocumented + case CDPTLVEnergyWise: + if err = checkCDPTLVLen(val, 72); err != nil { + return err + } + info.EnergyWise.EncryptedData = val.Value[0:20] + info.EnergyWise.Unknown1 = binary.BigEndian.Uint32(val.Value[20:24]) + info.EnergyWise.SequenceNumber = binary.BigEndian.Uint32(val.Value[24:28]) + info.EnergyWise.ModelNumber = string(val.Value[28:44]) + info.EnergyWise.Unknown2 = binary.BigEndian.Uint16(val.Value[44:46]) + info.EnergyWise.HardwareID = string(val.Value[46:49]) + info.EnergyWise.SerialNum = string(val.Value[49:60]) + info.EnergyWise.Unknown3 = val.Value[60:68] + tlvLen := binary.BigEndian.Uint16(val.Value[68:70]) + tlvNum := binary.BigEndian.Uint16(val.Value[70:72]) + data := val.Value[72:] + if len(data) < int(tlvLen) { + return fmt.Errorf("Invalid TLV length %d vs %d", tlvLen, len(data)) + } + numSeen := 0 + for len(data) > 8 { + numSeen++ + if numSeen > int(tlvNum) { // Too many TLV's ? + return fmt.Errorf("Too many TLV's - wanted %d, saw %d", tlvNum, numSeen) + } + tType := CDPEnergyWiseSubtype(binary.BigEndian.Uint32(data[0:4])) + tLen := int(binary.BigEndian.Uint32(data[4:8])) + if tLen > len(data)-8 { + return fmt.Errorf("Invalid TLV length %d vs %d", tLen, len(data)-8) + } + data = data[8:] + switch tType { + case CDPEnergyWiseRole: + info.EnergyWise.Role = string(data[:]) + case CDPEnergyWiseDomain: + info.EnergyWise.Domain = string(data[:]) + case CDPEnergyWiseName: + info.EnergyWise.Name = string(data[:]) + case CDPEnergyWiseReplyTo: + if len(data) >= 18 { + info.EnergyWise.ReplyUnknown1 = data[0:2] + info.EnergyWise.ReplyPort = data[2:4] + info.EnergyWise.ReplyAddress = data[4:8] + info.EnergyWise.ReplyUnknown2 = data[8:10] + info.EnergyWise.ReplyUnknown3 = data[10:14] + } + } + data = data[tLen:] + } + case CDPTLVSparePairPOE: + if err = checkCDPTLVLen(val, 1); err != nil { + return err + } + v := val.Value[0] + info.SparePairPoe.PSEFourWire = (v&CDPPoEFourWire > 0) + info.SparePairPoe.PDArchShared = (v&CDPPoEPDArch > 0) + info.SparePairPoe.PDRequestOn = (v&CDPPoEPDRequest > 0) + info.SparePairPoe.PSEOn = (v&CDPPoEPSE > 0) + default: + info.Unknown = append(info.Unknown, val) + } + } + return nil +} + +// CDP Protocol Types +const ( + CDPProtocolTypeNLPID byte = 1 + CDPProtocolType802_2 byte = 2 +) + +// CDPAddressType is used to define TLV values within CDP addresses. +type CDPAddressType uint64 + +// CDP Address types. +const ( + CDPAddressTypeCLNP CDPAddressType = 0x81 + CDPAddressTypeIPV4 CDPAddressType = 0xcc + CDPAddressTypeIPV6 CDPAddressType = 0xaaaa030000000800 + CDPAddressTypeDECNET CDPAddressType = 0xaaaa030000006003 + CDPAddressTypeAPPLETALK CDPAddressType = 0xaaaa03000000809b + CDPAddressTypeIPX CDPAddressType = 0xaaaa030000008137 + CDPAddressTypeVINES CDPAddressType = 0xaaaa0300000080c4 + CDPAddressTypeXNS CDPAddressType = 0xaaaa030000000600 + CDPAddressTypeAPOLLO CDPAddressType = 0xaaaa030000008019 +) + +func decodeAddresses(v []byte) (addresses []net.IP, err error) { + numaddr := int(binary.BigEndian.Uint32(v[0:4])) + if numaddr < 1 { + return nil, fmt.Errorf("Invalid Address TLV number %d", numaddr) + } + v = v[4:] + if len(v) < numaddr*8 { + return nil, fmt.Errorf("Invalid Address TLV length %d", len(v)) + } + for i := 0; i < numaddr; i++ { + prottype := v[0] + if prottype != CDPProtocolTypeNLPID && prottype != CDPProtocolType802_2 { // invalid protocol type + return nil, fmt.Errorf("Invalid Address Protocol %d", prottype) + } + protlen := int(v[1]) + if (prottype == CDPProtocolTypeNLPID && protlen != 1) || + (prottype == CDPProtocolType802_2 && protlen != 3 && protlen != 8) { // invalid length + return nil, fmt.Errorf("Invalid Address Protocol length %d", protlen) + } + plen := make([]byte, 8) + copy(plen[8-protlen:], v[2:2+protlen]) + protocol := CDPAddressType(binary.BigEndian.Uint64(plen)) + v = v[2+protlen:] + addrlen := binary.BigEndian.Uint16(v[0:2]) + ab := v[2 : 2+addrlen] + if protocol == CDPAddressTypeIPV4 && addrlen == 4 { + addresses = append(addresses, net.IPv4(ab[0], ab[1], ab[2], ab[3])) + } else if protocol == CDPAddressTypeIPV6 && addrlen == 16 { + addresses = append(addresses, net.IP(ab)) + } else { + // only handle IPV4 & IPV6 for now + } + v = v[2+addrlen:] + if len(v) < 8 { + break + } + } + return +} + +func (t CDPTLVType) String() (s string) { + switch t { + case CDPTLVDevID: + s = "Device ID" + case CDPTLVAddress: + s = "Addresses" + case CDPTLVPortID: + s = "Port ID" + case CDPTLVCapabilities: + s = "Capabilities" + case CDPTLVVersion: + s = "Software Version" + case CDPTLVPlatform: + s = "Platform" + case CDPTLVIPPrefix: + s = "IP Prefix" + case CDPTLVHello: + s = "Protocol Hello" + case CDPTLVVTPDomain: + s = "VTP Management Domain" + case CDPTLVNativeVLAN: + s = "Native VLAN" + case CDPTLVFullDuplex: + s = "Full Duplex" + case CDPTLVVLANReply: + s = "VoIP VLAN Reply" + case CDPTLVVLANQuery: + s = "VLANQuery" + case CDPTLVPower: + s = "Power consumption" + case CDPTLVMTU: + s = "MTU" + case CDPTLVExtendedTrust: + s = "Extended Trust Bitmap" + case CDPTLVUntrustedCOS: + s = "Untrusted Port CoS" + case CDPTLVSysName: + s = "System Name" + case CDPTLVSysOID: + s = "System OID" + case CDPTLVMgmtAddresses: + s = "Management Addresses" + case CDPTLVLocation: + s = "Location" + case CDPTLVExternalPortID: + s = "External Port ID" + case CDPTLVPowerRequested: + s = "Power Requested" + case CDPTLVPowerAvailable: + s = "Power Available" + case CDPTLVPortUnidirectional: + s = "Port Unidirectional" + case CDPTLVEnergyWise: + s = "Energy Wise" + case CDPTLVSparePairPOE: + s = "Spare Pair POE" + default: + s = "Unknown" + } + return +} + +func (a CDPAddressType) String() (s string) { + switch a { + case CDPAddressTypeCLNP: + s = "Connectionless Network Protocol" + case CDPAddressTypeIPV4: + s = "IPv4" + case CDPAddressTypeIPV6: + s = "IPv6" + case CDPAddressTypeDECNET: + s = "DECnet Phase IV" + case CDPAddressTypeAPPLETALK: + s = "Apple Talk" + case CDPAddressTypeIPX: + s = "Novell IPX" + case CDPAddressTypeVINES: + s = "Banyan VINES" + case CDPAddressTypeXNS: + s = "Xerox Network Systems" + case CDPAddressTypeAPOLLO: + s = "Apollo" + default: + s = "Unknown" + } + return +} + +func (t CDPEnergyWiseSubtype) String() (s string) { + switch t { + case CDPEnergyWiseRole: + s = "Role" + case CDPEnergyWiseDomain: + s = "Domain" + case CDPEnergyWiseName: + s = "Name" + case CDPEnergyWiseReplyTo: + s = "ReplyTo" + default: + s = "Unknown" + } + return +} + +func checkCDPTLVLen(v CiscoDiscoveryValue, l int) (err error) { + if len(v.Value) < l { + err = fmt.Errorf("Invalid TLV %v length %d", v.Type, len(v.Value)) + } + return +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cip.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cip.go new file mode 100644 index 0000000000..efe498f099 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/cip.go @@ -0,0 +1,279 @@ +// Copyright 2018, 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. +// +//****************************************************************************** + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +//****************************************************************************** +// +// CIP (Common Industrial Protocol) Decoding Layer +// ------------------------------------------ +// This file provides a GoPacket decoding layer for CIP. +// +//****************************************************************************** + +// CIPService represents the service code in a CIP request/response +type CIPService uint8 + +// Common CIP Service codes +const ( + CIPServiceGetAttributesAll CIPService = 0x01 + CIPServiceSetAttributesAll CIPService = 0x02 + CIPServiceGetAttributeSingle CIPService = 0x0E + CIPServiceSetAttributeSingle CIPService = 0x10 + CIPServiceMultipleServicePacket CIPService = 0x0A +) + +func (cs CIPService) String() string { + switch cs { + case CIPServiceGetAttributesAll: + return "Get Attributes All" + case CIPServiceSetAttributesAll: + return "Set Attributes All" + case CIPServiceGetAttributeSingle: + return "Get Attribute Single" + case CIPServiceSetAttributeSingle: + return "Set Attribute Single" + case CIPServiceMultipleServicePacket: + return "Multiple Service Packet" + default: + return fmt.Sprintf("Unknown Service (0x%02x)", uint8(cs)) + } +} + +// CIPStatus represents the status code in a CIP response +type CIPStatus uint8 + +// Common CIP Status codes +const ( + CIPStatusSuccess CIPStatus = 0x00 + CIPStatusConnectionFailure CIPStatus = 0x01 + CIPStatusResourceUnavailable CIPStatus = 0x02 + CIPStatusInvalidParameterValue CIPStatus = 0x03 + CIPStatusPathSegmentError CIPStatus = 0x04 + CIPStatusPathDestinationUnknown CIPStatus = 0x05 + CIPStatusPartialTransfer CIPStatus = 0x06 + CIPStatusConnectionLost CIPStatus = 0x07 + CIPStatusServiceNotSupported CIPStatus = 0x08 + CIPStatusInvalidAttributeValue CIPStatus = 0x09 +) + +func (cs CIPStatus) String() string { + switch cs { + case CIPStatusSuccess: + return "Success" + case CIPStatusConnectionFailure: + return "Connection Failure" + case CIPStatusResourceUnavailable: + return "Resource Unavailable" + case CIPStatusInvalidParameterValue: + return "Invalid Parameter Value" + case CIPStatusPathSegmentError: + return "Path Segment Error" + case CIPStatusPathDestinationUnknown: + return "Path Destination Unknown" + case CIPStatusPartialTransfer: + return "Partial Transfer" + case CIPStatusConnectionLost: + return "Connection Lost" + case CIPStatusServiceNotSupported: + return "Service Not Supported" + case CIPStatusInvalidAttributeValue: + return "Invalid Attribute Value" + default: + return fmt.Sprintf("Unknown Status (0x%02x)", uint8(cs)) + } +} + +//****************************************************************************** + +// CIP represents a Common Industrial Protocol packet +type CIP struct { + BaseLayer + + Service CIPService // Service code + Response bool // true if this is a response, false if request + PathSize uint8 // Size of path in words (16-bit) + ClassID *uint32 // Class ID if present in path + InstanceID *uint32 // Instance ID if present in path + AttributeID *uint32 // Attribute ID if present in path + Status CIPStatus // Status code (response only) + AdditionalStatus []uint8 // Additional status bytes (response only) +} + +//****************************************************************************** + +// LayerType returns the layer type of the CIP object +func (c *CIP) LayerType() gopacket.LayerType { + return LayerTypeCIP +} + +//****************************************************************************** + +// decodeCIP analyses a byte slice and attempts to decode it as a CIP packet +func decodeCIP(data []byte, p gopacket.PacketBuilder) error { + c := &CIP{} + err := c.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(c) + p.SetApplicationLayer(c) + return p.NextDecoder(c.NextLayerType()) +} + +//****************************************************************************** + +// DecodeFromBytes analyses a byte slice and attempts to decode it as a CIP packet +func (c *CIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 2 { + df.SetTruncated() + return errors.New("CIP packet too short") + } + + // First byte is service code + // Bit 7 indicates if this is a response (1) or request (0) + c.Service = CIPService(data[0] & 0x7F) + c.Response = (data[0] & 0x80) != 0 + + offset := 1 + + if c.Response { + // Response packet structure + if len(data) < 4 { + df.SetTruncated() + return errors.New("CIP response packet too short") + } + // Reserved byte + offset++ + + // Status + c.Status = CIPStatus(data[offset]) + offset++ + + // Additional status size + additionalStatusSize := int(data[offset]) + offset++ + + // Additional status bytes + if additionalStatusSize > 0 { + if len(data) < offset+additionalStatusSize*2 { + df.SetTruncated() + return errors.New("CIP response packet truncated in additional status") + } + c.AdditionalStatus = data[offset : offset+additionalStatusSize*2] + offset += additionalStatusSize * 2 + } + } else { + // Request packet structure + // Path size in words + c.PathSize = data[offset] + offset++ + + pathBytes := int(c.PathSize) * 2 + if len(data) < offset+pathBytes { + df.SetTruncated() + return errors.New("CIP request packet truncated in path") + } + + // Parse path segments (simplified - only handle logical segments) + pathData := data[offset : offset+pathBytes] + c.parsePath(pathData) + offset += pathBytes + } + + c.BaseLayer = BaseLayer{ + Contents: data[:offset], + Payload: data[offset:], + } + + return nil +} + +//****************************************************************************** + +// parsePath parses CIP path segments (simplified implementation) +func (c *CIP) parsePath(data []byte) { + offset := 0 + for offset < len(data) { + if offset+2 > len(data) { + break + } + + segmentType := data[offset] + + // Logical segment (0x20 series) + if segmentType&0xE0 == 0x20 { + logicalType := (segmentType >> 2) & 0x07 + logicalFormat := segmentType & 0x03 + + var value uint32 + var size int + + switch logicalFormat { + case 0: // 8-bit + if offset+2 <= len(data) { + value = uint32(data[offset+1]) + size = 2 + } + case 1: // 16-bit + if offset+4 <= len(data) { + value = uint32(binary.LittleEndian.Uint16(data[offset+2 : offset+4])) + size = 4 + } + case 2: // 32-bit + if offset+6 <= len(data) { + value = binary.LittleEndian.Uint32(data[offset+2 : offset+6]) + size = 6 + } + default: + return + } + + switch logicalType { + case 0: // Class ID + c.ClassID = &value + case 1: // Instance ID + c.InstanceID = &value + case 4: // Attribute ID + c.AttributeID = &value + } + + offset += size + } else { + // Unknown segment type, skip + offset += 2 + } + } +} + +//****************************************************************************** + +// NextLayerType returns the layer type of the CIP payload +func (c *CIP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +//****************************************************************************** + +// Payload returns the CIP payload bytes +func (c *CIP) Payload() []byte { + return c.BaseLayer.Payload +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode +func (c *CIP) CanDecode() gopacket.LayerClass { + return LayerTypeCIP +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ctp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ctp.go new file mode 100644 index 0000000000..8b43cb8042 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ctp.go @@ -0,0 +1,110 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +// EthernetCTPFunction is the function code used by the EthernetCTP protocol to identify each +// EthernetCTP layer. +type EthernetCTPFunction uint16 + +// EthernetCTPFunction values. +const ( + EthernetCTPFunctionReply EthernetCTPFunction = 1 + EthernetCTPFunctionForwardData EthernetCTPFunction = 2 +) + +// EthernetCTP implements the EthernetCTP protocol, see http://www.mit.edu/people/jhawk/ctp.html. +// We split EthernetCTP up into the top-level EthernetCTP layer, followed by zero or more +// EthernetCTPForwardData layers, followed by a final EthernetCTPReply layer. +type EthernetCTP struct { + BaseLayer + SkipCount uint16 +} + +// LayerType returns gopacket.LayerTypeEthernetCTP. +func (c *EthernetCTP) LayerType() gopacket.LayerType { + return LayerTypeEthernetCTP +} + +// EthernetCTPForwardData is the ForwardData layer inside EthernetCTP. See EthernetCTP's docs for more +// details. +type EthernetCTPForwardData struct { + BaseLayer + Function EthernetCTPFunction + ForwardAddress []byte +} + +// LayerType returns gopacket.LayerTypeEthernetCTPForwardData. +func (c *EthernetCTPForwardData) LayerType() gopacket.LayerType { + return LayerTypeEthernetCTPForwardData +} + +// ForwardEndpoint returns the EthernetCTPForwardData ForwardAddress as an endpoint. +func (c *EthernetCTPForwardData) ForwardEndpoint() gopacket.Endpoint { + return gopacket.NewEndpoint(EndpointMAC, c.ForwardAddress) +} + +// EthernetCTPReply is the Reply layer inside EthernetCTP. See EthernetCTP's docs for more details. +type EthernetCTPReply struct { + BaseLayer + Function EthernetCTPFunction + ReceiptNumber uint16 + Data []byte +} + +// LayerType returns gopacket.LayerTypeEthernetCTPReply. +func (c *EthernetCTPReply) LayerType() gopacket.LayerType { + return LayerTypeEthernetCTPReply +} + +// Payload returns the EthernetCTP reply's Data bytes. +func (c *EthernetCTPReply) Payload() []byte { return c.Data } + +func decodeEthernetCTP(data []byte, p gopacket.PacketBuilder) error { + c := &EthernetCTP{ + SkipCount: binary.LittleEndian.Uint16(data[:2]), + BaseLayer: BaseLayer{data[:2], data[2:]}, + } + if c.SkipCount%2 != 0 { + return fmt.Errorf("EthernetCTP skip count is odd: %d", c.SkipCount) + } + p.AddLayer(c) + return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType)) +} + +// decodeEthernetCTPFromFunctionType reads in the first 2 bytes to determine the EthernetCTP +// layer type to decode next, then decodes based on that. +func decodeEthernetCTPFromFunctionType(data []byte, p gopacket.PacketBuilder) error { + function := EthernetCTPFunction(binary.LittleEndian.Uint16(data[:2])) + switch function { + case EthernetCTPFunctionReply: + reply := &EthernetCTPReply{ + Function: function, + ReceiptNumber: binary.LittleEndian.Uint16(data[2:4]), + Data: data[4:], + BaseLayer: BaseLayer{data, nil}, + } + p.AddLayer(reply) + p.SetApplicationLayer(reply) + return nil + case EthernetCTPFunctionForwardData: + forward := &EthernetCTPForwardData{ + Function: function, + ForwardAddress: data[2:8], + BaseLayer: BaseLayer{data[:8], data[8:]}, + } + p.AddLayer(forward) + return p.NextDecoder(gopacket.DecodeFunc(decodeEthernetCTPFromFunctionType)) + } + return fmt.Errorf("Unknown EthernetCTP function type %v", function) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv4.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv4.go new file mode 100644 index 0000000000..1f1e623ece --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv4.go @@ -0,0 +1,595 @@ +// Copyright 2016 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 layers + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// DHCPOp rerprents a bootp operation +type DHCPOp byte + +// bootp operations +const ( + DHCPOpRequest DHCPOp = 1 + DHCPOpReply DHCPOp = 2 +) + +// String returns a string version of a DHCPOp. +func (o DHCPOp) String() string { + switch o { + case DHCPOpRequest: + return "Request" + case DHCPOpReply: + return "Reply" + default: + return "Unknown" + } +} + +// DHCPMsgType represents a DHCP operation +type DHCPMsgType byte + +// Constants that represent DHCP operations +const ( + DHCPMsgTypeUnspecified DHCPMsgType = iota + DHCPMsgTypeDiscover + DHCPMsgTypeOffer + DHCPMsgTypeRequest + DHCPMsgTypeDecline + DHCPMsgTypeAck + DHCPMsgTypeNak + DHCPMsgTypeRelease + DHCPMsgTypeInform +) + +// String returns a string version of a DHCPMsgType. +func (o DHCPMsgType) String() string { + switch o { + case DHCPMsgTypeUnspecified: + return "Unspecified" + case DHCPMsgTypeDiscover: + return "Discover" + case DHCPMsgTypeOffer: + return "Offer" + case DHCPMsgTypeRequest: + return "Request" + case DHCPMsgTypeDecline: + return "Decline" + case DHCPMsgTypeAck: + return "Ack" + case DHCPMsgTypeNak: + return "Nak" + case DHCPMsgTypeRelease: + return "Release" + case DHCPMsgTypeInform: + return "Inform" + default: + return "Unknown" + } +} + +// DHCPMagic is the RFC 2131 "magic cooke" for DHCP. +var DHCPMagic uint32 = 0x63825363 + +// DHCPv4 contains data for a single DHCP packet. +type DHCPv4 struct { + BaseLayer + Operation DHCPOp + HardwareType LinkType + HardwareLen uint8 + RelayHops uint8 + Xid uint32 + Secs uint16 + Flags uint16 + ClientIP net.IP + YourClientIP net.IP + NextServerIP net.IP + RelayAgentIP net.IP + ClientHWAddr net.HardwareAddr + ServerName []byte + File []byte + Options DHCPOptions +} + +// DHCPOptions is used to get nicely printed option lists which would normally +// be cut off after 5 options. +type DHCPOptions []DHCPOption + +// String returns a string version of the options list. +func (o DHCPOptions) String() string { + buf := &bytes.Buffer{} + buf.WriteByte('[') + for i, opt := range o { + buf.WriteString(opt.String()) + if i+1 != len(o) { + buf.WriteString(", ") + } + } + buf.WriteByte(']') + return buf.String() +} + +// LayerType returns gopacket.LayerTypeDHCPv4 +func (d *DHCPv4) LayerType() gopacket.LayerType { return LayerTypeDHCPv4 } + +// DecodeFromBytes decodes the given bytes into this layer. +func (d *DHCPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 240 { + df.SetTruncated() + return fmt.Errorf("DHCPv4 length %d too short", len(data)) + } + d.Options = d.Options[:0] + d.Operation = DHCPOp(data[0]) + d.HardwareType = LinkType(data[1]) + d.HardwareLen = data[2] + d.RelayHops = data[3] + d.Xid = binary.BigEndian.Uint32(data[4:8]) + d.Secs = binary.BigEndian.Uint16(data[8:10]) + d.Flags = binary.BigEndian.Uint16(data[10:12]) + d.ClientIP = net.IP(data[12:16]) + d.YourClientIP = net.IP(data[16:20]) + d.NextServerIP = net.IP(data[20:24]) + d.RelayAgentIP = net.IP(data[24:28]) + d.ClientHWAddr = net.HardwareAddr(data[28 : 28+d.HardwareLen]) + d.ServerName = data[44:108] + d.File = data[108:236] + if binary.BigEndian.Uint32(data[236:240]) != DHCPMagic { + return InvalidMagicCookie + } + + if len(data) <= 240 { + // DHCP Packet could have no option (??) + return nil + } + + options := data[240:] + + stop := len(options) + start := 0 + for start < stop { + o := DHCPOption{} + if err := o.decode(options[start:]); err != nil { + return err + } + if o.Type == DHCPOptEnd { + break + } + d.Options = append(d.Options, o) + // Check if the option is a single byte pad + if o.Type == DHCPOptPad { + start++ + } else { + start += int(o.Length) + 2 + } + } + + d.Contents = data + + return nil +} + +// Len returns the length of a DHCPv4 packet. +func (d *DHCPv4) Len() uint16 { + n := uint16(240) + for _, o := range d.Options { + if o.Type == DHCPOptPad { + n++ + } else { + n += uint16(o.Length) + 2 + } + } + n++ // for opt end + return n +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (d *DHCPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + plen := int(d.Len()) + + data, err := b.PrependBytes(plen) + if err != nil { + return err + } + + data[0] = byte(d.Operation) + data[1] = byte(d.HardwareType) + if opts.FixLengths { + d.HardwareLen = uint8(len(d.ClientHWAddr)) + } + data[2] = d.HardwareLen + data[3] = d.RelayHops + binary.BigEndian.PutUint32(data[4:8], d.Xid) + binary.BigEndian.PutUint16(data[8:10], d.Secs) + binary.BigEndian.PutUint16(data[10:12], d.Flags) + copy(data[12:16], d.ClientIP.To4()) + copy(data[16:20], d.YourClientIP.To4()) + copy(data[20:24], d.NextServerIP.To4()) + copy(data[24:28], d.RelayAgentIP.To4()) + copy(data[28:44], d.ClientHWAddr) + copy(data[44:108], d.ServerName) + copy(data[108:236], d.File) + binary.BigEndian.PutUint32(data[236:240], DHCPMagic) + + offset := 240 + if len(d.Options) > 0 { + for _, o := range d.Options { + if err := o.encode(data[offset:]); err != nil { + return err + } + // A pad option is only a single byte + if o.Type == DHCPOptPad { + offset++ + } else { + offset += 2 + len(o.Data) + } + } + } + optend := NewDHCPOption(DHCPOptEnd, nil) + if err := optend.encode(data[offset:]); err != nil { + return err + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (d *DHCPv4) CanDecode() gopacket.LayerClass { + return LayerTypeDHCPv4 +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (d *DHCPv4) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func decodeDHCPv4(data []byte, p gopacket.PacketBuilder) error { + dhcp := &DHCPv4{} + err := dhcp.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(dhcp) + return p.NextDecoder(gopacket.LayerTypePayload) +} + +// DHCPOpt represents a DHCP option or parameter from RFC-2132 +type DHCPOpt byte + +// Constants for the DHCPOpt options. +const ( + DHCPOptPad DHCPOpt = 0 + DHCPOptSubnetMask DHCPOpt = 1 // 4, net.IP + DHCPOptTimeOffset DHCPOpt = 2 // 4, int32 (signed seconds from UTC) + DHCPOptRouter DHCPOpt = 3 // n*4, [n]net.IP + DHCPOptTimeServer DHCPOpt = 4 // n*4, [n]net.IP + DHCPOptNameServer DHCPOpt = 5 // n*4, [n]net.IP + DHCPOptDNS DHCPOpt = 6 // n*4, [n]net.IP + DHCPOptLogServer DHCPOpt = 7 // n*4, [n]net.IP + DHCPOptCookieServer DHCPOpt = 8 // n*4, [n]net.IP + DHCPOptLPRServer DHCPOpt = 9 // n*4, [n]net.IP + DHCPOptImpressServer DHCPOpt = 10 // n*4, [n]net.IP + DHCPOptResLocServer DHCPOpt = 11 // n*4, [n]net.IP + DHCPOptHostname DHCPOpt = 12 // n, string + DHCPOptBootfileSize DHCPOpt = 13 // 2, uint16 + DHCPOptMeritDumpFile DHCPOpt = 14 // >1, string + DHCPOptDomainName DHCPOpt = 15 // n, string + DHCPOptSwapServer DHCPOpt = 16 // n*4, [n]net.IP + DHCPOptRootPath DHCPOpt = 17 // n, string + DHCPOptExtensionsPath DHCPOpt = 18 // n, string + DHCPOptIPForwarding DHCPOpt = 19 // 1, bool + DHCPOptSourceRouting DHCPOpt = 20 // 1, bool + DHCPOptPolicyFilter DHCPOpt = 21 // 8*n, [n]{net.IP/net.IP} + DHCPOptDatagramMTU DHCPOpt = 22 // 2, uint16 + DHCPOptDefaultTTL DHCPOpt = 23 // 1, byte + DHCPOptPathMTUAgingTimeout DHCPOpt = 24 // 4, uint32 + DHCPOptPathPlateuTableOption DHCPOpt = 25 // 2*n, []uint16 + DHCPOptInterfaceMTU DHCPOpt = 26 // 2, uint16 + DHCPOptAllSubsLocal DHCPOpt = 27 // 1, bool + DHCPOptBroadcastAddr DHCPOpt = 28 // 4, net.IP + DHCPOptMaskDiscovery DHCPOpt = 29 // 1, bool + DHCPOptMaskSupplier DHCPOpt = 30 // 1, bool + DHCPOptRouterDiscovery DHCPOpt = 31 // 1, bool + DHCPOptSolicitAddr DHCPOpt = 32 // 4, net.IP + DHCPOptStaticRoute DHCPOpt = 33 // n*8, [n]{net.IP/net.IP} -- note the 2nd is router not mask + DHCPOptARPTrailers DHCPOpt = 34 // 1, bool + DHCPOptARPTimeout DHCPOpt = 35 // 4, uint32 + DHCPOptEthernetEncap DHCPOpt = 36 // 1, bool + DHCPOptTCPTTL DHCPOpt = 37 // 1, byte + DHCPOptTCPKeepAliveInt DHCPOpt = 38 // 4, uint32 + DHCPOptTCPKeepAliveGarbage DHCPOpt = 39 // 1, bool + DHCPOptNISDomain DHCPOpt = 40 // n, string + DHCPOptNISServers DHCPOpt = 41 // 4*n, [n]net.IP + DHCPOptNTPServers DHCPOpt = 42 // 4*n, [n]net.IP + DHCPOptVendorOption DHCPOpt = 43 // n, [n]byte // may be encapsulated. + DHCPOptNetBIOSTCPNS DHCPOpt = 44 // 4*n, [n]net.IP + DHCPOptNetBIOSTCPDDS DHCPOpt = 45 // 4*n, [n]net.IP + DHCPOptNETBIOSTCPNodeType DHCPOpt = 46 // 1, magic byte + DHCPOptNetBIOSTCPScope DHCPOpt = 47 // n, string + DHCPOptXFontServer DHCPOpt = 48 // n, string + DHCPOptXDisplayManager DHCPOpt = 49 // n, string + DHCPOptRequestIP DHCPOpt = 50 // 4, net.IP + DHCPOptLeaseTime DHCPOpt = 51 // 4, uint32 + DHCPOptExtOptions DHCPOpt = 52 // 1, 1/2/3 + DHCPOptMessageType DHCPOpt = 53 // 1, 1-7 + DHCPOptServerID DHCPOpt = 54 // 4, net.IP + DHCPOptParamsRequest DHCPOpt = 55 // n, []byte + DHCPOptMessage DHCPOpt = 56 // n, 3 + DHCPOptMaxMessageSize DHCPOpt = 57 // 2, uint16 + DHCPOptT1 DHCPOpt = 58 // 4, uint32 + DHCPOptT2 DHCPOpt = 59 // 4, uint32 + DHCPOptClassID DHCPOpt = 60 // n, []byte + DHCPOptClientID DHCPOpt = 61 // n >= 2, []byte + DHCPOptDomainSearch DHCPOpt = 119 // n, string + DHCPOptSIPServers DHCPOpt = 120 // n, url + DHCPOptClasslessStaticRoute DHCPOpt = 121 // + DHCPOptMUDURLV4 DHCPOpt = 161 // n, string + DHCPOptEnd DHCPOpt = 255 +) + +// String returns a string version of a DHCPOpt. +func (o DHCPOpt) String() string { + switch o { + case DHCPOptPad: + return "(padding)" + case DHCPOptSubnetMask: + return "SubnetMask" + case DHCPOptTimeOffset: + return "TimeOffset" + case DHCPOptRouter: + return "Router" + case DHCPOptTimeServer: + return "rfc868" // old time server protocol stringified to dissuade confusion w. NTP + case DHCPOptNameServer: + return "ien116" // obscure nameserver protocol stringified to dissuade confusion w. DNS + case DHCPOptDNS: + return "DNS" + case DHCPOptLogServer: + return "mitLCS" // MIT LCS server protocol yada yada w. Syslog + case DHCPOptCookieServer: + return "CookieServer" + case DHCPOptLPRServer: + return "LPRServer" + case DHCPOptImpressServer: + return "ImpressServer" + case DHCPOptResLocServer: + return "ResourceLocationServer" + case DHCPOptHostname: + return "Hostname" + case DHCPOptBootfileSize: + return "BootfileSize" + case DHCPOptMeritDumpFile: + return "MeritDumpFile" + case DHCPOptDomainName: + return "DomainName" + case DHCPOptSwapServer: + return "SwapServer" + case DHCPOptRootPath: + return "RootPath" + case DHCPOptExtensionsPath: + return "ExtensionsPath" + case DHCPOptIPForwarding: + return "IPForwarding" + case DHCPOptSourceRouting: + return "SourceRouting" + case DHCPOptPolicyFilter: + return "PolicyFilter" + case DHCPOptDatagramMTU: + return "DatagramMTU" + case DHCPOptDefaultTTL: + return "DefaultTTL" + case DHCPOptPathMTUAgingTimeout: + return "PathMTUAgingTimeout" + case DHCPOptPathPlateuTableOption: + return "PathPlateuTableOption" + case DHCPOptInterfaceMTU: + return "InterfaceMTU" + case DHCPOptAllSubsLocal: + return "AllSubsLocal" + case DHCPOptBroadcastAddr: + return "BroadcastAddress" + case DHCPOptMaskDiscovery: + return "MaskDiscovery" + case DHCPOptMaskSupplier: + return "MaskSupplier" + case DHCPOptRouterDiscovery: + return "RouterDiscovery" + case DHCPOptSolicitAddr: + return "SolicitAddr" + case DHCPOptStaticRoute: + return "StaticRoute" + case DHCPOptARPTrailers: + return "ARPTrailers" + case DHCPOptARPTimeout: + return "ARPTimeout" + case DHCPOptEthernetEncap: + return "EthernetEncap" + case DHCPOptTCPTTL: + return "TCPTTL" + case DHCPOptTCPKeepAliveInt: + return "TCPKeepAliveInt" + case DHCPOptTCPKeepAliveGarbage: + return "TCPKeepAliveGarbage" + case DHCPOptNISDomain: + return "NISDomain" + case DHCPOptNISServers: + return "NISServers" + case DHCPOptNTPServers: + return "NTPServers" + case DHCPOptVendorOption: + return "VendorOption" + case DHCPOptNetBIOSTCPNS: + return "NetBIOSOverTCPNS" + case DHCPOptNetBIOSTCPDDS: + return "NetBiosOverTCPDDS" + case DHCPOptNETBIOSTCPNodeType: + return "NetBIOSOverTCPNodeType" + case DHCPOptNetBIOSTCPScope: + return "NetBIOSOverTCPScope" + case DHCPOptXFontServer: + return "XFontServer" + case DHCPOptXDisplayManager: + return "XDisplayManager" + case DHCPOptEnd: + return "(end)" + case DHCPOptSIPServers: + return "SipServers" + case DHCPOptRequestIP: + return "RequestIP" + case DHCPOptLeaseTime: + return "LeaseTime" + case DHCPOptExtOptions: + return "ExtOpts" + case DHCPOptMessageType: + return "MessageType" + case DHCPOptServerID: + return "ServerID" + case DHCPOptParamsRequest: + return "ParamsRequest" + case DHCPOptMessage: + return "Message" + case DHCPOptMaxMessageSize: + return "MaxDHCPSize" + case DHCPOptT1: + return "Timer1" + case DHCPOptT2: + return "Timer2" + case DHCPOptClassID: + return "ClassID" + case DHCPOptClientID: + return "ClientID" + case DHCPOptDomainSearch: + return "DomainSearch" + case DHCPOptClasslessStaticRoute: + return "ClasslessStaticRoute" + case DHCPOptMUDURLV4: + return "ManufacturerUsageDescriptionURL" + default: + return "Unknown" + } +} + +// DHCPOption rerpresents a DHCP option. +type DHCPOption struct { + Type DHCPOpt + Length uint8 + Data []byte +} + +// String returns a string version of a DHCP Option. +func (o DHCPOption) String() string { + switch o.Type { + + case DHCPOptHostname, DHCPOptMeritDumpFile, DHCPOptDomainName, DHCPOptRootPath, + DHCPOptExtensionsPath, DHCPOptNISDomain, DHCPOptNetBIOSTCPScope, DHCPOptXFontServer, + DHCPOptXDisplayManager, DHCPOptMessage, DHCPOptDomainSearch: // string + return fmt.Sprintf("Option(%s:%s)", o.Type, string(o.Data)) + + case DHCPOptMessageType: + if len(o.Data) != 1 { + return fmt.Sprintf("Option(%s:INVALID)", o.Type) + } + return fmt.Sprintf("Option(%s:%s)", o.Type, DHCPMsgType(o.Data[0])) + + case DHCPOptSubnetMask, DHCPOptServerID, DHCPOptBroadcastAddr, + DHCPOptSolicitAddr, DHCPOptRequestIP: // net.IP + if len(o.Data) < 4 { + return fmt.Sprintf("Option(%s:INVALID)", o.Type) + } + return fmt.Sprintf("Option(%s:%s)", o.Type, net.IP(o.Data)) + + case DHCPOptT1, DHCPOptT2, DHCPOptLeaseTime, DHCPOptPathMTUAgingTimeout, + DHCPOptARPTimeout, DHCPOptTCPKeepAliveInt: // uint32 + if len(o.Data) != 4 { + return fmt.Sprintf("Option(%s:INVALID)", o.Type) + } + return fmt.Sprintf("Option(%s:%d)", o.Type, + uint32(o.Data[0])<<24|uint32(o.Data[1])<<16|uint32(o.Data[2])<<8|uint32(o.Data[3])) + + case DHCPOptParamsRequest: + buf := &bytes.Buffer{} + buf.WriteString(fmt.Sprintf("Option(%s:", o.Type)) + for i, v := range o.Data { + buf.WriteString(DHCPOpt(v).String()) + if i+1 != len(o.Data) { + buf.WriteByte(',') + } + } + buf.WriteString(")") + return buf.String() + + default: + return fmt.Sprintf("Option(%s:%v)", o.Type, o.Data) + } +} + +// NewDHCPOption constructs a new DHCPOption with a given type and data. +func NewDHCPOption(t DHCPOpt, data []byte) DHCPOption { + o := DHCPOption{Type: t} + if data != nil { + o.Data = data + o.Length = uint8(len(data)) + } + return o +} + +func (o *DHCPOption) encode(b []byte) error { + switch o.Type { + case DHCPOptPad, DHCPOptEnd: + b[0] = byte(o.Type) + default: + b[0] = byte(o.Type) + b[1] = o.Length + copy(b[2:], o.Data) + } + return nil +} + +func (o *DHCPOption) decode(data []byte) error { + if len(data) < 1 { + // Pad/End have a length of 1 + return DecOptionNotEnoughData + } + o.Type = DHCPOpt(data[0]) + switch o.Type { + case DHCPOptPad, DHCPOptEnd: + o.Data = nil + default: + if len(data) < 2 { + return DecOptionNotEnoughData + } + o.Length = data[1] + if int(o.Length) > len(data[2:]) { + return DecOptionMalformed + } + o.Data = data[2 : 2+int(o.Length)] + } + return nil +} + +// DHCPv4Error is used for constant errors for DHCPv4. It is needed for test asserts. +type DHCPv4Error string + +// DHCPv4Error implements error interface. +func (d DHCPv4Error) Error() string { + return string(d) +} + +const ( + // DecOptionNotEnoughData is returned when there is not enough data during option's decode process + DecOptionNotEnoughData = DHCPv4Error("Not enough data to decode") + // DecOptionMalformed is returned when the option is malformed + DecOptionMalformed = DHCPv4Error("Option is malformed") + // InvalidMagicCookie is returned when Magic cookie is missing into BOOTP header + InvalidMagicCookie = DHCPv4Error("Bad DHCP header") +) diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6.go new file mode 100644 index 0000000000..ef0c2455a8 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6.go @@ -0,0 +1,360 @@ +// Copyright 2018 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 layers + +import ( + "encoding/binary" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// DHCPv6MsgType represents a DHCPv6 operation +type DHCPv6MsgType byte + +// Constants that represent DHCP operations +const ( + DHCPv6MsgTypeUnspecified DHCPv6MsgType = iota + DHCPv6MsgTypeSolicit + DHCPv6MsgTypeAdvertise + DHCPv6MsgTypeRequest + DHCPv6MsgTypeConfirm + DHCPv6MsgTypeRenew + DHCPv6MsgTypeRebind + DHCPv6MsgTypeReply + DHCPv6MsgTypeRelease + DHCPv6MsgTypeDecline + DHCPv6MsgTypeReconfigure + DHCPv6MsgTypeInformationRequest + DHCPv6MsgTypeRelayForward + DHCPv6MsgTypeRelayReply +) + +// String returns a string version of a DHCPv6MsgType. +func (o DHCPv6MsgType) String() string { + switch o { + case DHCPv6MsgTypeUnspecified: + return "Unspecified" + case DHCPv6MsgTypeSolicit: + return "Solicit" + case DHCPv6MsgTypeAdvertise: + return "Advertise" + case DHCPv6MsgTypeRequest: + return "Request" + case DHCPv6MsgTypeConfirm: + return "Confirm" + case DHCPv6MsgTypeRenew: + return "Renew" + case DHCPv6MsgTypeRebind: + return "Rebind" + case DHCPv6MsgTypeReply: + return "Reply" + case DHCPv6MsgTypeRelease: + return "Release" + case DHCPv6MsgTypeDecline: + return "Decline" + case DHCPv6MsgTypeReconfigure: + return "Reconfigure" + case DHCPv6MsgTypeInformationRequest: + return "InformationRequest" + case DHCPv6MsgTypeRelayForward: + return "RelayForward" + case DHCPv6MsgTypeRelayReply: + return "RelayReply" + default: + return "Unknown" + } +} + +// DHCPv6 contains data for a single DHCP packet. +type DHCPv6 struct { + BaseLayer + MsgType DHCPv6MsgType + HopCount uint8 + LinkAddr net.IP + PeerAddr net.IP + TransactionID []byte + Options DHCPv6Options +} + +// LayerType returns gopacket.LayerTypeDHCPv6 +func (d *DHCPv6) LayerType() gopacket.LayerType { return LayerTypeDHCPv6 } + +// DecodeFromBytes decodes the given bytes into this layer. +func (d *DHCPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("DHCPv6 length %d too short", len(data)) + } + d.BaseLayer = BaseLayer{Contents: data} + d.Options = d.Options[:0] + d.MsgType = DHCPv6MsgType(data[0]) + + offset := 0 + if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply { + if len(data) < 34 { + df.SetTruncated() + return fmt.Errorf("DHCPv6 length %d too short for message type %d", len(data), d.MsgType) + } + d.HopCount = data[1] + d.LinkAddr = net.IP(data[2:18]) + d.PeerAddr = net.IP(data[18:34]) + offset = 34 + } else { + d.TransactionID = data[1:4] + offset = 4 + } + + stop := len(data) + for offset < stop { + o := DHCPv6Option{} + if err := o.decode(data[offset:]); err != nil { + return err + } + d.Options = append(d.Options, o) + offset += int(o.Length) + 4 // 2 from option code, 2 from option length + } + + return nil +} + +// Len returns the length of a DHCPv6 packet. +func (d *DHCPv6) Len() int { + n := 1 + if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply { + n += 33 + } else { + n += 3 + } + + for _, o := range d.Options { + n += int(o.Length) + 4 // 2 from option code, 2 from option length + } + + return n +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (d *DHCPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + plen := int(d.Len()) + + data, err := b.PrependBytes(plen) + if err != nil { + return err + } + + offset := 0 + data[0] = byte(d.MsgType) + if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply { + data[1] = byte(d.HopCount) + copy(data[2:18], d.LinkAddr.To16()) + copy(data[18:34], d.PeerAddr.To16()) + offset = 34 + } else { + copy(data[1:4], d.TransactionID) + offset = 4 + } + + if len(d.Options) > 0 { + for _, o := range d.Options { + if err := o.encode(data[offset:], opts); err != nil { + return err + } + offset += int(o.Length) + 4 // 2 from option code, 2 from option length + } + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (d *DHCPv6) CanDecode() gopacket.LayerClass { + return LayerTypeDHCPv6 +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (d *DHCPv6) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func decodeDHCPv6(data []byte, p gopacket.PacketBuilder) error { + dhcp := &DHCPv6{} + err := dhcp.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(dhcp) + return p.NextDecoder(gopacket.LayerTypePayload) +} + +// DHCPv6StatusCode represents a DHCP status code - RFC-3315 +type DHCPv6StatusCode uint16 + +// Constants for the DHCPv6StatusCode. +const ( + DHCPv6StatusCodeSuccess DHCPv6StatusCode = iota + DHCPv6StatusCodeUnspecFail + DHCPv6StatusCodeNoAddrsAvail + DHCPv6StatusCodeNoBinding + DHCPv6StatusCodeNotOnLink + DHCPv6StatusCodeUseMulticast +) + +// String returns a string version of a DHCPv6StatusCode. +func (o DHCPv6StatusCode) String() string { + switch o { + case DHCPv6StatusCodeSuccess: + return "Success" + case DHCPv6StatusCodeUnspecFail: + return "UnspecifiedFailure" + case DHCPv6StatusCodeNoAddrsAvail: + return "NoAddressAvailable" + case DHCPv6StatusCodeNoBinding: + return "NoBinding" + case DHCPv6StatusCodeNotOnLink: + return "NotOnLink" + case DHCPv6StatusCodeUseMulticast: + return "UseMulticast" + default: + return "Unknown" + } +} + +// DHCPv6DUIDType represents a DHCP DUID - RFC-3315 +type DHCPv6DUIDType uint16 + +// Constants for the DHCPv6DUIDType. +const ( + DHCPv6DUIDTypeLLT DHCPv6DUIDType = iota + 1 + DHCPv6DUIDTypeEN + DHCPv6DUIDTypeLL +) + +// String returns a string version of a DHCPv6DUIDType. +func (o DHCPv6DUIDType) String() string { + switch o { + case DHCPv6DUIDTypeLLT: + return "LLT" + case DHCPv6DUIDTypeEN: + return "EN" + case DHCPv6DUIDTypeLL: + return "LL" + default: + return "Unknown" + } +} + +// DHCPv6DUID means DHCP Unique Identifier as stated in RFC 3315, section 9 (https://tools.ietf.org/html/rfc3315#page-19) +type DHCPv6DUID struct { + Type DHCPv6DUIDType + // LLT, LL + HardwareType []byte + // EN + EnterpriseNumber []byte + // LLT + Time []byte + // LLT, LL + LinkLayerAddress net.HardwareAddr + // EN + Identifier []byte +} + +// DecodeFromBytes decodes the given bytes into a DHCPv6DUID +func (d *DHCPv6DUID) DecodeFromBytes(data []byte) error { + if len(data) < 2 { + return fmt.Errorf("Not enough bytes to decode: %d", len(data)) + } + + d.Type = DHCPv6DUIDType(binary.BigEndian.Uint16(data[:2])) + if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL { + if len(data) < 4 { + return fmt.Errorf("Not enough bytes to decode: %d", len(data)) + } + d.HardwareType = data[2:4] + } + + if d.Type == DHCPv6DUIDTypeLLT { + if len(data) < 8 { + return fmt.Errorf("Not enough bytes to decode: %d", len(data)) + } + d.Time = data[4:8] + d.LinkLayerAddress = net.HardwareAddr(data[8:]) + } else if d.Type == DHCPv6DUIDTypeEN { + if len(data) < 6 { + return fmt.Errorf("Not enough bytes to decode: %d", len(data)) + } + d.EnterpriseNumber = data[2:6] + d.Identifier = data[6:] + } else { // DHCPv6DUIDTypeLL + if len(data) < 4 { + return fmt.Errorf("Not enough bytes to decode: %d", len(data)) + } + d.LinkLayerAddress = net.HardwareAddr(data[4:]) + } + + return nil +} + +// Encode encodes the DHCPv6DUID in a slice of bytes +func (d *DHCPv6DUID) Encode() []byte { + length := d.Len() + data := make([]byte, length) + binary.BigEndian.PutUint16(data[0:2], uint16(d.Type)) + + if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL { + copy(data[2:4], d.HardwareType) + } + + if d.Type == DHCPv6DUIDTypeLLT { + copy(data[4:8], d.Time) + copy(data[8:], d.LinkLayerAddress) + } else if d.Type == DHCPv6DUIDTypeEN { + copy(data[2:6], d.EnterpriseNumber) + copy(data[6:], d.Identifier) + } else { + copy(data[4:], d.LinkLayerAddress) + } + + return data +} + +// Len returns the length of the DHCPv6DUID, respecting the type +func (d *DHCPv6DUID) Len() int { + length := 2 // d.Type + if d.Type == DHCPv6DUIDTypeLLT { + length += 2 /*HardwareType*/ + 4 /*d.Time*/ + len(d.LinkLayerAddress) + } else if d.Type == DHCPv6DUIDTypeEN { + length += 4 /*d.EnterpriseNumber*/ + len(d.Identifier) + } else { // LL + length += 2 /*d.HardwareType*/ + len(d.LinkLayerAddress) + } + + return length +} + +func (d *DHCPv6DUID) String() string { + duid := "Type: " + d.Type.String() + ", " + if d.Type == DHCPv6DUIDTypeLLT { + duid += fmt.Sprintf("HardwareType: %v, Time: %v, LinkLayerAddress: %v", d.HardwareType, d.Time, d.LinkLayerAddress) + } else if d.Type == DHCPv6DUIDTypeEN { + duid += fmt.Sprintf("EnterpriseNumber: %v, Identifier: %v", d.EnterpriseNumber, d.Identifier) + } else { // DHCPv6DUIDTypeLL + duid += fmt.Sprintf("HardwareType: %v, LinkLayerAddress: %v", d.HardwareType, d.LinkLayerAddress) + } + return duid +} + +func decodeDHCPv6DUID(data []byte) (*DHCPv6DUID, error) { + duid := &DHCPv6DUID{} + err := duid.DecodeFromBytes(data) + if err != nil { + return nil, err + } + return duid, nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6_options.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6_options.go new file mode 100644 index 0000000000..fd25775b98 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dhcpv6_options.go @@ -0,0 +1,622 @@ +// Copyright 2018 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. + +package layers + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// DHCPv6Opt represents a DHCP option or parameter from RFC-3315 +type DHCPv6Opt uint16 + +// Constants for the DHCPv6Opt options. +const ( + DHCPv6OptClientID DHCPv6Opt = 1 + DHCPv6OptServerID DHCPv6Opt = 2 + DHCPv6OptIANA DHCPv6Opt = 3 + DHCPv6OptIATA DHCPv6Opt = 4 + DHCPv6OptIAAddr DHCPv6Opt = 5 + DHCPv6OptOro DHCPv6Opt = 6 + DHCPv6OptPreference DHCPv6Opt = 7 + DHCPv6OptElapsedTime DHCPv6Opt = 8 + DHCPv6OptRelayMessage DHCPv6Opt = 9 + DHCPv6OptAuth DHCPv6Opt = 11 + DHCPv6OptUnicast DHCPv6Opt = 12 + DHCPv6OptStatusCode DHCPv6Opt = 13 + DHCPv6OptRapidCommit DHCPv6Opt = 14 + DHCPv6OptUserClass DHCPv6Opt = 15 + DHCPv6OptVendorClass DHCPv6Opt = 16 + DHCPv6OptVendorOpts DHCPv6Opt = 17 + DHCPv6OptInterfaceID DHCPv6Opt = 18 + DHCPv6OptReconfigureMessage DHCPv6Opt = 19 + DHCPv6OptReconfigureAccept DHCPv6Opt = 20 + + // RFC 3319 Session Initiation Protocol (SIP) + DHCPv6OptSIPServersDomainList DHCPv6Opt = 21 + DHCPv6OptSIPServersAddressList DHCPv6Opt = 22 + + // RFC 3646 DNS Configuration + DHCPv6OptDNSServers DHCPv6Opt = 23 + DHCPv6OptDomainList DHCPv6Opt = 24 + + // RFC 3633 Prefix Delegation + DHCPv6OptIAPD DHCPv6Opt = 25 + DHCPv6OptIAPrefix DHCPv6Opt = 26 + + // RFC 3898 Network Information Service (NIS) + DHCPv6OptNISServers DHCPv6Opt = 27 + DHCPv6OptNISPServers DHCPv6Opt = 28 + DHCPv6OptNISDomainName DHCPv6Opt = 29 + DHCPv6OptNISPDomainName DHCPv6Opt = 30 + + // RFC 4075 Simple Network Time Protocol (SNTP) + DHCPv6OptSNTPServers DHCPv6Opt = 31 + + // RFC 4242 Information Refresh Time Option + DHCPv6OptInformationRefreshTime DHCPv6Opt = 32 + + // RFC 4280 Broadcast and Multicast Control Servers + DHCPv6OptBCMCSServerDomainNameList DHCPv6Opt = 33 + DHCPv6OptBCMCSServerAddressList DHCPv6Opt = 34 + + // RFC 4776 Civic Address ConfigurationOption + DHCPv6OptGeoconfCivic DHCPv6Opt = 36 + + // RFC 4649 Relay Agent Remote-ID + DHCPv6OptRemoteID DHCPv6Opt = 37 + + // RFC 4580 Relay Agent Subscriber-ID + DHCPv6OptSubscriberID DHCPv6Opt = 38 + + // RFC 4704 Client Full Qualified Domain Name (FQDN) + DHCPv6OptClientFQDN DHCPv6Opt = 39 + + // RFC 5192 Protocol for Carrying Authentication for Network Access (PANA) + DHCPv6OptPanaAgent DHCPv6Opt = 40 + + // RFC 4833 Timezone Options + DHCPv6OptNewPOSIXTimezone DHCPv6Opt = 41 + DHCPv6OptNewTZDBTimezone DHCPv6Opt = 42 + + // RFC 4994 Relay Agent Echo Request + DHCPv6OptEchoRequestOption DHCPv6Opt = 43 + + // RFC 5007 Leasequery + DHCPv6OptLQQuery DHCPv6Opt = 44 + DHCPv6OptCLTTime DHCPv6Opt = 45 + DHCPv6OptClientData DHCPv6Opt = 46 + DHCPv6OptLQRelayData DHCPv6Opt = 47 + DHCPv6OptLQClientLink DHCPv6Opt = 48 + + // RFC 6610 Home Information Discovery in Mobile IPv6 (MIPv6) + DHCPv6OptMIP6HNIDF DHCPv6Opt = 49 + DHCPv6OptMIP6VDINF DHCPv6Opt = 50 + DHCPv6OptMIP6IDINF DHCPv6Opt = 69 + DHCPv6OptMIP6UDINF DHCPv6Opt = 70 + DHCPv6OptMIP6HNP DHCPv6Opt = 71 + DHCPv6OptMIP6HAA DHCPv6Opt = 72 + DHCPv6OptMIP6HAF DHCPv6Opt = 73 + + // RFC 5223 Discovering Location-to-Service Translation (LoST) Servers + DHCPv6OptV6LOST DHCPv6Opt = 51 + + // RFC 5417 Control And Provisioning of Wireless Access Points (CAPWAP) + DHCPv6OptCAPWAPACV6 DHCPv6Opt = 52 + + // RFC 5460 Bulk Leasequery + DHCPv6OptRelayID DHCPv6Opt = 53 + + // RFC 5678 IEEE 802.21 Mobility Services (MoS) Discovery + DHCPv6OptIPv6AddressMoS DHCPv6Opt = 54 + DHCPv6OptIPv6FQDNMoS DHCPv6Opt = 55 + + // RFC 5908 NTP Server Option + DHCPv6OptNTPServer DHCPv6Opt = 56 + + // RFC 5986 Discovering the Local Location Information Server (LIS) + DHCPv6OptV6AccessDomain DHCPv6Opt = 57 + + // RFC 5986 SIP User Agent + DHCPv6OptSIPUACSList DHCPv6Opt = 58 + + // RFC 5970 Options for Network Boot + DHCPv6OptBootFileURL DHCPv6Opt = 59 + DHCPv6OptBootFileParam DHCPv6Opt = 60 + DHCPv6OptClientArchType DHCPv6Opt = 61 + DHCPv6OptNII DHCPv6Opt = 62 + + // RFC 6225 Coordinate-Based Location Configuration Information + DHCPv6OptGeolocation DHCPv6Opt = 63 + + // RFC 6334 Dual-Stack Lite + DHCPv6OptAFTRName DHCPv6Opt = 64 + + // RFC 6440 EAP Re-authentication Protocol (ERP) + DHCPv6OptERPLocalDomainName DHCPv6Opt = 65 + + // RFC 6422 Relay-Supplied DHCP Options + DHCPv6OptRSOO DHCPv6Opt = 66 + + // RFC 6603 Prefix Exclude Option for DHCPv6-based Prefix Delegation + DHCPv6OptPDExclude DHCPv6Opt = 67 + + // RFC 6607 Virtual Subnet Selection + DHCPv6OptVSS DHCPv6Opt = 68 + + // RFC 6731 Improved Recursive DNS Server Selection for Multi-Interfaced Nodes + DHCPv6OptRDNSSSelection DHCPv6Opt = 74 + + // RFC 6784 Kerberos Options for DHCPv6 + DHCPv6OptKRBPrincipalName DHCPv6Opt = 75 + DHCPv6OptKRBRealmName DHCPv6Opt = 76 + DHCPv6OptKRBKDC DHCPv6Opt = 77 + + // RFC 6939 Client Link-Layer Address Option + DHCPv6OptClientLinkLayerAddress DHCPv6Opt = 79 + + // RFC 6977 Triggering DHCPv6 Reconfiguration from Relay Agents + DHCPv6OptLinkAddress DHCPv6Opt = 80 + + // RFC 7037 RADIUS Option for the DHCPv6 Relay Agent + DHCPv6OptRADIUS DHCPv6Opt = 81 + + // RFC 7083 Modification to Default Values of SOL_MAX_RT and INF_MAX_RT + DHCPv6OptSolMaxRt DHCPv6Opt = 82 + DHCPv6OptInfMaxRt DHCPv6Opt = 83 + + // RFC 7078 Distributing Address Selection Policy + DHCPv6OptAddrSel DHCPv6Opt = 84 + DHCPv6OptAddrSelTable DHCPv6Opt = 85 + + // RFC 7291 DHCP Options for the Port Control Protocol (PCP) + DHCPv6OptV6PCPServer DHCPv6Opt = 86 + + // RFC 7341 DHCPv4-over-DHCPv6 (DHCP 4o6) Transport + DHCPv6OptDHCPv4Message DHCPv6Opt = 87 + DHCPv6OptDHCPv4OverDHCPv6Server DHCPv6Opt = 88 + + // RFC 7598 Configuration of Softwire Address and Port-Mapped Clients + DHCPv6OptS46Rule DHCPv6Opt = 89 + DHCPv6OptS46BR DHCPv6Opt = 90 + DHCPv6OptS46DMR DHCPv6Opt = 91 + DHCPv6OptS46V4V4Bind DHCPv6Opt = 92 + DHCPv6OptS46PortParameters DHCPv6Opt = 93 + DHCPv6OptS46ContMAPE DHCPv6Opt = 94 + DHCPv6OptS46ContMAPT DHCPv6Opt = 95 + DHCPv6OptS46ContLW DHCPv6Opt = 96 + + // RFC 7600 IPv4 Residual Deployment via IPv6 + DHCPv6Opt4RD DHCPv6Opt = 97 + DHCPv6Opt4RDMapRule DHCPv6Opt = 98 + DHCPv6Opt4RDNonMapRule DHCPv6Opt = 99 + + // RFC 7653 Active Leasequery + DHCPv6OptLQBaseTime DHCPv6Opt = 100 + DHCPv6OptLQStartTime DHCPv6Opt = 101 + DHCPv6OptLQEndTime DHCPv6Opt = 102 + + // RFC 7710 Captive-Portal Identification + DHCPv6OptCaptivePortal DHCPv6Opt = 103 + + // RFC 7774 Multicast Protocol for Low-Power and Lossy Networks (MPL) Parameter Configuration + DHCPv6OptMPLParameters DHCPv6Opt = 104 + + // RFC 7839 Access-Network-Identifier (ANI) + DHCPv6OptANIATT DHCPv6Opt = 105 + DHCPv6OptANINetworkName DHCPv6Opt = 106 + DHCPv6OptANIAPName DHCPv6Opt = 107 + DHCPv6OptANIAPBSSID DHCPv6Opt = 108 + DHCPv6OptANIOperatorID DHCPv6Opt = 109 + DHCPv6OptANIOperatorRealm DHCPv6Opt = 110 + + // RFC 8026 Unified IPv4-in-IPv6 Softwire Customer Premises Equipment (CPE) + DHCPv6OptS46Priority DHCPv6Opt = 111 + + // draft-ietf-opsawg-mud-25 Manufacturer Usage Description (MUD) + DHCPv6OptMUDURLV6 DHCPv6Opt = 112 + + // RFC 8115 IPv4-Embedded Multicast and Unicast IPv6 Prefixes + DHCPv6OptV6Prefix64 DHCPv6Opt = 113 + + // RFC 8156 DHCPv6 Failover Protocol + DHCPv6OptFBindingStatus DHCPv6Opt = 114 + DHCPv6OptFConnectFlags DHCPv6Opt = 115 + DHCPv6OptFDNSRemovalInfo DHCPv6Opt = 116 + DHCPv6OptFDNSHostName DHCPv6Opt = 117 + DHCPv6OptFDNSZoneName DHCPv6Opt = 118 + DHCPv6OptFDNSFlags DHCPv6Opt = 119 + DHCPv6OptFExpirationTime DHCPv6Opt = 120 + DHCPv6OptFMaxUnacknowledgedBNDUPD DHCPv6Opt = 121 + DHCPv6OptFMCLT DHCPv6Opt = 122 + DHCPv6OptFPartnerLifetime DHCPv6Opt = 123 + DHCPv6OptFPartnerLifetimeSent DHCPv6Opt = 124 + DHCPv6OptFPartnerDownTime DHCPv6Opt = 125 + DHCPv6OptFPartnerRawCltTime DHCPv6Opt = 126 + DHCPv6OptFProtocolVersion DHCPv6Opt = 127 + DHCPv6OptFKeepaliveTime DHCPv6Opt = 128 + DHCPv6OptFReconfigureData DHCPv6Opt = 129 + DHCPv6OptFRelationshipName DHCPv6Opt = 130 + DHCPv6OptFServerFlags DHCPv6Opt = 131 + DHCPv6OptFServerState DHCPv6Opt = 132 + DHCPv6OptFStartTimeOfState DHCPv6Opt = 133 + DHCPv6OptFStateExpirationTime DHCPv6Opt = 134 + + // RFC 8357 Generalized UDP Source Port for DHCP Relay + DHCPv6OptRelayPort DHCPv6Opt = 135 + + // draft-ietf-netconf-zerotouch-25 Zero Touch Provisioning for Networking Devices + DHCPv6OptV6ZeroTouchRedirect DHCPv6Opt = 136 + + // RFC 6153 Access Network Discovery and Selection Function (ANDSF) Discovery + DHCPv6OptIPV6AddressANDSF DHCPv6Opt = 143 +) + +// String returns a string version of a DHCPv6Opt. +func (o DHCPv6Opt) String() string { + switch o { + case DHCPv6OptClientID: + return "ClientID" + case DHCPv6OptServerID: + return "ServerID" + case DHCPv6OptIANA: + return "IA_NA" + case DHCPv6OptIATA: + return "IA_TA" + case DHCPv6OptIAAddr: + return "IAAddr" + case DHCPv6OptOro: + return "Oro" + case DHCPv6OptPreference: + return "Preference" + case DHCPv6OptElapsedTime: + return "ElapsedTime" + case DHCPv6OptRelayMessage: + return "RelayMessage" + case DHCPv6OptAuth: + return "Auth" + case DHCPv6OptUnicast: + return "Unicast" + case DHCPv6OptStatusCode: + return "StatusCode" + case DHCPv6OptRapidCommit: + return "RapidCommit" + case DHCPv6OptUserClass: + return "UserClass" + case DHCPv6OptVendorClass: + return "VendorClass" + case DHCPv6OptVendorOpts: + return "VendorOpts" + case DHCPv6OptInterfaceID: + return "InterfaceID" + case DHCPv6OptReconfigureMessage: + return "ReconfigureMessage" + case DHCPv6OptReconfigureAccept: + return "ReconfigureAccept" + case DHCPv6OptSIPServersDomainList: + return "SIPServersDomainList" + case DHCPv6OptSIPServersAddressList: + return "SIPServersAddressList" + case DHCPv6OptDNSServers: + return "DNSRecursiveNameServer" + case DHCPv6OptDomainList: + return "DomainSearchList" + case DHCPv6OptIAPD: + return "IdentityAssociationPrefixDelegation" + case DHCPv6OptIAPrefix: + return "IAPDPrefix" + case DHCPv6OptNISServers: + return "NISServers" + case DHCPv6OptNISPServers: + return "NISv2Servers" + case DHCPv6OptNISDomainName: + return "NISDomainName" + case DHCPv6OptNISPDomainName: + return "NISv2DomainName" + case DHCPv6OptSNTPServers: + return "SNTPServers" + case DHCPv6OptInformationRefreshTime: + return "InformationRefreshTime" + case DHCPv6OptBCMCSServerDomainNameList: + return "BCMCSControlServersDomainNameList" + case DHCPv6OptBCMCSServerAddressList: + return "BCMCSControlServersAddressList" + case DHCPv6OptGeoconfCivic: + return "CivicAddress" + case DHCPv6OptRemoteID: + return "RelayAgentRemoteID" + case DHCPv6OptSubscriberID: + return "RelayAgentSubscriberID" + case DHCPv6OptClientFQDN: + return "ClientFQDN" + case DHCPv6OptPanaAgent: + return "PANAAuthenticationAgent" + case DHCPv6OptNewPOSIXTimezone: + return "NewPOSIXTimezone" + case DHCPv6OptNewTZDBTimezone: + return "NewTZDBTimezone" + case DHCPv6OptEchoRequestOption: + return "EchoRequest" + case DHCPv6OptLQQuery: + return "LeasequeryQuery" + case DHCPv6OptClientData: + return "LeasequeryClientData" + case DHCPv6OptCLTTime: + return "LeasequeryClientLastTransactionTime" + case DHCPv6OptLQRelayData: + return "LeasequeryRelayData" + case DHCPv6OptLQClientLink: + return "LeasequeryClientLink" + case DHCPv6OptMIP6HNIDF: + return "MIPv6HomeNetworkIDFQDN" + case DHCPv6OptMIP6VDINF: + return "MIPv6VisitedHomeNetworkInformation" + case DHCPv6OptMIP6IDINF: + return "MIPv6IdentifiedHomeNetworkInformation" + case DHCPv6OptMIP6UDINF: + return "MIPv6UnrestrictedHomeNetworkInformation" + case DHCPv6OptMIP6HNP: + return "MIPv6HomeNetworkPrefix" + case DHCPv6OptMIP6HAA: + return "MIPv6HomeAgentAddress" + case DHCPv6OptMIP6HAF: + return "MIPv6HomeAgentFQDN" + case DHCPv6OptV6LOST: + return "LoST Server" + case DHCPv6OptCAPWAPACV6: + return "CAPWAPAccessControllerV6" + case DHCPv6OptRelayID: + return "LeasequeryRelayID" + case DHCPv6OptIPv6AddressMoS: + return "MoSIPv6Address" + case DHCPv6OptIPv6FQDNMoS: + return "MoSDomainNameList" + case DHCPv6OptNTPServer: + return "NTPServer" + case DHCPv6OptV6AccessDomain: + return "AccessNetworkDomainName" + case DHCPv6OptSIPUACSList: + return "SIPUserAgentConfigurationServiceDomains" + case DHCPv6OptBootFileURL: + return "BootFileURL" + case DHCPv6OptBootFileParam: + return "BootFileParameters" + case DHCPv6OptClientArchType: + return "ClientSystemArchitectureType" + case DHCPv6OptNII: + return "ClientNetworkInterfaceIdentifier" + case DHCPv6OptGeolocation: + return "Geolocation" + case DHCPv6OptAFTRName: + return "AFTRName" + case DHCPv6OptERPLocalDomainName: + return "AFTRName" + case DHCPv6OptRSOO: + return "RSOOption" + case DHCPv6OptPDExclude: + return "PrefixExclude" + case DHCPv6OptVSS: + return "VirtualSubnetSelection" + case DHCPv6OptRDNSSSelection: + return "RDNSSSelection" + case DHCPv6OptKRBPrincipalName: + return "KerberosPrincipalName" + case DHCPv6OptKRBRealmName: + return "KerberosRealmName" + case DHCPv6OptKRBKDC: + return "KerberosKDC" + case DHCPv6OptClientLinkLayerAddress: + return "ClientLinkLayerAddress" + case DHCPv6OptLinkAddress: + return "LinkAddress" + case DHCPv6OptRADIUS: + return "RADIUS" + case DHCPv6OptSolMaxRt: + return "SolMaxRt" + case DHCPv6OptInfMaxRt: + return "InfMaxRt" + case DHCPv6OptAddrSel: + return "AddressSelection" + case DHCPv6OptAddrSelTable: + return "AddressSelectionTable" + case DHCPv6OptV6PCPServer: + return "PCPServer" + case DHCPv6OptDHCPv4Message: + return "DHCPv4Message" + case DHCPv6OptDHCPv4OverDHCPv6Server: + return "DHCP4o6ServerAddress" + case DHCPv6OptS46Rule: + return "S46Rule" + case DHCPv6OptS46BR: + return "S46BR" + case DHCPv6OptS46DMR: + return "S46DMR" + case DHCPv6OptS46V4V4Bind: + return "S46IPv4IPv6AddressBinding" + case DHCPv6OptS46PortParameters: + return "S46PortParameters" + case DHCPv6OptS46ContMAPE: + return "S46MAPEContainer" + case DHCPv6OptS46ContMAPT: + return "S46MAPTContainer" + case DHCPv6OptS46ContLW: + return "S46Lightweight4Over6Container" + case DHCPv6Opt4RD: + return "4RD" + case DHCPv6Opt4RDMapRule: + return "4RDMapRule" + case DHCPv6Opt4RDNonMapRule: + return "4RDNonMapRule" + case DHCPv6OptLQBaseTime: + return "LQBaseTime" + case DHCPv6OptLQStartTime: + return "LQStartTime" + case DHCPv6OptLQEndTime: + return "LQEndTime" + case DHCPv6OptCaptivePortal: + return "CaptivePortal" + case DHCPv6OptMPLParameters: + return "MPLParameterConfiguration" + case DHCPv6OptANIATT: + return "ANIAccessTechnologyType" + case DHCPv6OptANINetworkName: + return "ANINetworkName" + case DHCPv6OptANIAPName: + return "ANIAccessPointName" + case DHCPv6OptANIAPBSSID: + return "ANIAccessPointBSSID" + case DHCPv6OptANIOperatorID: + return "ANIOperatorIdentifier" + case DHCPv6OptANIOperatorRealm: + return "ANIOperatorRealm" + case DHCPv6OptS46Priority: + return "S64Priority" + case DHCPv6OptMUDURLV6: + return "ManufacturerUsageDescriptionURL" + case DHCPv6OptV6Prefix64: + return "V6Prefix64" + case DHCPv6OptFBindingStatus: + return "FailoverBindingStatus" + case DHCPv6OptFConnectFlags: + return "FailoverConnectFlags" + case DHCPv6OptFDNSRemovalInfo: + return "FailoverDNSRemovalInfo" + case DHCPv6OptFDNSHostName: + return "FailoverDNSHostName" + case DHCPv6OptFDNSZoneName: + return "FailoverDNSZoneName" + case DHCPv6OptFDNSFlags: + return "FailoverDNSFlags" + case DHCPv6OptFExpirationTime: + return "FailoverExpirationTime" + case DHCPv6OptFMaxUnacknowledgedBNDUPD: + return "FailoverMaxUnacknowledgedBNDUPDMessages" + case DHCPv6OptFMCLT: + return "FailoverMaximumClientLeadTime" + case DHCPv6OptFPartnerLifetime: + return "FailoverPartnerLifetime" + case DHCPv6OptFPartnerLifetimeSent: + return "FailoverPartnerLifetimeSent" + case DHCPv6OptFPartnerDownTime: + return "FailoverPartnerDownTime" + case DHCPv6OptFPartnerRawCltTime: + return "FailoverPartnerRawClientLeadTime" + case DHCPv6OptFProtocolVersion: + return "FailoverProtocolVersion" + case DHCPv6OptFKeepaliveTime: + return "FailoverKeepaliveTime" + case DHCPv6OptFReconfigureData: + return "FailoverReconfigureData" + case DHCPv6OptFRelationshipName: + return "FailoverRelationshipName" + case DHCPv6OptFServerFlags: + return "FailoverServerFlags" + case DHCPv6OptFServerState: + return "FailoverServerState" + case DHCPv6OptFStartTimeOfState: + return "FailoverStartTimeOfState" + case DHCPv6OptFStateExpirationTime: + return "FailoverStateExpirationTime" + case DHCPv6OptRelayPort: + return "RelayPort" + case DHCPv6OptV6ZeroTouchRedirect: + return "ZeroTouch" + case DHCPv6OptIPV6AddressANDSF: + return "ANDSFIPv6Address" + default: + return fmt.Sprintf("Unknown(%d)", uint16(o)) + } +} + +// DHCPv6Options is used to get nicely printed option lists which would normally +// be cut off after 5 options. +type DHCPv6Options []DHCPv6Option + +// String returns a string version of the options list. +func (o DHCPv6Options) String() string { + buf := &bytes.Buffer{} + buf.WriteByte('[') + for i, opt := range o { + buf.WriteString(opt.String()) + if i+1 != len(o) { + buf.WriteString(", ") + } + } + buf.WriteByte(']') + return buf.String() +} + +// DHCPv6Option rerpresents a DHCP option. +type DHCPv6Option struct { + Code DHCPv6Opt + Length uint16 + Data []byte +} + +// String returns a string version of a DHCP Option. +func (o DHCPv6Option) String() string { + switch o.Code { + case DHCPv6OptClientID, DHCPv6OptServerID: + duid, err := decodeDHCPv6DUID(o.Data) + if err != nil { + return fmt.Sprintf("Option(%s:INVALID)", o.Code) + } + return fmt.Sprintf("Option(%s:[%s])", o.Code, duid.String()) + case DHCPv6OptOro: + options := "" + for i := 0; i < int(o.Length); i += 2 { + if options != "" { + options += "," + } + option := DHCPv6Opt(binary.BigEndian.Uint16(o.Data[i : i+2])) + options += option.String() + } + return fmt.Sprintf("Option(%s:[%s])", o.Code, options) + default: + return fmt.Sprintf("Option(%s:%v)", o.Code, o.Data) + } +} + +// NewDHCPv6Option constructs a new DHCPv6Option with a given type and data. +func NewDHCPv6Option(code DHCPv6Opt, data []byte) DHCPv6Option { + o := DHCPv6Option{Code: code} + if data != nil { + o.Data = data + o.Length = uint16(len(data)) + } + + return o +} + +func (o *DHCPv6Option) encode(b []byte, opts gopacket.SerializeOptions) error { + binary.BigEndian.PutUint16(b[0:2], uint16(o.Code)) + if opts.FixLengths { + binary.BigEndian.PutUint16(b[2:4], uint16(len(o.Data))) + } else { + binary.BigEndian.PutUint16(b[2:4], o.Length) + } + copy(b[4:], o.Data) + + return nil +} + +func (o *DHCPv6Option) decode(data []byte) error { + if len(data) < 4 { + return errors.New("not enough data to decode") + } + o.Code = DHCPv6Opt(binary.BigEndian.Uint16(data[0:2])) + o.Length = binary.BigEndian.Uint16(data[2:4]) + if len(data) < 4+int(o.Length) { + return fmt.Errorf("dhcpv6 option size < length %d", 4+o.Length) + } + o.Data = data[4 : 4+o.Length] + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dns.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dns.go new file mode 100644 index 0000000000..6a143f752c --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dns.go @@ -0,0 +1,1465 @@ +// Copyright 2014, 2018, 2024 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. + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + "strings" + + "github.com/gopacket/gopacket" +) + +// DNSClass defines the class associated with a request/response. Different DNS +// classes can be thought of as an array of parallel namespace trees. +type DNSClass uint16 + +// DNSClass known values. +const ( + DNSClassIN DNSClass = 1 // Internet + DNSClassCS DNSClass = 2 // the CSNET class (Obsolete) + DNSClassCH DNSClass = 3 // the CHAOS class + DNSClassHS DNSClass = 4 // Hesiod [Dyer 87] + DNSClassAny DNSClass = 255 // AnyClass +) + +func (dc DNSClass) String() string { + switch dc { + default: + return "Unknown" + case DNSClassIN: + return "IN" + case DNSClassCS: + return "CS" + case DNSClassCH: + return "CH" + case DNSClassHS: + return "HS" + case DNSClassAny: + return "Any" + } +} + +// DNSType defines the type of data being requested/returned in a +// question/answer. +type DNSType uint16 + +// DNSType known values. +const ( + DNSTypeA DNSType = 1 // a host address + DNSTypeNS DNSType = 2 // an authoritative name server + DNSTypeMD DNSType = 3 // a mail destination (Obsolete - use MX) + DNSTypeMF DNSType = 4 // a mail forwarder (Obsolete - use MX) + DNSTypeCNAME DNSType = 5 // the canonical name for an alias + DNSTypeSOA DNSType = 6 // marks the start of a zone of authority + DNSTypeMB DNSType = 7 // a mailbox domain name (EXPERIMENTAL) + DNSTypeMG DNSType = 8 // a mail group member (EXPERIMENTAL) + DNSTypeMR DNSType = 9 // a mail rename domain name (EXPERIMENTAL) + DNSTypeNULL DNSType = 10 // a null RR (EXPERIMENTAL) + DNSTypeWKS DNSType = 11 // a well known service description + DNSTypePTR DNSType = 12 // a domain name pointer + DNSTypeHINFO DNSType = 13 // host information + DNSTypeMINFO DNSType = 14 // mailbox or mail list information + DNSTypeMX DNSType = 15 // mail exchange + DNSTypeTXT DNSType = 16 // text strings + DNSTypeAAAA DNSType = 28 // a IPv6 host address [RFC3596] + DNSTypeSRV DNSType = 33 // server discovery [RFC2782] [RFC6195] + DNSTypeOPT DNSType = 41 // OPT Pseudo-RR [RFC6891] + DNSTypeRRSIG DNSType = 46 // RRSIG RR [RFC4034][RFC3755] + DNSTypeDNSKEY DNSType = 48 // DNSKEY RR [RFC4034][RFC3755] + DNSTypeSVCB DNSType = 64 // SVCB DNS RR [RFC9460] + DNSTypeHTTPS DNSType = 65 // HTTPS RR [RFC9460] + DNSTypeURI DNSType = 256 // URI RR [RFC7553] +) + +func (dt DNSType) String() string { + switch dt { + default: + return "Unknown" + case DNSTypeA: + return "A" + case DNSTypeNS: + return "NS" + case DNSTypeMD: + return "MD" + case DNSTypeMF: + return "MF" + case DNSTypeCNAME: + return "CNAME" + case DNSTypeSOA: + return "SOA" + case DNSTypeMB: + return "MB" + case DNSTypeMG: + return "MG" + case DNSTypeMR: + return "MR" + case DNSTypeNULL: + return "NULL" + case DNSTypeWKS: + return "WKS" + case DNSTypePTR: + return "PTR" + case DNSTypeHINFO: + return "HINFO" + case DNSTypeMINFO: + return "MINFO" + case DNSTypeMX: + return "MX" + case DNSTypeTXT: + return "TXT" + case DNSTypeAAAA: + return "AAAA" + case DNSTypeSRV: + return "SRV" + case DNSTypeOPT: + return "OPT" + case DNSTypeRRSIG: + return "RRSIG" + case DNSTypeDNSKEY: + return "DNSKEY" + case DNSTypeSVCB: + return "SVCB" + case DNSTypeHTTPS: + return "HTTPS" + case DNSTypeURI: + return "URI" + } +} + +// DNSResponseCode provides response codes for question answers. +type DNSResponseCode uint8 + +// DNSResponseCode known values. +const ( + DNSResponseCodeNoErr DNSResponseCode = 0 // No error + DNSResponseCodeFormErr DNSResponseCode = 1 // Format Error [RFC1035] + DNSResponseCodeServFail DNSResponseCode = 2 // Server Failure [RFC1035] + DNSResponseCodeNXDomain DNSResponseCode = 3 // Non-Existent Domain [RFC1035] + DNSResponseCodeNotImp DNSResponseCode = 4 // Not Implemented [RFC1035] + DNSResponseCodeRefused DNSResponseCode = 5 // Query Refused [RFC1035] + DNSResponseCodeYXDomain DNSResponseCode = 6 // Name Exists when it should not [RFC2136] + DNSResponseCodeYXRRSet DNSResponseCode = 7 // RR Set Exists when it should not [RFC2136] + DNSResponseCodeNXRRSet DNSResponseCode = 8 // RR Set that should exist does not [RFC2136] + DNSResponseCodeNotAuth DNSResponseCode = 9 // Server Not Authoritative for zone [RFC2136] + DNSResponseCodeNotZone DNSResponseCode = 10 // Name not contained in zone [RFC2136] + DNSResponseCodeBadVers DNSResponseCode = 16 // Bad OPT Version [RFC2671] + DNSResponseCodeBadSig DNSResponseCode = 16 // TSIG Signature Failure [RFC2845] + DNSResponseCodeBadKey DNSResponseCode = 17 // Key not recognized [RFC2845] + DNSResponseCodeBadTime DNSResponseCode = 18 // Signature out of time window [RFC2845] + DNSResponseCodeBadMode DNSResponseCode = 19 // Bad TKEY Mode [RFC2930] + DNSResponseCodeBadName DNSResponseCode = 20 // Duplicate key name [RFC2930] + DNSResponseCodeBadAlg DNSResponseCode = 21 // Algorithm not supported [RFC2930] + DNSResponseCodeBadTruc DNSResponseCode = 22 // Bad Truncation [RFC4635] + DNSResponseCodeBadCookie DNSResponseCode = 23 // Bad/missing Server Cookie [RFC7873] +) + +func (drc DNSResponseCode) String() string { + switch drc { + default: + return "Unknown" + case DNSResponseCodeNoErr: + return "No Error" + case DNSResponseCodeFormErr: + return "Format Error" + case DNSResponseCodeServFail: + return "Server Failure" + case DNSResponseCodeNXDomain: + return "Non-Existent Domain" + case DNSResponseCodeNotImp: + return "Not Implemented" + case DNSResponseCodeRefused: + return "Query Refused" + case DNSResponseCodeYXDomain: + return "Name Exists when it should not" + case DNSResponseCodeYXRRSet: + return "RR Set Exists when it should not" + case DNSResponseCodeNXRRSet: + return "RR Set that should exist does not" + case DNSResponseCodeNotAuth: + return "Server Not Authoritative for zone" + case DNSResponseCodeNotZone: + return "Name not contained in zone" + case DNSResponseCodeBadVers: + return "Bad OPT Version" + case DNSResponseCodeBadKey: + return "Key not recognized" + case DNSResponseCodeBadTime: + return "Signature out of time window" + case DNSResponseCodeBadMode: + return "Bad TKEY Mode" + case DNSResponseCodeBadName: + return "Duplicate key name" + case DNSResponseCodeBadAlg: + return "Algorithm not supported" + case DNSResponseCodeBadTruc: + return "Bad Truncation" + case DNSResponseCodeBadCookie: + return "Bad Cookie" + } +} + +// DNSOpCode defines a set of different operation types. +type DNSOpCode uint8 + +// DNSOpCode known values. +const ( + DNSOpCodeQuery DNSOpCode = 0 // Query [RFC1035] + DNSOpCodeIQuery DNSOpCode = 1 // Inverse Query Obsolete [RFC3425] + DNSOpCodeStatus DNSOpCode = 2 // Status [RFC1035] + DNSOpCodeNotify DNSOpCode = 4 // Notify [RFC1996] + DNSOpCodeUpdate DNSOpCode = 5 // Update [RFC2136] +) + +func (doc DNSOpCode) String() string { + switch doc { + default: + return "Unknown" + case DNSOpCodeQuery: + return "Query" + case DNSOpCodeIQuery: + return "Inverse Query" + case DNSOpCodeStatus: + return "Status" + case DNSOpCodeNotify: + return "Notify" + case DNSOpCodeUpdate: + return "Update" + } +} + +// DNS is specified in RFC 1034 / RFC 1035 +// +---------------------+ +// | Header | +// +---------------------+ +// | Question | the question for the name server +// +---------------------+ +// | Answer | RRs answering the question +// +---------------------+ +// | Authority | RRs pointing toward an authority +// +---------------------+ +// | Additional | RRs holding additional information +// +---------------------+ +// +// DNS Header +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | ID | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | QDCOUNT | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | ANCOUNT | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | NSCOUNT | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | ARCOUNT | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// DNS contains data from a single Domain Name Service packet. +type DNS struct { + BaseLayer + + // Header fields + ID uint16 + QR bool + OpCode DNSOpCode + + AA bool // Authoritative answer + TC bool // Truncated + RD bool // Recursion desired + RA bool // Recursion available + Z uint8 // Reserved for future use + + ResponseCode DNSResponseCode + QDCount uint16 // Number of questions to expect + ANCount uint16 // Number of answers to expect + NSCount uint16 // Number of authorities to expect + ARCount uint16 // Number of additional records to expect + + // Entries + Questions []DNSQuestion + Answers []DNSResourceRecord + Authorities []DNSResourceRecord + Additionals []DNSResourceRecord + + // buffer for doing name decoding. We use a single reusable buffer to avoid + // name decoding on a single object via multiple DecodeFromBytes calls + // requiring constant allocation of small byte slices. + buffer []byte +} + +// LayerType returns gopacket.LayerTypeDNS. +func (d *DNS) LayerType() gopacket.LayerType { return LayerTypeDNS } + +// decodeDNS decodes the byte slice into a DNS type. It also +// setups the application Layer in PacketBuilder. +func decodeDNS(data []byte, p gopacket.PacketBuilder) error { + d := &DNS{} + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(d) + p.SetApplicationLayer(d) + return nil +} + +// DecodeFromBytes decodes the slice into the DNS struct. +func (d *DNS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + d.buffer = d.buffer[:0] + + if len(data) < 12 { + df.SetTruncated() + return errDNSPacketTooShort + } + + // since there are no further layers, the baselayer's content is + // pointing to this layer + d.BaseLayer = BaseLayer{Contents: data[:len(data)]} + d.ID = binary.BigEndian.Uint16(data[:2]) + d.QR = data[2]&0x80 != 0 + d.OpCode = DNSOpCode(data[2]>>3) & 0x0F + d.AA = data[2]&0x04 != 0 + d.TC = data[2]&0x02 != 0 + d.RD = data[2]&0x01 != 0 + d.RA = data[3]&0x80 != 0 + d.Z = uint8(data[3]>>4) & 0x7 + d.ResponseCode = DNSResponseCode(data[3] & 0xF) + d.QDCount = binary.BigEndian.Uint16(data[4:6]) + d.ANCount = binary.BigEndian.Uint16(data[6:8]) + d.NSCount = binary.BigEndian.Uint16(data[8:10]) + d.ARCount = binary.BigEndian.Uint16(data[10:12]) + + d.Questions = d.Questions[:0] + d.Answers = d.Answers[:0] + d.Authorities = d.Authorities[:0] + d.Additionals = d.Additionals[:0] + + offset := 12 + var err error + for i := 0; i < int(d.QDCount); i++ { + var q DNSQuestion + if offset, err = q.decode(data, offset, df, &d.buffer); err != nil { + return err + } + d.Questions = append(d.Questions, q) + } + + // For some horrible reason, if we do the obvious thing in this loop: + // var r DNSResourceRecord + // if blah := r.decode(blah); err != nil { + // return err + // } + // d.Foo = append(d.Foo, r) + // the Go compiler thinks that 'r' escapes to the heap, causing a malloc for + // every Answer, Authority, and Additional. To get around this, we do + // something really silly: we append an empty resource record to our slice, + // then use the last value in the slice to call decode. Since the value is + // already in the slice, there's no WAY it can escape... on the other hand our + // code is MUCH uglier :( + for i := 0; i < int(d.ANCount); i++ { + d.Answers = append(d.Answers, DNSResourceRecord{}) + if offset, err = d.Answers[i].decode(data, offset, df, &d.buffer); err != nil { + d.Answers = d.Answers[:i] // strip off erroneous value + return err + } + } + for i := 0; i < int(d.NSCount); i++ { + d.Authorities = append(d.Authorities, DNSResourceRecord{}) + if offset, err = d.Authorities[i].decode(data, offset, df, &d.buffer); err != nil { + d.Authorities = d.Authorities[:i] // strip off erroneous value + return err + } + } + for i := 0; i < int(d.ARCount); i++ { + d.Additionals = append(d.Additionals, DNSResourceRecord{}) + if offset, err = d.Additionals[i].decode(data, offset, df, &d.buffer); err != nil { + d.Additionals = d.Additionals[:i] // strip off erroneous value + return err + } + // extract extended RCODE from OPT RRs, RFC 6891 section 6.1.3 + if d.Additionals[i].Type == DNSTypeOPT { + d.ResponseCode = DNSResponseCode(uint8(d.ResponseCode) | uint8(d.Additionals[i].TTL>>20&0xF0)) + } + } + + if uint16(len(d.Questions)) != d.QDCount { + return errDecodeQueryBadQDCount + } else if uint16(len(d.Answers)) != d.ANCount { + return errDecodeQueryBadANCount + } else if uint16(len(d.Authorities)) != d.NSCount { + return errDecodeQueryBadNSCount + } else if uint16(len(d.Additionals)) != d.ARCount { + return errDecodeQueryBadARCount + } + return nil +} + +// CanDecode implements gopacket.DecodingLayer. +func (d *DNS) CanDecode() gopacket.LayerClass { + return LayerTypeDNS +} + +// NextLayerType implements gopacket.DecodingLayer. +func (d *DNS) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// Payload returns nil. +func (d *DNS) Payload() []byte { + return nil +} + +func b2i(b bool) int { + if b { + return 1 + } + return 0 +} + +func recSize(rr *DNSResourceRecord) int { + switch rr.Type { + case DNSTypeA: + return 4 + case DNSTypeAAAA: + return 16 + case DNSTypeNS: + return len(rr.NS) + 2 + case DNSTypeCNAME: + return len(rr.CNAME) + 2 + case DNSTypePTR: + return len(rr.PTR) + 2 + case DNSTypeSOA: + return len(rr.SOA.MName) + 2 + len(rr.SOA.RName) + 2 + 20 + case DNSTypeMX: + return 2 + len(rr.MX.Name) + 2 + case DNSTypeTXT: + l := len(rr.TXTs) + for _, txt := range rr.TXTs { + l += len(txt) + } + return l + case DNSTypeSRV: + return 6 + len(rr.SRV.Name) + 2 + case DNSTypeURI: + return 4 + len(rr.URI.Target) + case DNSTypeOPT: + l := len(rr.OPT) * 4 + for _, opt := range rr.OPT { + l += len(opt.Data) + } + return l + case DNSTypeRRSIG: + return rr.RRSIG.size() + case DNSTypeDNSKEY: + return rr.DNSKEY.size() + case DNSTypeSVCB, DNSTypeHTTPS: + return rr.SVCB.size() + } + + return 0 +} + +func computeSize(recs []DNSResourceRecord) int { + sz := 0 + for _, rr := range recs { + v := len(rr.Name) + + if v == 0 { + sz += v + 11 + } else { + sz += v + 12 + } + + sz += recSize(&rr) + } + return sz +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +func (d *DNS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + dsz := 0 + for _, q := range d.Questions { + dsz += len(q.Name) + 6 + } + dsz += computeSize(d.Answers) + dsz += computeSize(d.Authorities) + dsz += computeSize(d.Additionals) + + bytes, err := b.PrependBytes(12 + dsz) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes, d.ID) + bytes[2] = byte((b2i(d.QR) << 7) | (int(d.OpCode) << 3) | (b2i(d.AA) << 2) | (b2i(d.TC) << 1) | b2i(d.RD)) + bytes[3] = byte((b2i(d.RA) << 7) | (int(d.Z) << 4) | int(d.ResponseCode)) + + if opts.FixLengths { + d.QDCount = uint16(len(d.Questions)) + d.ANCount = uint16(len(d.Answers)) + d.NSCount = uint16(len(d.Authorities)) + d.ARCount = uint16(len(d.Additionals)) + } + binary.BigEndian.PutUint16(bytes[4:], d.QDCount) + binary.BigEndian.PutUint16(bytes[6:], d.ANCount) + binary.BigEndian.PutUint16(bytes[8:], d.NSCount) + binary.BigEndian.PutUint16(bytes[10:], d.ARCount) + + off := 12 + for _, qd := range d.Questions { + n := qd.encode(bytes, off) + off += n + } + + for i := range d.Answers { + // done this way so we can modify DNSResourceRecord to fix + // lengths if requested + qa := &d.Answers[i] + n, err := qa.encode(bytes, off, opts) + if err != nil { + return err + } + off += n + } + + for i := range d.Authorities { + qa := &d.Authorities[i] + n, err := qa.encode(bytes, off, opts) + if err != nil { + return err + } + off += n + } + for i := range d.Additionals { + qa := &d.Additionals[i] + n, err := qa.encode(bytes, off, opts) + if err != nil { + return err + } + off += n + } + + return nil +} + +const maxRecursionLevel = 255 + +func decodeName(data []byte, offset int, buffer *[]byte, level int) ([]byte, int, error) { + if level > maxRecursionLevel { + return nil, 0, errMaxRecursion + } else if offset >= len(data) { + return nil, 0, errDNSNameOffsetTooHigh + } else if offset < 0 { + return nil, 0, errDNSNameOffsetNegative + } + start := len(*buffer) + index := offset + if data[index] == 0x00 { + return nil, index + 1, nil + } +loop: + for data[index] != 0x00 { + switch data[index] & 0xc0 { + default: + /* RFC 1035 + A domain name represented as a sequence of labels, where + each label consists of a length octet followed by that + number of octets. The domain name terminates with the + zero length octet for the null label of the root. Note + that this field may be an odd number of octets; no + padding is used. + */ + index2 := index + int(data[index]) + 1 + if index2-offset > 255 { + return nil, 0, errDNSNameTooLong + } else if index2 < index+1 || index2 > len(data) { + return nil, 0, errDNSNameInvalidIndex + } + *buffer = append(*buffer, '.') + *buffer = append(*buffer, data[index+1:index2]...) + index = index2 + + case 0xc0: + /* RFC 1035 + The pointer takes the form of a two octet sequence. + + The first two bits are ones. This allows a pointer to + be distinguished from a label, since the label must + begin with two zero bits because labels are restricted + to 63 octets or less. (The 10 and 01 combinations are + reserved for future use.) The OFFSET field specifies + an offset from the start of the message (i.e., the + first octet of the ID field in the domain header). A + zero offset specifies the first byte of the ID field, + etc. + + The compression scheme allows a domain name in a message to be + represented as either: + - a sequence of labels ending in a zero octet + - a pointer + - a sequence of labels ending with a pointer + */ + if index+2 > len(data) { + return nil, 0, errDNSPointerOffsetTooHigh + } + offsetp := int(binary.BigEndian.Uint16(data[index:index+2]) & 0x3fff) + if offsetp > len(data) { + return nil, 0, errDNSPointerOffsetTooHigh + } + // This looks a little tricky, but actually isn't. Because of how + // decodeName is written, calling it appends the decoded name to the + // current buffer. We already have the start of the buffer, then, so + // once this call is done buffer[start:] will contain our full name. + _, _, err := decodeName(data, offsetp, buffer, level+1) + if err != nil { + return nil, 0, err + } + index++ // pointer is two bytes, so add an extra byte here. + break loop + /* EDNS, or other DNS option ? */ + case 0x40: // RFC 2673 + return nil, 0, fmt.Errorf("qname '0x40' - RFC 2673 unsupported yet (data=%x index=%d)", + data[index], index) + + case 0x80: + return nil, 0, fmt.Errorf("qname '0x80' unsupported yet (data=%x index=%d)", + data[index], index) + } + if index >= len(data) { + return nil, 0, errDNSIndexOutOfRange + } + } + if len(*buffer) <= start { + return (*buffer)[start:], index + 1, nil + } + return (*buffer)[start+1:], index + 1, nil +} + +// DNSQuestion wraps a single request (question) within a DNS query. +type DNSQuestion struct { + Name []byte + Type DNSType + Class DNSClass +} + +func (q *DNSQuestion) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) { + name, endq, err := decodeName(data, offset, buffer, 1) + if err != nil { + return 0, err + } + + if len(data) < endq+4 { + return 0, errors.New("DNS question too small") + } + + q.Name = name + q.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2])) + q.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4])) + + return endq + 4, nil +} + +func (q *DNSQuestion) encode(data []byte, offset int) int { + noff := encodeName(q.Name, data, offset) + nSz := noff - offset + binary.BigEndian.PutUint16(data[noff:], uint16(q.Type)) + binary.BigEndian.PutUint16(data[noff+2:], uint16(q.Class)) + return nSz + 4 +} + +// DNSResourceRecord +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | | +// / / +// / NAME / +// | | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TYPE | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | CLASS | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TTL | +// | | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | RDLENGTH | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +// / RDATA / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// DNSResourceRecord wraps the data from a single DNS resource within a +// response. +type DNSResourceRecord struct { + // Header + Name []byte + Type DNSType + Class DNSClass + TTL uint32 + + // RDATA Raw Values + DataLength uint16 + Data []byte + + // RDATA Decoded Values + IP net.IP + NS, CNAME, PTR []byte + TXTs [][]byte + SOA DNSSOA + SRV DNSSRV + MX DNSMX + OPT []DNSOPT // See RFC 6891, section 6.1.2 + RRSIG DNSRRSIG // See RFC 4034, section 3.1 + DNSKEY DNSKEY // See RFC 4034, section 2.1 + SVCB DNSSVCB // See RFC 9460, this contains both SVCB and HTTPS + URI DNSURI + + // Undecoded TXT for backward compatibility + TXT []byte +} + +// decode decodes the resource record, returning the total length of the record. +func (rr *DNSResourceRecord) decode(data []byte, offset int, df gopacket.DecodeFeedback, buffer *[]byte) (int, error) { + name, endq, err := decodeName(data, offset, buffer, 1) + if err != nil { + return 0, err + } + + if len(data) < endq+10 { + return 0, errors.New("DNS record too small") + } + + rr.Name = name + rr.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2])) + rr.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4])) + rr.TTL = binary.BigEndian.Uint32(data[endq+4 : endq+8]) + rr.DataLength = binary.BigEndian.Uint16(data[endq+8 : endq+10]) + end := endq + 10 + int(rr.DataLength) + if end > len(data) { + return 0, errDecodeRecordLength + } + rr.Data = data[endq+10 : end] + + if rr.DataLength > 0 { + if err = rr.decodeRData(data[:end], endq+10, buffer); err != nil { + return 0, err + } + } + + return endq + 10 + int(rr.DataLength), nil +} + +func encodeName(name []byte, data []byte, offset int) int { + l := 0 + for i := range name { + if name[i] == '.' { + data[offset+i-l] = byte(l) + l = 0 + } else { + // skip one to write the length + data[offset+i+1] = name[i] + l++ + } + } + + if len(name) == 0 { + data[offset] = 0x00 // terminal + return offset + 1 + } + + // length for final portion + data[offset+len(name)-l] = byte(l) + data[offset+len(name)+1] = 0x00 // terminal + return offset + len(name) + 2 +} + +func (rr *DNSResourceRecord) encode(data []byte, offset int, opts gopacket.SerializeOptions) (int, error) { + + noff := encodeName(rr.Name, data, offset) + nSz := noff - offset + + binary.BigEndian.PutUint16(data[noff:], uint16(rr.Type)) + binary.BigEndian.PutUint16(data[noff+2:], uint16(rr.Class)) + binary.BigEndian.PutUint32(data[noff+4:], uint32(rr.TTL)) + + switch rr.Type { + case DNSTypeA: + copy(data[noff+10:], rr.IP.To4()) + case DNSTypeAAAA: + copy(data[noff+10:], rr.IP) + case DNSTypeNS: + encodeName(rr.NS, data, noff+10) + case DNSTypeCNAME: + encodeName(rr.CNAME, data, noff+10) + case DNSTypePTR: + encodeName(rr.PTR, data, noff+10) + case DNSTypeSOA: + noff2 := encodeName(rr.SOA.MName, data, noff+10) + noff2 = encodeName(rr.SOA.RName, data, noff2) + binary.BigEndian.PutUint32(data[noff2:], rr.SOA.Serial) + binary.BigEndian.PutUint32(data[noff2+4:], rr.SOA.Refresh) + binary.BigEndian.PutUint32(data[noff2+8:], rr.SOA.Retry) + binary.BigEndian.PutUint32(data[noff2+12:], rr.SOA.Expire) + binary.BigEndian.PutUint32(data[noff2+16:], rr.SOA.Minimum) + case DNSTypeMX: + binary.BigEndian.PutUint16(data[noff+10:], rr.MX.Preference) + encodeName(rr.MX.Name, data, noff+12) + case DNSTypeTXT: + noff2 := noff + 10 + for _, txt := range rr.TXTs { + data[noff2] = byte(len(txt)) + copy(data[noff2+1:], txt) + noff2 += 1 + len(txt) + } + case DNSTypeSRV: + binary.BigEndian.PutUint16(data[noff+10:], rr.SRV.Priority) + binary.BigEndian.PutUint16(data[noff+12:], rr.SRV.Weight) + binary.BigEndian.PutUint16(data[noff+14:], rr.SRV.Port) + encodeName(rr.SRV.Name, data, noff+16) + case DNSTypeURI: + binary.BigEndian.PutUint16(data[noff+10:], rr.URI.Priority) + binary.BigEndian.PutUint16(data[noff+12:], rr.URI.Weight) + copy(data[noff+14:], rr.URI.Target) + case DNSTypeOPT: + noff2 := noff + 10 + for _, opt := range rr.OPT { + binary.BigEndian.PutUint16(data[noff2:], uint16(opt.Code)) + binary.BigEndian.PutUint16(data[noff2+2:], uint16(len(opt.Data))) + copy(data[noff2+4:], opt.Data) + noff2 += 4 + len(opt.Data) + } + case DNSTypeRRSIG: + rr.RRSIG.encode(data, noff+10) + case DNSTypeDNSKEY: + rr.DNSKEY.encode(data, noff+10) + case DNSTypeSVCB, DNSTypeHTTPS: + rr.SVCB.encode(data, noff+10) + default: + return 0, fmt.Errorf("serializing resource record of type %v not supported", rr.Type) + } + + // DataLength + dSz := recSize(rr) + binary.BigEndian.PutUint16(data[noff+8:], uint16(dSz)) + + if opts.FixLengths { + rr.DataLength = uint16(dSz) + } + + return nSz + 10 + dSz, nil +} + +func (rr *DNSResourceRecord) String() string { + + if rr.Type == DNSTypeOPT { + opts := make([]string, len(rr.OPT)) + for i, opt := range rr.OPT { + opts[i] = opt.String() + } + return "OPT " + strings.Join(opts, ",") + } + if rr.Type == DNSTypeURI { + return fmt.Sprintf("URI %d %d %s", rr.URI.Priority, rr.URI.Weight, string(rr.URI.Target)) + } + if rr.Class == DNSClassIN { + switch rr.Type { + case DNSTypeA, DNSTypeAAAA: + return rr.IP.String() + case DNSTypeNS: + return "NS " + string(rr.NS) + case DNSTypeCNAME: + return "CNAME " + string(rr.CNAME) + case DNSTypePTR: + return "PTR " + string(rr.PTR) + case DNSTypeTXT: + return "TXT " + string(rr.TXT) + } + } + + return fmt.Sprintf("<%v, %v>", rr.Class, rr.Type) +} + +func decodeCharacterStrings(data []byte) ([][]byte, error) { + strings := make([][]byte, 0, 1) + end := len(data) + for index, index2 := 0, 0; index != end; index = index2 { + index2 = index + 1 + int(data[index]) // index increases by 1..256 and does not overflow + if index2 > end { + return nil, errCharStringMissData + } + strings = append(strings, data[index+1:index2]) + } + return strings, nil +} + +func decodeOPTs(data []byte, offset int) ([]DNSOPT, error) { + allOPT := []DNSOPT{} + end := len(data) + + if offset == end { + return allOPT, nil // There is no data to read + } + + if offset+4 > end { + return allOPT, fmt.Errorf("DNSOPT record is of length %d, it should be at least length 4", end-offset) + } + + for i := offset; i < end; { + opt := DNSOPT{} + if len(data) < i+4 { + return allOPT, fmt.Errorf("Malformed DNSOPT record. Length %d < %d", len(data), i+4) + } + opt.Code = DNSOptionCode(binary.BigEndian.Uint16(data[i : i+2])) + l := binary.BigEndian.Uint16(data[i+2 : i+4]) + if i+4+int(l) > end { + return allOPT, fmt.Errorf("Malformed DNSOPT record. The length (%d) field implies a packet larger than the one received", l) + } + opt.Data = data[i+4 : i+4+int(l)] + allOPT = append(allOPT, opt) + i += int(l) + 4 + } + return allOPT, nil +} + +func decodeSVCB(data []byte, offset int, buffer *[]byte) (DNSSVCB, error) { + var svcb DNSSVCB + end := len(data) + + if offset == end { + return svcb, fmt.Errorf("DNSSVCB record is empty") + } + + if offset+3 > end { + return svcb, fmt.Errorf("DNSSVCB record is of length %d, it should be at least length 3", end-offset) + } + priority := binary.BigEndian.Uint16(data[offset:]) + target, ofs, err := decodeName(data, offset+2, buffer, 1) + if err != nil { + return svcb, err + } + + var params []DNSSvcParam + for ofs < end { + if offset+4 > end { + return svcb, fmt.Errorf("DNSSVCB record truncated in SvcParams") + } + key := DNSSvcParamKey(binary.BigEndian.Uint16(data[ofs:])) + l := int(binary.BigEndian.Uint16(data[ofs+2:])) + if ofs+4+l > end { + return svcb, fmt.Errorf("DNSSVCB record truncated in SvcParams") + } + params = append(params, DNSSvcParam{ + Key: key, + Value: data[ofs+4 : ofs+4+l], + }) + ofs += 4 + l + } + + return DNSSVCB{ + Priority: priority, + Target: target, + Params: params, + }, nil +} + +func (rr *DNSResourceRecord) decodeRData(data []byte, offset int, buffer *[]byte) error { + switch rr.Type { + case DNSTypeA: + rr.IP = rr.Data + case DNSTypeAAAA: + rr.IP = rr.Data + case DNSTypeTXT, DNSTypeHINFO: + rr.TXT = rr.Data + txts, err := decodeCharacterStrings(rr.Data) + if err != nil { + return err + } + rr.TXTs = txts + case DNSTypeNS: + name, _, err := decodeName(data, offset, buffer, 1) + if err != nil { + return err + } + rr.NS = name + case DNSTypeCNAME: + name, _, err := decodeName(data, offset, buffer, 1) + if err != nil { + return err + } + rr.CNAME = name + case DNSTypePTR: + name, _, err := decodeName(data, offset, buffer, 1) + if err != nil { + return err + } + rr.PTR = name + case DNSTypeSOA: + name, endq, err := decodeName(data, offset, buffer, 1) + if err != nil { + return err + } + rr.SOA.MName = name + name, endq, err = decodeName(data, endq, buffer, 1) + if err != nil { + return err + } + if len(data) < endq+20 { + return errors.New("SOA too small") + } + rr.SOA.RName = name + rr.SOA.Serial = binary.BigEndian.Uint32(data[endq : endq+4]) + rr.SOA.Refresh = binary.BigEndian.Uint32(data[endq+4 : endq+8]) + rr.SOA.Retry = binary.BigEndian.Uint32(data[endq+8 : endq+12]) + rr.SOA.Expire = binary.BigEndian.Uint32(data[endq+12 : endq+16]) + rr.SOA.Minimum = binary.BigEndian.Uint32(data[endq+16 : endq+20]) + case DNSTypeMX: + if len(data) < offset+2 { + return errors.New("MX too small") + } + rr.MX.Preference = binary.BigEndian.Uint16(data[offset : offset+2]) + name, _, err := decodeName(data, offset+2, buffer, 1) + if err != nil { + return err + } + rr.MX.Name = name + case DNSTypeURI: + if len(rr.Data) < 4 { + return errors.New("URI too small") + } + rr.URI.Priority = binary.BigEndian.Uint16(data[offset : offset+2]) + rr.URI.Weight = binary.BigEndian.Uint16(data[offset+2 : offset+4]) + rr.URI.Target = rr.Data[4:] + case DNSTypeSRV: + if len(data) < offset+6 { + return errors.New("SRV too small") + } + rr.SRV.Priority = binary.BigEndian.Uint16(data[offset : offset+2]) + rr.SRV.Weight = binary.BigEndian.Uint16(data[offset+2 : offset+4]) + rr.SRV.Port = binary.BigEndian.Uint16(data[offset+4 : offset+6]) + name, _, err := decodeName(data, offset+6, buffer, 1) + if err != nil { + return err + } + rr.SRV.Name = name + case DNSTypeOPT: + allOPT, err := decodeOPTs(data, offset) + if err != nil { + return err + } + rr.OPT = allOPT + case DNSTypeRRSIG: + err := rr.RRSIG.decode(data, offset) + if err != nil { + return err + } + case DNSTypeDNSKEY: + err := rr.DNSKEY.decode(data, offset) + if err != nil { + return err + } + case DNSTypeSVCB, DNSTypeHTTPS: + svcb, err := decodeSVCB(data, offset, buffer) + if err != nil { + return err + } + rr.SVCB = svcb + } + return nil +} + +// DNSSOA is a Start of Authority record. Each domain requires a SOA record at +// the cutover where a domain is delegated from its parent. +type DNSSOA struct { + MName, RName []byte + Serial, Refresh, Retry, Expire, Minimum uint32 +} + +// DNSSRV is a Service record, defining a location (hostname/port) of a +// server/service. +type DNSSRV struct { + Priority, Weight, Port uint16 + Name []byte +} + +// DNSMX is a mail exchange record, defining a mail server for a recipient's +// domain. +type DNSMX struct { + Preference uint16 + Name []byte +} + +// DNSSVCB resource record is used to facilitate the lookup of +// information needed to make connections to network services, such as +// for HTTP origins. +type DNSSVCB struct { + Priority uint16 + Target []byte + Params []DNSSvcParam +} + +func (svcb DNSSVCB) size() int { + // Target. + sz := len(svcb.Target) + if sz == 0 { + sz++ + } else { + sz += 2 + } + // Priority. + sz += 2 + + // Params. + for _, param := range svcb.Params { + sz += param.size() + } + return sz +} + +func (svcb DNSSVCB) String() string { + return fmt.Sprintf("%v [%s] %v", + svcb.Priority, string(svcb.Target), svcb.Params) +} + +func (svcb DNSSVCB) encode(data []byte, offset int) { + binary.BigEndian.PutUint16(data[offset:], svcb.Priority) + offset = encodeName(svcb.Target, data, offset+2) + + for _, param := range svcb.Params { + offset = param.encode(data, offset) + } +} + +// DNSSvcParamKey defines SVCB service parameter keys. +type DNSSvcParamKey uint16 + +func (key DNSSvcParamKey) String() string { + switch key { + default: + return "Unknown" + case DNSSvcParamKeyMandatory: + return "mandatory" + case DNSSvcParamKeyAlpn: + return "alpn" + case DNSSvcParamKeyNoDefaultAlpn: + return "no-default-alpn" + case DNSSvcParamKeyPort: + return "port" + case DNSSvcParamKeyIPv4Hint: + return "ipv4hint" + case DNSSvcParamKeyECH: + return "ech" + case DNSSvcParamKeyIPv6Hint: + return "ipv6hint" + case DNSSvcParamKeyDoHPath: + return "dohpath" + case DNSSvcParamKeyOHTTP: + return "ohttp" + case DNSSvcParamKeyDoHURI: + return "dohuri" + case DNSSvcParamKeyInvalidKey: + return "Invalid key" + } +} + +// DNSSvcParamKey known values. +const ( + DNSSvcParamKeyMandatory DNSSvcParamKey = 0 // RFC9460, Section 8 + DNSSvcParamKeyAlpn DNSSvcParamKey = 1 // RFC9460, Section 7.1 + DNSSvcParamKeyNoDefaultAlpn DNSSvcParamKey = 2 // RFC9460, Section 7.1 + DNSSvcParamKeyPort DNSSvcParamKey = 3 // RFC9460, Section 7.2 + DNSSvcParamKeyIPv4Hint DNSSvcParamKey = 4 // RFC9460, Section 7.3 + DNSSvcParamKeyECH DNSSvcParamKey = 5 // RFC9460 + DNSSvcParamKeyIPv6Hint DNSSvcParamKey = 6 // RFC9460, Section 7.3 + DNSSvcParamKeyDoHPath DNSSvcParamKey = 7 // RFC9461 + DNSSvcParamKeyOHTTP DNSSvcParamKey = 8 // RFC9540, Section 4 + DNSSvcParamKeyDoHURI DNSSvcParamKey = 32768 // draft-pauly-add-resolver-discovery-00.html + DNSSvcParamKeyInvalidKey DNSSvcParamKey = 65535 // RFC9460 +) + +// DNSSvcParam is a service param, see RFC9460, section 2.2. +type DNSSvcParam struct { + Key DNSSvcParamKey + Value []byte +} + +func (param DNSSvcParam) size() int { + return 2 + 2 + len(param.Value) +} + +func (param DNSSvcParam) encode(data []byte, offset int) int { + binary.BigEndian.PutUint16(data[offset:], uint16(param.Key)) + offset += 2 + binary.BigEndian.PutUint16(data[offset:], uint16(len(param.Value))) + offset += 2 + copy(data[offset:], param.Value) + offset += len(param.Value) + + return offset +} + +func (param DNSSvcParam) String() string { + return fmt.Sprintf("%s=%x", param.Key, param.Value) +} + +// DNSRRSIG is a DNS RRSIG record, see RFC 4034, section 3.1 +type DNSRRSIG struct { + TypeCovered DNSType + Algorithm DNSSECAlgorithm + Labels uint8 + OriginalTTL, Expiration, Inception uint32 + KeyTag uint16 + SignerName, Signature []byte +} + +func (rrsig DNSRRSIG) size() int { + // 18 bytes for the fixed fields, 2 bytes for the first Label Length, and ending 0x00 byte. + return 18 + len(rrsig.SignerName) + 2 + len(rrsig.Signature) +} + +func (rrsig DNSRRSIG) String() string { + return fmt.Sprintf("RRSIG %d %d %d %d %d %d %d %v %v", + rrsig.TypeCovered, rrsig.Algorithm, rrsig.Labels, rrsig.OriginalTTL, + rrsig.Expiration, rrsig.Inception, rrsig.KeyTag, rrsig.SignerName, rrsig.Signature) +} + +// RRSIG RDATA Wire Format +// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type Covered | Algorithm | Labels | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Original TTL | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Signature Expiration | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Signature Inception | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Key Tag | / +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Signer’s Name / +// / / +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// / / +// / Signature / +// / / +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +func (rrsig *DNSRRSIG) decode(data []byte, offset int) error { + if len(data) < offset+18 { + return errors.New("RRSIG too small") + } + var err error + rrsig.TypeCovered = DNSType(binary.BigEndian.Uint16(data[offset:])) + rrsig.Algorithm = DNSSECAlgorithm(data[offset+2]) + rrsig.Labels = data[offset+3] + rrsig.OriginalTTL = binary.BigEndian.Uint32(data[offset+4:]) + rrsig.Expiration = binary.BigEndian.Uint32(data[offset+8:]) + rrsig.Inception = binary.BigEndian.Uint32(data[offset+12:]) + rrsig.KeyTag = binary.BigEndian.Uint16(data[offset+16:]) + _, offset, err = decodeName(data, offset+18, &rrsig.SignerName, 1) + if len(rrsig.SignerName) > 1 { + rrsig.SignerName = rrsig.SignerName[1:] // Remove leading '.' + } + if err != nil { + return err + } + rrsig.Signature = data[offset:] + return nil +} + +func (rrsig DNSRRSIG) encode(data []byte, offset int) { + binary.BigEndian.PutUint16(data[offset:], uint16(rrsig.TypeCovered)) + data[offset+2] = uint8(rrsig.Algorithm) + data[offset+3] = rrsig.Labels + binary.BigEndian.PutUint32(data[offset+4:], rrsig.OriginalTTL) + binary.BigEndian.PutUint32(data[offset+8:], rrsig.Expiration) + binary.BigEndian.PutUint32(data[offset+12:], rrsig.Inception) + binary.BigEndian.PutUint16(data[offset+16:], rrsig.KeyTag) + offset += encodeName(rrsig.SignerName, data[offset+18:], 0) + 18 + copy(data[offset:], rrsig.Signature) +} + +// DNSSECAlgorithm common values +const ( + DNSSECAlgorithmRSAMD5 DNSSECAlgorithm = 1 + DNSSECAlgorithmDH DNSSECAlgorithm = 3 + DNSSECAlgorithmDSASHA1 DNSSECAlgorithm = 3 + DNSSECAlgorithmECC DNSSECAlgorithm = 4 + DNSSECAlgorithmRSASHA1 DNSSECAlgorithm = 5 + DNSSECAlgorithmDSASHA1NSEC3 DNSSECAlgorithm = 6 + DNSSECAlgorithmRSASHA1NSEC3 DNSSECAlgorithm = 7 + DNSSECAlgorithmRSASHA256 DNSSECAlgorithm = 8 + DNSSECAlgorithmRSASHA512 DNSSECAlgorithm = 10 + DNSSECAlgorithmECCGOST DNSSECAlgorithm = 12 + DNSSECAlgorithmECDSAP256SHA256 DNSSECAlgorithm = 13 + DNSSECAlgorithmECDSAP384SHA384 DNSSECAlgorithm = 14 + DNSSECAlgorithmED25519 DNSSECAlgorithm = 15 + DNSSECAlgorithmED448 DNSSECAlgorithm = 16 +) + +// DNSSECAlgorithm represents the algorithm used in a DNSSEC record, see RFC 4034, section 5.1 +type DNSSECAlgorithm uint8 + +// DNSKEY is a DNSKEY record, see RFC 4034, section 2.1 +type DNSKEY struct { + Flags DNSKEYFlag + Protocol DNSKEYProtocol + Algorithm DNSSECAlgorithm + PublicKey []byte +} + +func (dnskey DNSKEY) size() int { + return 4 + len(dnskey.PublicKey) +} + +func (dnskey DNSKEY) String() string { + return fmt.Sprintf("DNSKEY %d %d %d %v", + dnskey.Flags, dnskey.Protocol, dnskey.Algorithm, dnskey.PublicKey) +} + +// DNSKEY RDATA Wire Format +// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Flags | Protocol | Algorithm | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// / / +// / Public Key / +// / / +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +func (dnskey *DNSKEY) decode(data []byte, offset int) error { + if len(data) < offset+4 { + return errors.New("DNSKEY too small") + } + dnskey.Flags = DNSKEYFlag(binary.BigEndian.Uint16(data[offset:])) + dnskey.Protocol = DNSKEYProtocol(data[offset+2]) + dnskey.Algorithm = DNSSECAlgorithm(data[offset+3]) + dnskey.PublicKey = data[offset+4:] + return nil +} + +func (dnskey DNSKEY) encode(data []byte, offset int) { + binary.BigEndian.PutUint16(data[offset:], uint16(dnskey.Flags)) + data[offset+2] = uint8(dnskey.Protocol) + data[offset+3] = uint8(dnskey.Algorithm) + copy(data[offset+4:], dnskey.PublicKey) +} + +// DNSKEYFlag common values +const ( + DNSKEYFlagOtherKey DNSKEYFlag = 0 + DNSKEYFlagZoneKey DNSKEYFlag = 256 + DNSKEYFlagSecureEntryPoint DNSKEYFlag = 257 +) + +// DNSKEYFlag represents the key type of a DNSKEY record, see RFC 4034, section 2.1.1 +type DNSKEYFlag uint16 + +// DNSKEYProtocol common values, see RFC 4034, section 2.1.2 +const ( + DNSKEYProtocolReserved DNSKEYProtocol = 0 + DNSKEYProtocolValue DNSKEYProtocol = 3 +) + +type DNSKEYProtocol uint8 + +// DNSURI is a URI record, defining a target (URI) of a server/service +type DNSURI struct { + Priority, Weight uint16 + Target []byte +} + +// DNSOptionCode represents the code of a DNS Option, see RFC6891, section 6.1.2 +type DNSOptionCode uint16 + +func (doc DNSOptionCode) String() string { + switch doc { + default: + return "Unknown" + case DNSOptionCodeNSID: + return "NSID" + case DNSOptionCodeDAU: + return "DAU" + case DNSOptionCodeDHU: + return "DHU" + case DNSOptionCodeN3U: + return "N3U" + case DNSOptionCodeEDNSClientSubnet: + return "EDNSClientSubnet" + case DNSOptionCodeEDNSExpire: + return "EDNSExpire" + case DNSOptionCodeCookie: + return "Cookie" + case DNSOptionCodeEDNSKeepAlive: + return "EDNSKeepAlive" + case DNSOptionCodePadding: + return "CodePadding" + case DNSOptionCodeChain: + return "CodeChain" + case DNSOptionCodeEDNSKeyTag: + return "CodeEDNSKeyTag" + case DNSOptionCodeEDNSClientTag: + return "EDNSClientTag" + case DNSOptionCodeEDNSServerTag: + return "EDNSServerTag" + case DNSOptionCodeDeviceID: + return "DeviceID" + } +} + +// DNSOptionCode known values. See IANA +const ( + DNSOptionCodeNSID DNSOptionCode = 3 + DNSOptionCodeDAU DNSOptionCode = 5 + DNSOptionCodeDHU DNSOptionCode = 6 + DNSOptionCodeN3U DNSOptionCode = 7 + DNSOptionCodeEDNSClientSubnet DNSOptionCode = 8 + DNSOptionCodeEDNSExpire DNSOptionCode = 9 + DNSOptionCodeCookie DNSOptionCode = 10 + DNSOptionCodeEDNSKeepAlive DNSOptionCode = 11 + DNSOptionCodePadding DNSOptionCode = 12 + DNSOptionCodeChain DNSOptionCode = 13 + DNSOptionCodeEDNSKeyTag DNSOptionCode = 14 + DNSOptionCodeEDNSClientTag DNSOptionCode = 16 + DNSOptionCodeEDNSServerTag DNSOptionCode = 17 + DNSOptionCodeDeviceID DNSOptionCode = 26946 +) + +// DNSOPT is a DNS Option, see RFC6891, section 6.1.2 +type DNSOPT struct { + Code DNSOptionCode + Data []byte +} + +func (opt DNSOPT) String() string { + return fmt.Sprintf("%s=%x", opt.Code, opt.Data) +} + +var ( + errMaxRecursion = errors.New("max DNS recursion level hit") + + errDNSNameOffsetTooHigh = errors.New("dns name offset too high") + errDNSNameOffsetNegative = errors.New("dns name offset is negative") + errDNSPacketTooShort = errors.New("DNS packet too short") + errDNSNameTooLong = errors.New("dns name is too long") + errDNSNameInvalidIndex = errors.New("dns name uncomputable: invalid index") + errDNSPointerOffsetTooHigh = errors.New("dns offset pointer too high") + errDNSIndexOutOfRange = errors.New("dns index walked out of range") + errDNSNameHasNoData = errors.New("no dns data found for name") + + errCharStringMissData = errors.New("Insufficient data for a ") + + errDecodeRecordLength = errors.New("resource record length exceeds data") + + errDecodeQueryBadQDCount = errors.New("Invalid query decoding, not the right number of questions") + errDecodeQueryBadANCount = errors.New("Invalid query decoding, not the right number of answers") + errDecodeQueryBadNSCount = errors.New("Invalid query decoding, not the right number of authorities") + errDecodeQueryBadARCount = errors.New("Invalid query decoding, not the right number of additionals info") +) diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/doc.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/doc.go new file mode 100644 index 0000000000..846ace9049 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/doc.go @@ -0,0 +1,61 @@ +// 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 layers provides decoding layers for many common protocols. + +The layers package contains decode implementations for a number of different +types of packet layers. Users of gopacket will almost always want to also use +layers to actually decode packet data into useful pieces. To see the set of +protocols that gopacket/layers is currently able to decode, +look at the set of LayerTypes defined in the Variables sections. The +layers package also defines endpoints for many of the common packet layers +that have source/destination addresses associated with them, for example IPv4/6 +(IPs) and TCP/UDP (ports). +Finally, layers contains a number of useful enumerations (IPProtocol, +EthernetType, LinkType, PPPType, etc...). Many of these implement the +gopacket.Decoder interface, so they can be passed into gopacket as decoders. + +Most common protocol layers are named using acronyms or other industry-common +names (IPv4, TCP, PPP). Some of the less common ones have their names expanded +(CiscoDiscoveryProtocol). +For certain protocols, sub-parts of the protocol are split out into their own +layers (SCTP, for example). This is done mostly in cases where portions of the +protocol may fulfill the capabilities of interesting layers (SCTPData implements +ApplicationLayer, while base SCTP implements TransportLayer), or possibly +because splitting a protocol into a few layers makes decoding easier. + +This package is meant to be used with its parent, +http://github.com/gopacket/gopacket. + +# Port Types + +Instead of using raw uint16 or uint8 values for ports, we use a different port +type for every protocol, for example TCPPort and UDPPort. This allows us to +override string behavior for each port, which we do by setting up port name +maps (TCPPortNames, UDPPortNames, etc...). Well-known ports are annotated with +their protocol names, and their String function displays these names: + + p := TCPPort(80) + fmt.Printf("Number: %d String: %v", p, p) + // Prints: "Number: 80 String: 80(http)" + +# Modifying Decode Behavior + +layers links together decoding through its enumerations. For example, after +decoding layer type Ethernet, it uses Ethernet.EthernetType as its next decoder. +All enumerations that act as decoders, like EthernetType, can be modified by +users depending on their preferences. For example, if you have a spiffy new +IPv4 decoder that works way better than the one built into layers, you can do +this: + + var mySpiffyIPv4Decoder gopacket.Decoder = ... + layers.EthernetTypeMetadata[EthernetTypeIPv4].DecodeWith = mySpiffyIPv4Decoder + +This will make all future ethernet packets use your new decoder to decode IPv4 +packets, instead of the built-in decoder used by gopacket. +*/ +package layers diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot11.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot11.go new file mode 100644 index 0000000000..0f92748d00 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot11.go @@ -0,0 +1,2278 @@ +// Copyright 2014 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. + +// See http://standards.ieee.org/findstds/standard/802.11-2012.html for info on +// all of the layers in this file. + +package layers + +import ( + "bytes" + "encoding/binary" + "fmt" + "hash/crc32" + "net" + + "github.com/gopacket/gopacket" +) + +// Dot11Flags contains the set of 8 flags in the IEEE 802.11 frame control +// header, all in one place. +type Dot11Flags uint8 + +const ( + Dot11FlagsToDS Dot11Flags = 1 << iota + Dot11FlagsFromDS + Dot11FlagsMF + Dot11FlagsRetry + Dot11FlagsPowerManagement + Dot11FlagsMD + Dot11FlagsWEP + Dot11FlagsOrder +) + +func (d Dot11Flags) ToDS() bool { + return d&Dot11FlagsToDS != 0 +} +func (d Dot11Flags) FromDS() bool { + return d&Dot11FlagsFromDS != 0 +} +func (d Dot11Flags) MF() bool { + return d&Dot11FlagsMF != 0 +} +func (d Dot11Flags) Retry() bool { + return d&Dot11FlagsRetry != 0 +} +func (d Dot11Flags) PowerManagement() bool { + return d&Dot11FlagsPowerManagement != 0 +} +func (d Dot11Flags) MD() bool { + return d&Dot11FlagsMD != 0 +} +func (d Dot11Flags) WEP() bool { + return d&Dot11FlagsWEP != 0 +} +func (d Dot11Flags) Order() bool { + return d&Dot11FlagsOrder != 0 +} + +// String provides a human readable string for Dot11Flags. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11Flags value, not its string. +func (a Dot11Flags) String() string { + var out bytes.Buffer + if a.ToDS() { + out.WriteString("TO-DS,") + } + if a.FromDS() { + out.WriteString("FROM-DS,") + } + if a.MF() { + out.WriteString("MF,") + } + if a.Retry() { + out.WriteString("Retry,") + } + if a.PowerManagement() { + out.WriteString("PowerManagement,") + } + if a.MD() { + out.WriteString("MD,") + } + if a.WEP() { + out.WriteString("WEP,") + } + if a.Order() { + out.WriteString("Order,") + } + + if length := out.Len(); length > 0 { + return string(out.Bytes()[:length-1]) // strip final comma + } + return "" +} + +type Dot11Reason uint16 + +// TODO: Verify these reasons, and append more reasons if necessary. + +const ( + Dot11ReasonReserved Dot11Reason = 1 + Dot11ReasonUnspecified Dot11Reason = 2 + Dot11ReasonAuthExpired Dot11Reason = 3 + Dot11ReasonDeauthStLeaving Dot11Reason = 4 + Dot11ReasonInactivity Dot11Reason = 5 + Dot11ReasonApFull Dot11Reason = 6 + Dot11ReasonClass2FromNonAuth Dot11Reason = 7 + Dot11ReasonClass3FromNonAss Dot11Reason = 8 + Dot11ReasonDisasStLeaving Dot11Reason = 9 + Dot11ReasonStNotAuth Dot11Reason = 10 +) + +// String provides a human readable string for Dot11Reason. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11Reason value, not its string. +func (a Dot11Reason) String() string { + switch a { + case Dot11ReasonReserved: + return "Reserved" + case Dot11ReasonUnspecified: + return "Unspecified" + case Dot11ReasonAuthExpired: + return "Auth. expired" + case Dot11ReasonDeauthStLeaving: + return "Deauth. st. leaving" + case Dot11ReasonInactivity: + return "Inactivity" + case Dot11ReasonApFull: + return "Ap. full" + case Dot11ReasonClass2FromNonAuth: + return "Class2 from non auth." + case Dot11ReasonClass3FromNonAss: + return "Class3 from non ass." + case Dot11ReasonDisasStLeaving: + return "Disass st. leaving" + case Dot11ReasonStNotAuth: + return "St. not auth." + default: + return "Unknown reason" + } +} + +type Dot11Status uint16 + +const ( + Dot11StatusSuccess Dot11Status = 0 + Dot11StatusFailure Dot11Status = 1 // Unspecified failure + Dot11StatusCannotSupportAllCapabilities Dot11Status = 10 // Cannot support all requested capabilities in the Capability Information field + Dot11StatusInabilityExistsAssociation Dot11Status = 11 // Reassociation denied due to inability to confirm that association exists + Dot11StatusAssociationDenied Dot11Status = 12 // Association denied due to reason outside the scope of this standard + Dot11StatusAlgorithmUnsupported Dot11Status = 13 // Responding station does not support the specified authentication algorithm + Dot11StatusOufOfExpectedSequence Dot11Status = 14 // Received an Authentication frame with authentication transaction sequence number out of expected sequence + Dot11StatusChallengeFailure Dot11Status = 15 // Authentication rejected because of challenge failure + Dot11StatusTimeout Dot11Status = 16 // Authentication rejected due to timeout waiting for next frame in sequence + Dot11StatusAPUnableToHandle Dot11Status = 17 // Association denied because AP is unable to handle additional associated stations + Dot11StatusRateUnsupported Dot11Status = 18 // Association denied due to requesting station not supporting all of the data rates in the BSSBasicRateSet parameter +) + +// String provides a human readable string for Dot11Status. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11Status value, not its string. +func (a Dot11Status) String() string { + switch a { + case Dot11StatusSuccess: + return "success" + case Dot11StatusFailure: + return "failure" + case Dot11StatusCannotSupportAllCapabilities: + return "cannot-support-all-capabilities" + case Dot11StatusInabilityExistsAssociation: + return "inability-exists-association" + case Dot11StatusAssociationDenied: + return "association-denied" + case Dot11StatusAlgorithmUnsupported: + return "algorithm-unsupported" + case Dot11StatusOufOfExpectedSequence: + return "out-of-expected-sequence" + case Dot11StatusChallengeFailure: + return "challenge-failure" + case Dot11StatusTimeout: + return "timeout" + case Dot11StatusAPUnableToHandle: + return "ap-unable-to-handle" + case Dot11StatusRateUnsupported: + return "rate-unsupported" + default: + return "unknown status" + } +} + +type Dot11AckPolicy uint8 + +const ( + Dot11AckPolicyNormal Dot11AckPolicy = 0 + Dot11AckPolicyNone Dot11AckPolicy = 1 + Dot11AckPolicyNoExplicit Dot11AckPolicy = 2 + Dot11AckPolicyBlock Dot11AckPolicy = 3 +) + +// String provides a human readable string for Dot11AckPolicy. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11AckPolicy value, not its string. +func (a Dot11AckPolicy) String() string { + switch a { + case Dot11AckPolicyNormal: + return "normal-ack" + case Dot11AckPolicyNone: + return "no-ack" + case Dot11AckPolicyNoExplicit: + return "no-explicit-ack" + case Dot11AckPolicyBlock: + return "block-ack" + default: + return "unknown-ack-policy" + } +} + +type Dot11Algorithm uint16 + +const ( + Dot11AlgorithmOpen Dot11Algorithm = 0 + Dot11AlgorithmSharedKey Dot11Algorithm = 1 +) + +// String provides a human readable string for Dot11Algorithm. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11Algorithm value, not its string. +func (a Dot11Algorithm) String() string { + switch a { + case Dot11AlgorithmOpen: + return "open" + case Dot11AlgorithmSharedKey: + return "shared-key" + default: + return "unknown-algorithm" + } +} + +type Dot11InformationElementID uint8 + +const ( + Dot11InformationElementIDSSID Dot11InformationElementID = 0 + Dot11InformationElementIDRates Dot11InformationElementID = 1 + Dot11InformationElementIDFHSet Dot11InformationElementID = 2 + Dot11InformationElementIDDSSet Dot11InformationElementID = 3 + Dot11InformationElementIDCFSet Dot11InformationElementID = 4 + Dot11InformationElementIDTIM Dot11InformationElementID = 5 + Dot11InformationElementIDIBSSSet Dot11InformationElementID = 6 + Dot11InformationElementIDCountryInfo Dot11InformationElementID = 7 + Dot11InformationElementIDHoppingPatternParam Dot11InformationElementID = 8 + Dot11InformationElementIDHoppingPatternTable Dot11InformationElementID = 9 + Dot11InformationElementIDRequest Dot11InformationElementID = 10 + Dot11InformationElementIDQBSSLoadElem Dot11InformationElementID = 11 + Dot11InformationElementIDEDCAParamSet Dot11InformationElementID = 12 + Dot11InformationElementIDTrafficSpec Dot11InformationElementID = 13 + Dot11InformationElementIDTrafficClass Dot11InformationElementID = 14 + Dot11InformationElementIDSchedule Dot11InformationElementID = 15 + Dot11InformationElementIDChallenge Dot11InformationElementID = 16 + Dot11InformationElementIDPowerConst Dot11InformationElementID = 32 + Dot11InformationElementIDPowerCapability Dot11InformationElementID = 33 + Dot11InformationElementIDTPCRequest Dot11InformationElementID = 34 + Dot11InformationElementIDTPCReport Dot11InformationElementID = 35 + Dot11InformationElementIDSupportedChannels Dot11InformationElementID = 36 + Dot11InformationElementIDSwitchChannelAnnounce Dot11InformationElementID = 37 + Dot11InformationElementIDMeasureRequest Dot11InformationElementID = 38 + Dot11InformationElementIDMeasureReport Dot11InformationElementID = 39 + Dot11InformationElementIDQuiet Dot11InformationElementID = 40 + Dot11InformationElementIDIBSSDFS Dot11InformationElementID = 41 + Dot11InformationElementIDERPInfo Dot11InformationElementID = 42 + Dot11InformationElementIDTSDelay Dot11InformationElementID = 43 + Dot11InformationElementIDTCLASProcessing Dot11InformationElementID = 44 + Dot11InformationElementIDHTCapabilities Dot11InformationElementID = 45 + Dot11InformationElementIDQOSCapability Dot11InformationElementID = 46 + Dot11InformationElementIDERPInfo2 Dot11InformationElementID = 47 + Dot11InformationElementIDRSNInfo Dot11InformationElementID = 48 + Dot11InformationElementIDESRates Dot11InformationElementID = 50 + Dot11InformationElementIDAPChannelReport Dot11InformationElementID = 51 + Dot11InformationElementIDNeighborReport Dot11InformationElementID = 52 + Dot11InformationElementIDRCPI Dot11InformationElementID = 53 + Dot11InformationElementIDMobilityDomain Dot11InformationElementID = 54 + Dot11InformationElementIDFastBSSTrans Dot11InformationElementID = 55 + Dot11InformationElementIDTimeoutInt Dot11InformationElementID = 56 + Dot11InformationElementIDRICData Dot11InformationElementID = 57 + Dot11InformationElementIDDSERegisteredLoc Dot11InformationElementID = 58 + Dot11InformationElementIDSuppOperatingClass Dot11InformationElementID = 59 + Dot11InformationElementIDExtChanSwitchAnnounce Dot11InformationElementID = 60 + Dot11InformationElementIDHTInfo Dot11InformationElementID = 61 + Dot11InformationElementIDSecChanOffset Dot11InformationElementID = 62 + Dot11InformationElementIDBSSAverageAccessDelay Dot11InformationElementID = 63 + Dot11InformationElementIDAntenna Dot11InformationElementID = 64 + Dot11InformationElementIDRSNI Dot11InformationElementID = 65 + Dot11InformationElementIDMeasurePilotTrans Dot11InformationElementID = 66 + Dot11InformationElementIDBSSAvailAdmCapacity Dot11InformationElementID = 67 + Dot11InformationElementIDBSSACAccDelayWAPIParam Dot11InformationElementID = 68 + Dot11InformationElementIDTimeAdvertisement Dot11InformationElementID = 69 + Dot11InformationElementIDRMEnabledCapabilities Dot11InformationElementID = 70 + Dot11InformationElementIDMultipleBSSID Dot11InformationElementID = 71 + Dot11InformationElementID2040BSSCoExist Dot11InformationElementID = 72 + Dot11InformationElementID2040BSSIntChanReport Dot11InformationElementID = 73 + Dot11InformationElementIDOverlapBSSScanParam Dot11InformationElementID = 74 + Dot11InformationElementIDRICDescriptor Dot11InformationElementID = 75 + Dot11InformationElementIDManagementMIC Dot11InformationElementID = 76 + Dot11InformationElementIDEventRequest Dot11InformationElementID = 78 + Dot11InformationElementIDEventReport Dot11InformationElementID = 79 + Dot11InformationElementIDDiagnosticRequest Dot11InformationElementID = 80 + Dot11InformationElementIDDiagnosticReport Dot11InformationElementID = 81 + Dot11InformationElementIDLocationParam Dot11InformationElementID = 82 + Dot11InformationElementIDNonTransBSSIDCapability Dot11InformationElementID = 83 + Dot11InformationElementIDSSIDList Dot11InformationElementID = 84 + Dot11InformationElementIDMultipleBSSIDIndex Dot11InformationElementID = 85 + Dot11InformationElementIDFMSDescriptor Dot11InformationElementID = 86 + Dot11InformationElementIDFMSRequest Dot11InformationElementID = 87 + Dot11InformationElementIDFMSResponse Dot11InformationElementID = 88 + Dot11InformationElementIDQOSTrafficCapability Dot11InformationElementID = 89 + Dot11InformationElementIDBSSMaxIdlePeriod Dot11InformationElementID = 90 + Dot11InformationElementIDTFSRequest Dot11InformationElementID = 91 + Dot11InformationElementIDTFSResponse Dot11InformationElementID = 92 + Dot11InformationElementIDWNMSleepMode Dot11InformationElementID = 93 + Dot11InformationElementIDTIMBroadcastRequest Dot11InformationElementID = 94 + Dot11InformationElementIDTIMBroadcastResponse Dot11InformationElementID = 95 + Dot11InformationElementIDCollInterferenceReport Dot11InformationElementID = 96 + Dot11InformationElementIDChannelUsage Dot11InformationElementID = 97 + Dot11InformationElementIDTimeZone Dot11InformationElementID = 98 + Dot11InformationElementIDDMSRequest Dot11InformationElementID = 99 + Dot11InformationElementIDDMSResponse Dot11InformationElementID = 100 + Dot11InformationElementIDLinkIdentifier Dot11InformationElementID = 101 + Dot11InformationElementIDWakeupSchedule Dot11InformationElementID = 102 + Dot11InformationElementIDChannelSwitchTiming Dot11InformationElementID = 104 + Dot11InformationElementIDPTIControl Dot11InformationElementID = 105 + Dot11InformationElementIDPUBufferStatus Dot11InformationElementID = 106 + Dot11InformationElementIDInterworking Dot11InformationElementID = 107 + Dot11InformationElementIDAdvertisementProtocol Dot11InformationElementID = 108 + Dot11InformationElementIDExpBWRequest Dot11InformationElementID = 109 + Dot11InformationElementIDQOSMapSet Dot11InformationElementID = 110 + Dot11InformationElementIDRoamingConsortium Dot11InformationElementID = 111 + Dot11InformationElementIDEmergencyAlertIdentifier Dot11InformationElementID = 112 + Dot11InformationElementIDMeshConfiguration Dot11InformationElementID = 113 + Dot11InformationElementIDMeshID Dot11InformationElementID = 114 + Dot11InformationElementIDMeshLinkMetricReport Dot11InformationElementID = 115 + Dot11InformationElementIDCongestionNotification Dot11InformationElementID = 116 + Dot11InformationElementIDMeshPeeringManagement Dot11InformationElementID = 117 + Dot11InformationElementIDMeshChannelSwitchParam Dot11InformationElementID = 118 + Dot11InformationElementIDMeshAwakeWindows Dot11InformationElementID = 119 + Dot11InformationElementIDBeaconTiming Dot11InformationElementID = 120 + Dot11InformationElementIDMCCAOPSetupRequest Dot11InformationElementID = 121 + Dot11InformationElementIDMCCAOPSetupReply Dot11InformationElementID = 122 + Dot11InformationElementIDMCCAOPAdvertisement Dot11InformationElementID = 123 + Dot11InformationElementIDMCCAOPTeardown Dot11InformationElementID = 124 + Dot11InformationElementIDGateAnnouncement Dot11InformationElementID = 125 + Dot11InformationElementIDRootAnnouncement Dot11InformationElementID = 126 + Dot11InformationElementIDExtCapability Dot11InformationElementID = 127 + Dot11InformationElementIDAgereProprietary Dot11InformationElementID = 128 + Dot11InformationElementIDPathRequest Dot11InformationElementID = 130 + Dot11InformationElementIDPathReply Dot11InformationElementID = 131 + Dot11InformationElementIDPathError Dot11InformationElementID = 132 + Dot11InformationElementIDCiscoCCX1CKIPDeviceName Dot11InformationElementID = 133 + Dot11InformationElementIDCiscoCCX2 Dot11InformationElementID = 136 + Dot11InformationElementIDProxyUpdate Dot11InformationElementID = 137 + Dot11InformationElementIDProxyUpdateConfirmation Dot11InformationElementID = 138 + Dot11InformationElementIDAuthMeshPerringExch Dot11InformationElementID = 139 + Dot11InformationElementIDMIC Dot11InformationElementID = 140 + Dot11InformationElementIDDestinationURI Dot11InformationElementID = 141 + Dot11InformationElementIDUAPSDCoexistence Dot11InformationElementID = 142 + Dot11InformationElementIDWakeupSchedule80211ad Dot11InformationElementID = 143 + Dot11InformationElementIDExtendedSchedule Dot11InformationElementID = 144 + Dot11InformationElementIDSTAAvailability Dot11InformationElementID = 145 + Dot11InformationElementIDDMGTSPEC Dot11InformationElementID = 146 + Dot11InformationElementIDNextDMGATI Dot11InformationElementID = 147 + Dot11InformationElementIDDMSCapabilities Dot11InformationElementID = 148 + Dot11InformationElementIDCiscoUnknown95 Dot11InformationElementID = 149 + Dot11InformationElementIDVendor2 Dot11InformationElementID = 150 + Dot11InformationElementIDDMGOperating Dot11InformationElementID = 151 + Dot11InformationElementIDDMGBSSParamChange Dot11InformationElementID = 152 + Dot11InformationElementIDDMGBeamRefinement Dot11InformationElementID = 153 + Dot11InformationElementIDChannelMeasFeedback Dot11InformationElementID = 154 + Dot11InformationElementIDAwakeWindow Dot11InformationElementID = 157 + Dot11InformationElementIDMultiBand Dot11InformationElementID = 158 + Dot11InformationElementIDADDBAExtension Dot11InformationElementID = 159 + Dot11InformationElementIDNEXTPCPList Dot11InformationElementID = 160 + Dot11InformationElementIDPCPHandover Dot11InformationElementID = 161 + Dot11InformationElementIDDMGLinkMargin Dot11InformationElementID = 162 + Dot11InformationElementIDSwitchingStream Dot11InformationElementID = 163 + Dot11InformationElementIDSessionTransmission Dot11InformationElementID = 164 + Dot11InformationElementIDDynamicTonePairReport Dot11InformationElementID = 165 + Dot11InformationElementIDClusterReport Dot11InformationElementID = 166 + Dot11InformationElementIDRelayCapabilities Dot11InformationElementID = 167 + Dot11InformationElementIDRelayTransferParameter Dot11InformationElementID = 168 + Dot11InformationElementIDBeamlinkMaintenance Dot11InformationElementID = 169 + Dot11InformationElementIDMultipleMacSublayers Dot11InformationElementID = 170 + Dot11InformationElementIDUPID Dot11InformationElementID = 171 + Dot11InformationElementIDDMGLinkAdaptionAck Dot11InformationElementID = 172 + Dot11InformationElementIDSymbolProprietary Dot11InformationElementID = 173 + Dot11InformationElementIDMCCAOPAdvertOverview Dot11InformationElementID = 174 + Dot11InformationElementIDQuietPeriodRequest Dot11InformationElementID = 175 + Dot11InformationElementIDQuietPeriodResponse Dot11InformationElementID = 177 + Dot11InformationElementIDECPACPolicy Dot11InformationElementID = 182 + Dot11InformationElementIDClusterTimeOffset Dot11InformationElementID = 183 + Dot11InformationElementIDAntennaSectorID Dot11InformationElementID = 190 + Dot11InformationElementIDVHTCapabilities Dot11InformationElementID = 191 + Dot11InformationElementIDVHTOperation Dot11InformationElementID = 192 + Dot11InformationElementIDExtendedBSSLoad Dot11InformationElementID = 193 + Dot11InformationElementIDWideBWChannelSwitch Dot11InformationElementID = 194 + Dot11InformationElementIDVHTTxPowerEnvelope Dot11InformationElementID = 195 + Dot11InformationElementIDChannelSwitchWrapper Dot11InformationElementID = 196 + Dot11InformationElementIDOperatingModeNotification Dot11InformationElementID = 199 + Dot11InformationElementIDUPSIM Dot11InformationElementID = 200 + Dot11InformationElementIDReducedNeighborReport Dot11InformationElementID = 201 + Dot11InformationElementIDTVHTOperation Dot11InformationElementID = 202 + Dot11InformationElementIDDeviceLocation Dot11InformationElementID = 204 + Dot11InformationElementIDWhiteSpaceMap Dot11InformationElementID = 205 + Dot11InformationElementIDFineTuningMeasureParams Dot11InformationElementID = 206 + Dot11InformationElementIDVendor Dot11InformationElementID = 221 + Dot11InformationElementIDQosParameter Dot11InformationElementID = 222 + Dot11InformationElementIDS1GOperation Dot11InformationElementID = 232 + Dot11InformationElementIDCAGNumber Dot11InformationElementID = 237 + Dot11InformationElementIDAPCSN Dot11InformationElementID = 239 + Dot11InformationElementIDFILSIndication Dot11InformationElementID = 240 + Dot11InformationElementIDDILS Dot11InformationElementID = 241 + Dot11InformationElementIDFragment Dot11InformationElementID = 242 + Dot11InformationElementIDRSNX Dot11InformationElementID = 244 + Dot11InformationElementIDExtension Dot11InformationElementID = 255 +) + +// String provides a human readable string for Dot11InformationElementID. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11InformationElementID value, +// not its string. +func (a Dot11InformationElementID) String() string { + switch a { + case Dot11InformationElementIDSSID: + return "SSID parameter set" + case Dot11InformationElementIDRates: + return "Supported Rates" + case Dot11InformationElementIDFHSet: + return "FH Parameter set" + case Dot11InformationElementIDDSSet: + return "DS Parameter set" + case Dot11InformationElementIDCFSet: + return "CF Parameter set" + case Dot11InformationElementIDTIM: + return "Traffic Indication Map (TIM)" + case Dot11InformationElementIDIBSSSet: + return "IBSS Parameter set" + case Dot11InformationElementIDCountryInfo: + return "Country Information" + case Dot11InformationElementIDHoppingPatternParam: + return "Hopping Pattern Parameters" + case Dot11InformationElementIDHoppingPatternTable: + return "Hopping Pattern Table" + case Dot11InformationElementIDRequest: + return "Request" + case Dot11InformationElementIDQBSSLoadElem: + return "QBSS Load Element" + case Dot11InformationElementIDEDCAParamSet: + return "EDCA Parameter Set" + case Dot11InformationElementIDTrafficSpec: + return "Traffic Specification" + case Dot11InformationElementIDTrafficClass: + return "Traffic Classification" + case Dot11InformationElementIDSchedule: + return "Schedule" + case Dot11InformationElementIDChallenge: + return "Challenge text" + case Dot11InformationElementIDPowerConst: + return "Power Constraint" + case Dot11InformationElementIDPowerCapability: + return "Power Capability" + case Dot11InformationElementIDTPCRequest: + return "TPC Request" + case Dot11InformationElementIDTPCReport: + return "TPC Report" + case Dot11InformationElementIDSupportedChannels: + return "Supported Channels" + case Dot11InformationElementIDSwitchChannelAnnounce: + return "Channel Switch Announcement" + case Dot11InformationElementIDMeasureRequest: + return "Measurement Request" + case Dot11InformationElementIDMeasureReport: + return "Measurement Report" + case Dot11InformationElementIDQuiet: + return "Quiet" + case Dot11InformationElementIDIBSSDFS: + return "IBSS DFS" + case Dot11InformationElementIDERPInfo: + return "ERP Information" + case Dot11InformationElementIDTSDelay: + return "TS Delay" + case Dot11InformationElementIDTCLASProcessing: + return "TCLAS Processing" + case Dot11InformationElementIDHTCapabilities: + return "HT Capabilities (802.11n D1.10)" + case Dot11InformationElementIDQOSCapability: + return "QOS Capability" + case Dot11InformationElementIDERPInfo2: + return "ERP Information-2" + case Dot11InformationElementIDRSNInfo: + return "RSN Information" + case Dot11InformationElementIDESRates: + return "Extended Supported Rates" + case Dot11InformationElementIDAPChannelReport: + return "AP Channel Report" + case Dot11InformationElementIDNeighborReport: + return "Neighbor Report" + case Dot11InformationElementIDRCPI: + return "RCPI" + case Dot11InformationElementIDMobilityDomain: + return "Mobility Domain" + case Dot11InformationElementIDFastBSSTrans: + return "Fast BSS Transition" + case Dot11InformationElementIDTimeoutInt: + return "Timeout Interval" + case Dot11InformationElementIDRICData: + return "RIC Data" + case Dot11InformationElementIDDSERegisteredLoc: + return "DSE Registered Location" + case Dot11InformationElementIDSuppOperatingClass: + return "Supported Operating Classes" + case Dot11InformationElementIDExtChanSwitchAnnounce: + return "Extended Channel Switch Announcement" + case Dot11InformationElementIDHTInfo: + return "HT Information (802.11n D1.10)" + case Dot11InformationElementIDSecChanOffset: + return "Secondary Channel Offset (802.11n D1.10)" + case Dot11InformationElementIDBSSAverageAccessDelay: + return "BSS Average Access Delay" + case Dot11InformationElementIDAntenna: + return "Antenna" + case Dot11InformationElementIDRSNI: + return "RSNI" + case Dot11InformationElementIDMeasurePilotTrans: + return "Measurement Pilot Transmission" + case Dot11InformationElementIDBSSAvailAdmCapacity: + return "BSS Available Admission Capacity" + case Dot11InformationElementIDBSSACAccDelayWAPIParam: + return "BSS AC Access Delay/WAPI Parameter Set" + case Dot11InformationElementIDTimeAdvertisement: + return "Time Advertisement" + case Dot11InformationElementIDRMEnabledCapabilities: + return "RM Enabled Capabilities" + case Dot11InformationElementIDMultipleBSSID: + return "Multiple BSSID" + case Dot11InformationElementID2040BSSCoExist: + return "20/40 BSS Coexistence" + case Dot11InformationElementID2040BSSIntChanReport: + return "20/40 BSS Intolerant Channel Report" + case Dot11InformationElementIDOverlapBSSScanParam: + return "Overlapping BSS Scan Parameters" + case Dot11InformationElementIDRICDescriptor: + return "RIC Descriptor" + case Dot11InformationElementIDManagementMIC: + return "Management MIC" + case Dot11InformationElementIDEventRequest: + return "Event Request" + case Dot11InformationElementIDEventReport: + return "Event Report" + case Dot11InformationElementIDDiagnosticRequest: + return "Diagnostic Request" + case Dot11InformationElementIDDiagnosticReport: + return "Diagnostic Report" + case Dot11InformationElementIDLocationParam: + return "Location Parameters" + case Dot11InformationElementIDNonTransBSSIDCapability: + return "Non Transmitted BSSID Capability" + case Dot11InformationElementIDSSIDList: + return "SSID List" + case Dot11InformationElementIDMultipleBSSIDIndex: + return "Multiple BSSID Index" + case Dot11InformationElementIDFMSDescriptor: + return "FMS Descriptor" + case Dot11InformationElementIDFMSRequest: + return "FMS Request" + case Dot11InformationElementIDFMSResponse: + return "FMS Response" + case Dot11InformationElementIDQOSTrafficCapability: + return "QoS Traffic Capability" + case Dot11InformationElementIDBSSMaxIdlePeriod: + return "BSS Max Idle Period" + case Dot11InformationElementIDTFSRequest: + return "TFS Request" + case Dot11InformationElementIDTFSResponse: + return "TFS Response" + case Dot11InformationElementIDWNMSleepMode: + return "WNM-Sleep Mode" + case Dot11InformationElementIDTIMBroadcastRequest: + return "TIM Broadcast Request" + case Dot11InformationElementIDTIMBroadcastResponse: + return "TIM Broadcast Response" + case Dot11InformationElementIDCollInterferenceReport: + return "Collocated Interference Report" + case Dot11InformationElementIDChannelUsage: + return "Channel Usage" + case Dot11InformationElementIDTimeZone: + return "Time Zone" + case Dot11InformationElementIDDMSRequest: + return "DMS Request" + case Dot11InformationElementIDDMSResponse: + return "DMS Response" + case Dot11InformationElementIDLinkIdentifier: + return "Link Identifier" + case Dot11InformationElementIDWakeupSchedule: + return "Wakeup Schedule" + case Dot11InformationElementIDChannelSwitchTiming: + return "Channel Switch Timing" + case Dot11InformationElementIDPTIControl: + return "PTI Control" + case Dot11InformationElementIDPUBufferStatus: + return "PU Buffer Status" + case Dot11InformationElementIDInterworking: + return "Interworking" + case Dot11InformationElementIDAdvertisementProtocol: + return "Advertisement Protocol" + case Dot11InformationElementIDExpBWRequest: + return "Expedited Bandwidth Request" + case Dot11InformationElementIDQOSMapSet: + return "QoS Map Set" + case Dot11InformationElementIDRoamingConsortium: + return "Roaming Consortium" + case Dot11InformationElementIDEmergencyAlertIdentifier: + return "Emergency Alert Identifier" + case Dot11InformationElementIDMeshConfiguration: + return "Mesh Configuration" + case Dot11InformationElementIDMeshID: + return "Mesh ID" + case Dot11InformationElementIDMeshLinkMetricReport: + return "Mesh Link Metric Report" + case Dot11InformationElementIDCongestionNotification: + return "Congestion Notification" + case Dot11InformationElementIDMeshPeeringManagement: + return "Mesh Peering Management" + case Dot11InformationElementIDMeshChannelSwitchParam: + return "Mesh Channel Switch Parameters" + case Dot11InformationElementIDMeshAwakeWindows: + return "Mesh Awake Windows" + case Dot11InformationElementIDBeaconTiming: + return "Beacon Timing" + case Dot11InformationElementIDMCCAOPSetupRequest: + return "MCCAOP Setup Request" + case Dot11InformationElementIDMCCAOPSetupReply: + return "MCCAOP SETUP Reply" + case Dot11InformationElementIDMCCAOPAdvertisement: + return "MCCAOP Advertisement" + case Dot11InformationElementIDMCCAOPTeardown: + return "MCCAOP Teardown" + case Dot11InformationElementIDGateAnnouncement: + return "Gate Announcement" + case Dot11InformationElementIDRootAnnouncement: + return "Root Announcement" + case Dot11InformationElementIDExtCapability: + return "Extended Capabilities" + case Dot11InformationElementIDAgereProprietary: + return "Agere Proprietary" + case Dot11InformationElementIDPathRequest: + return "Path Request" + case Dot11InformationElementIDPathReply: + return "Path Reply" + case Dot11InformationElementIDPathError: + return "Path Error" + case Dot11InformationElementIDCiscoCCX1CKIPDeviceName: + return "Cisco CCX1 CKIP + Device Name" + case Dot11InformationElementIDCiscoCCX2: + return "Cisco CCX2" + case Dot11InformationElementIDProxyUpdate: + return "Proxy Update" + case Dot11InformationElementIDProxyUpdateConfirmation: + return "Proxy Update Confirmation" + case Dot11InformationElementIDAuthMeshPerringExch: + return "Auhenticated Mesh Perring Exchange" + case Dot11InformationElementIDMIC: + return "MIC (Message Integrity Code)" + case Dot11InformationElementIDDestinationURI: + return "Destination URI" + case Dot11InformationElementIDUAPSDCoexistence: + return "U-APSD Coexistence" + case Dot11InformationElementIDWakeupSchedule80211ad: + return "Wakeup Schedule 802.11ad" + case Dot11InformationElementIDExtendedSchedule: + return "Extended Schedule" + case Dot11InformationElementIDSTAAvailability: + return "STA Availability" + case Dot11InformationElementIDDMGTSPEC: + return "DMG TSPEC" + case Dot11InformationElementIDNextDMGATI: + return "Next DMG ATI" + case Dot11InformationElementIDDMSCapabilities: + return "DMG Capabilities" + case Dot11InformationElementIDCiscoUnknown95: + return "Cisco Unknown 95" + case Dot11InformationElementIDVendor2: + return "Vendor Specific" + case Dot11InformationElementIDDMGOperating: + return "DMG Operating" + case Dot11InformationElementIDDMGBSSParamChange: + return "DMG BSS Parameter Change" + case Dot11InformationElementIDDMGBeamRefinement: + return "DMG Beam Refinement" + case Dot11InformationElementIDChannelMeasFeedback: + return "Channel Measurement Feedback" + case Dot11InformationElementIDAwakeWindow: + return "Awake Window" + case Dot11InformationElementIDMultiBand: + return "Multi Band" + case Dot11InformationElementIDADDBAExtension: + return "ADDBA Extension" + case Dot11InformationElementIDNEXTPCPList: + return "NEXTPCP List" + case Dot11InformationElementIDPCPHandover: + return "PCP Handover" + case Dot11InformationElementIDDMGLinkMargin: + return "DMG Link Margin" + case Dot11InformationElementIDSwitchingStream: + return "Switching Stream" + case Dot11InformationElementIDSessionTransmission: + return "Session Transmission" + case Dot11InformationElementIDDynamicTonePairReport: + return "Dynamic Tone Pairing Report" + case Dot11InformationElementIDClusterReport: + return "Cluster Report" + case Dot11InformationElementIDRelayCapabilities: + return "Relay Capabilities" + case Dot11InformationElementIDRelayTransferParameter: + return "Relay Transfer Parameter" + case Dot11InformationElementIDBeamlinkMaintenance: + return "Beamlink Maintenance" + case Dot11InformationElementIDMultipleMacSublayers: + return "Multiple MAC Sublayers" + case Dot11InformationElementIDUPID: + return "U-PID" + case Dot11InformationElementIDDMGLinkAdaptionAck: + return "DMG Link Adaption Acknowledgment" + case Dot11InformationElementIDSymbolProprietary: + return "Symbol Proprietary" + case Dot11InformationElementIDMCCAOPAdvertOverview: + return "MCCAOP Advertisement Overview" + case Dot11InformationElementIDQuietPeriodRequest: + return "Quiet Period Request" + case Dot11InformationElementIDQuietPeriodResponse: + return "Quiet Period Response" + case Dot11InformationElementIDECPACPolicy: + return "ECPAC Policy" + case Dot11InformationElementIDClusterTimeOffset: + return "Cluster Time Offset" + case Dot11InformationElementIDAntennaSectorID: + return "Antenna Sector ID" + case Dot11InformationElementIDVHTCapabilities: + return "VHT Capabilities (IEEE Std 802.11ac/D3.1)" + case Dot11InformationElementIDVHTOperation: + return "VHT Operation (IEEE Std 802.11ac/D3.1)" + case Dot11InformationElementIDExtendedBSSLoad: + return "Extended BSS Load" + case Dot11InformationElementIDWideBWChannelSwitch: + return "Wide Bandwidth Channel Switch" + case Dot11InformationElementIDVHTTxPowerEnvelope: + return "VHT Tx Power Envelope (IEEE Std 802.11ac/D5.0)" + case Dot11InformationElementIDChannelSwitchWrapper: + return "Channel Switch Wrapper" + case Dot11InformationElementIDOperatingModeNotification: + return "Operating Mode Notification" + case Dot11InformationElementIDUPSIM: + return "UP SIM" + case Dot11InformationElementIDReducedNeighborReport: + return "Reduced Neighbor Report" + case Dot11InformationElementIDTVHTOperation: + return "TVHT Op" + case Dot11InformationElementIDDeviceLocation: + return "Device Location" + case Dot11InformationElementIDWhiteSpaceMap: + return "White Space Map" + case Dot11InformationElementIDFineTuningMeasureParams: + return "Fine Tuning Measure Parameters" + case Dot11InformationElementIDVendor: + return "Vendor" + case Dot11InformationElementIDS1GOperation: + return "IDS1G Operation" + case Dot11InformationElementIDCAGNumber: + return "CAG Number" + case Dot11InformationElementIDAPCSN: + return "APCSN" + case Dot11InformationElementIDFILSIndication: + return "FILS Indication" + case Dot11InformationElementIDDILS: + return "DILS" + case Dot11InformationElementIDFragment: + return "Fragment" + case Dot11InformationElementIDRSNX: + return "RSNX" + case Dot11InformationElementIDExtension: + return "Extension" + default: + return "Unknown information element id" + } +} + +type Dot11InformationElementExtId uint8 + +const ( + Dot11InformationElementExtIDAssocDelayInfo Dot11InformationElementExtId = 1 + Dot11InformationElementExtIDFilsReqParams Dot11InformationElementExtId = 2 + Dot11InformationElementExtIDFilsKeyConfirm Dot11InformationElementExtId = 3 + Dot11InformationElementExtIDFilsSession Dot11InformationElementExtId = 4 + Dot11InformationElementExtIDFilsHLPContainer Dot11InformationElementExtId = 5 + Dot11InformationElementExtIDFilsIPAddrAssign Dot11InformationElementExtId = 6 + Dot11InformationElementExtIDKeyDelivery Dot11InformationElementExtId = 7 + Dot11InformationElementExtIDFilsWrappedData Dot11InformationElementExtId = 8 + Dot11InformationElementExtIDFilsPublicKey Dot11InformationElementExtId = 12 + Dot11InformationElementExtIDFilsNonce Dot11InformationElementExtId = 13 + Dot11InformationElementExtIDFutureChanGuidance Dot11InformationElementExtId = 14 + Dot11InformationElementExtIDHeCapability Dot11InformationElementExtId = 35 + Dot11InformationElementExtIDHEOperation Dot11InformationElementExtId = 36 + Dot11InformationElementExtIDUora Dot11InformationElementExtId = 37 + Dot11InformationElementExtIDHeMuEdca Dot11InformationElementExtId = 38 + Dot11InformationElementExtIDHeSpr Dot11InformationElementExtId = 39 + Dot11InformationElementExtIDNdpFeedbackReportParamset Dot11InformationElementExtId = 41 + Dot11InformationElementExtIDBssColorChgAnn Dot11InformationElementExtId = 42 + Dot11InformationElementExtIDQuietTimePeriodSetup Dot11InformationElementExtId = 43 + Dot11InformationElementExtIDEssReport Dot11InformationElementExtId = 45 + Dot11InformationElementExtIDOps Dot11InformationElementExtId = 46 + Dot11InformationElementExtIDHeBssLoad Dot11InformationElementExtId = 47 + Dot11InformationElementExtIDMaxChannelSwitchTime Dot11InformationElementExtId = 52 + Dot11InformationElementExtIDMultipleBssidConfiguration Dot11InformationElementExtId = 55 + Dot11InformationElementExtIDNonInheritance Dot11InformationElementExtId = 56 + Dot11InformationElementExtIDKnownBssid Dot11InformationElementExtId = 57 + Dot11InformationElementExtIDShortSsidList Dot11InformationElementExtId = 58 + Dot11InformationElementExtIDHe6ghzCApA Dot11InformationElementExtId = 59 + Dot11InformationElementExtIDuLMuPowerCapA Dot11InformationElementExtId = 60 + Dot11InformationElementExtIDEhTOperation Dot11InformationElementExtId = 106 + Dot11InformationElementExtIDEhtMultiLink Dot11InformationElementExtId = 107 + Dot11InformationElementExtIDEHhCapability Dot11InformationElementExtId = 108 +) + +// String provides a human readable string for Dot11InformationElementExtId. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the Dot11InformationElementExtId value, +// not its string. +func (a Dot11InformationElementExtId) String() string { + switch a { + case Dot11InformationElementExtIDAssocDelayInfo: + return "Association Delay Information" + case Dot11InformationElementExtIDFilsReqParams: + return "FILS Request Parameters" + case Dot11InformationElementExtIDFilsKeyConfirm: + return "FILS Key Confirmation" + case Dot11InformationElementExtIDFilsSession: + return "FILS Session" + case Dot11InformationElementExtIDFilsHLPContainer: + return "FILS HLP Container" + case Dot11InformationElementExtIDFilsIPAddrAssign: + return "FILS IP Address Assignment" + case Dot11InformationElementExtIDKeyDelivery: + return "Key Delivery" + case Dot11InformationElementExtIDFilsWrappedData: + return "FILS Wrapped Data" + case Dot11InformationElementExtIDFilsPublicKey: + return "FILS Public Key" + case Dot11InformationElementExtIDFilsNonce: + return "FILS Nonce" + case Dot11InformationElementExtIDFutureChanGuidance: + return "Future Channel Guidance" + case Dot11InformationElementExtIDHeCapability: + return "HE Capability" + case Dot11InformationElementExtIDHEOperation: + return "HE Operation" + case Dot11InformationElementExtIDUora: + return "UORA" + case Dot11InformationElementExtIDHeMuEdca: + return "HE MU EDCA" + case Dot11InformationElementExtIDHeSpr: + return "HE Spatial Reuse Parameter" + case Dot11InformationElementExtIDNdpFeedbackReportParamset: + return "NDP Feedback Report Parameter Set" + case Dot11InformationElementExtIDBssColorChgAnn: + return "BSS Color Change Announcement" + case Dot11InformationElementExtIDQuietTimePeriodSetup: + return "Quiet Time Period Setup" + case Dot11InformationElementExtIDEssReport: + return "ESS Report" + case Dot11InformationElementExtIDOps: + return "Operating Mode Notification" + case Dot11InformationElementExtIDHeBssLoad: + return "HE BSS Load" + case Dot11InformationElementExtIDMaxChannelSwitchTime: + return "Maximum Channel Switching Time" + case Dot11InformationElementExtIDMultipleBssidConfiguration: + return "Multiple BSSID Configuration" + case Dot11InformationElementExtIDNonInheritance: + return "Non-Inheritance" + case Dot11InformationElementExtIDKnownBssid: + return "Known BSSID" + case Dot11InformationElementExtIDShortSsidList: + return "Short SSID List" + case Dot11InformationElementExtIDHe6ghzCApA: + return "HE 6 GHz Capabilities" + case Dot11InformationElementExtIDuLMuPowerCapA: + return "uL MU Power Capability" + case Dot11InformationElementExtIDEhTOperation: + return "EH-Transition Operation" + case Dot11InformationElementExtIDEhtMultiLink: + return "EHT Multi-link" + case Dot11InformationElementExtIDEHhCapability: + return "EH-Transition HE Capabilities" + default: + return "Unknown information element extended id" + } +} + +// Dot11 provides an IEEE 802.11 base packet header. +// See http://standards.ieee.org/findstds/standard/802.11-2012.html +// for excruciating detail. +type Dot11 struct { + BaseLayer + Type Dot11Type + Proto uint8 + Flags Dot11Flags + DurationID uint16 + Address1 net.HardwareAddr + Address2 net.HardwareAddr + Address3 net.HardwareAddr + Address4 net.HardwareAddr + SequenceNumber uint16 + FragmentNumber uint16 + Checksum uint32 + QOS *Dot11QOS + HTControl *Dot11HTControl + DataLayer gopacket.Layer +} + +type Dot11QOS struct { + TID uint8 /* Traffic IDentifier */ + EOSP bool /* End of service period */ + AckPolicy Dot11AckPolicy + TXOP uint8 +} + +type Dot11HTControl struct { + ACConstraint bool + RDGMorePPDU bool + + VHT *Dot11HTControlVHT + HT *Dot11HTControlHT +} + +type Dot11HTControlHT struct { + LinkAdapationControl *Dot11LinkAdapationControl + CalibrationPosition uint8 + CalibrationSequence uint8 + CSISteering uint8 + NDPAnnouncement bool + DEI bool +} + +type Dot11HTControlVHT struct { + MRQ bool + UnsolicitedMFB bool + MSI *uint8 + MFB Dot11HTControlMFB + CompressedMSI *uint8 + STBCIndication bool + MFSI *uint8 + GID *uint8 + CodingType *Dot11CodingType + FbTXBeamformed bool +} + +type Dot11HTControlMFB struct { + NumSTS uint8 + VHTMCS uint8 + BW uint8 + SNR int8 +} + +type Dot11LinkAdapationControl struct { + TRQ bool + MRQ bool + MSI uint8 + MFSI uint8 + ASEL *Dot11ASEL + MFB *uint8 +} + +type Dot11ASEL struct { + Command uint8 + Data uint8 +} + +type Dot11CodingType uint8 + +const ( + Dot11CodingTypeBCC = 0 + Dot11CodingTypeLDPC = 1 +) + +func (a Dot11CodingType) String() string { + switch a { + case Dot11CodingTypeBCC: + return "BCC" + case Dot11CodingTypeLDPC: + return "LDPC" + default: + return "Unknown coding type" + } +} + +func (m *Dot11HTControlMFB) NoFeedBackPresent() bool { + return m.VHTMCS == 15 && m.NumSTS == 7 +} + +func decodeDot11(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11{} + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(d) + if d.DataLayer != nil { + p.AddLayer(d.DataLayer) + } + return p.NextDecoder(d.NextLayerType()) +} + +func (m *Dot11) LayerType() gopacket.LayerType { return LayerTypeDot11 } +func (m *Dot11) CanDecode() gopacket.LayerClass { return LayerTypeDot11 } +func (m *Dot11) NextLayerType() gopacket.LayerType { + if m.DataLayer != nil { + if m.Flags.WEP() { + return LayerTypeDot11WEP + } + return m.DataLayer.(gopacket.DecodingLayer).NextLayerType() + } + return m.Type.LayerType() +} + +func createU8(x uint8) *uint8 { + return &x +} + +var dataDecodeMap = map[Dot11Type]func() gopacket.DecodingLayer{ + Dot11TypeData: func() gopacket.DecodingLayer { return &Dot11Data{} }, + Dot11TypeDataCFAck: func() gopacket.DecodingLayer { return &Dot11DataCFAck{} }, + Dot11TypeDataCFPoll: func() gopacket.DecodingLayer { return &Dot11DataCFPoll{} }, + Dot11TypeDataCFAckPoll: func() gopacket.DecodingLayer { return &Dot11DataCFAckPoll{} }, + Dot11TypeDataNull: func() gopacket.DecodingLayer { return &Dot11DataNull{} }, + Dot11TypeDataCFAckNoData: func() gopacket.DecodingLayer { return &Dot11DataCFAckNoData{} }, + Dot11TypeDataCFPollNoData: func() gopacket.DecodingLayer { return &Dot11DataCFPollNoData{} }, + Dot11TypeDataCFAckPollNoData: func() gopacket.DecodingLayer { return &Dot11DataCFAckPollNoData{} }, + Dot11TypeDataQOSData: func() gopacket.DecodingLayer { return &Dot11DataQOSData{} }, + Dot11TypeDataQOSDataCFAck: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAck{} }, + Dot11TypeDataQOSDataCFPoll: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFPoll{} }, + Dot11TypeDataQOSDataCFAckPoll: func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAckPoll{} }, + Dot11TypeDataQOSNull: func() gopacket.DecodingLayer { return &Dot11DataQOSNull{} }, + Dot11TypeDataQOSCFPollNoData: func() gopacket.DecodingLayer { return &Dot11DataQOSCFPollNoData{} }, + Dot11TypeDataQOSCFAckPollNoData: func() gopacket.DecodingLayer { return &Dot11DataQOSCFAckPollNoData{} }, +} + +func (m *Dot11) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 10 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), 10) + } + m.Type = Dot11Type((data[0])&0xFC) >> 2 + + m.DataLayer = nil + m.Proto = uint8(data[0]) & 0x0003 + m.Flags = Dot11Flags(data[1]) + m.DurationID = binary.LittleEndian.Uint16(data[2:4]) + m.Address1 = net.HardwareAddr(data[4:10]) + + offset := 10 + + mainType := m.Type.MainType() + + switch mainType { + case Dot11TypeCtrl: + switch m.Type { + case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck, Dot11TypeCtrlBlockAck, Dot11TypeCtrlBlockAckReq: + if len(data) < offset+6 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) + } + m.Address2 = net.HardwareAddr(data[offset : offset+6]) + offset += 6 + } + case Dot11TypeMgmt, Dot11TypeData: + if len(data) < offset+14 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+14) + } + m.Address2 = net.HardwareAddr(data[offset : offset+6]) + offset += 6 + m.Address3 = net.HardwareAddr(data[offset : offset+6]) + offset += 6 + + m.SequenceNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0xFFF0) >> 4 + m.FragmentNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0x000F) + offset += 2 + } + + if mainType == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() { + if len(data) < offset+6 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) + } + m.Address4 = net.HardwareAddr(data[offset : offset+6]) + offset += 6 + } + + if m.Type.QOS() { + if len(data) < offset+2 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) + } + m.QOS = &Dot11QOS{ + TID: (uint8(data[offset]) & 0x0F), + EOSP: (uint8(data[offset]) & 0x10) == 0x10, + AckPolicy: Dot11AckPolicy((uint8(data[offset]) & 0x60) >> 5), + TXOP: uint8(data[offset+1]), + } + offset += 2 + } + if m.Flags.Order() && (m.Type.QOS() || mainType == Dot11TypeMgmt) { + if len(data) < offset+4 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) + } + + htc := &Dot11HTControl{ + ACConstraint: data[offset+3]&0x40 != 0, + RDGMorePPDU: data[offset+3]&0x80 != 0, + } + m.HTControl = htc + + if data[offset]&0x1 != 0 { // VHT Variant + vht := &Dot11HTControlVHT{} + htc.VHT = vht + vht.MRQ = data[offset]&0x4 != 0 + vht.UnsolicitedMFB = data[offset+3]&0x20 != 0 + vht.MFB = Dot11HTControlMFB{ + NumSTS: uint8(data[offset+1] >> 1 & 0x7), + VHTMCS: uint8(data[offset+1] >> 4 & 0xF), + BW: uint8(data[offset+2] & 0x3), + SNR: int8((-(data[offset+2] >> 2 & 0x20))+data[offset+2]>>2&0x1F) + 22, + } + + if vht.UnsolicitedMFB { + if !vht.MFB.NoFeedBackPresent() { + vht.CompressedMSI = createU8(data[offset] >> 3 & 0x3) + vht.STBCIndication = data[offset]&0x20 != 0 + vht.CodingType = (*Dot11CodingType)(createU8(data[offset+3] >> 3 & 0x1)) + vht.FbTXBeamformed = data[offset+3]&0x10 != 0 + vht.GID = createU8( + data[offset]>>6 + + (data[offset+1] & 0x1 << 2) + + data[offset+3]&0x7<<3) + } + } else { + if vht.MRQ { + vht.MSI = createU8((data[offset] >> 3) & 0x07) + } + vht.MFSI = createU8(data[offset]>>6 + (data[offset+1] & 0x1 << 2)) + } + + } else { // HT Variant + ht := &Dot11HTControlHT{} + htc.HT = ht + + lac := &Dot11LinkAdapationControl{} + ht.LinkAdapationControl = lac + lac.TRQ = data[offset]&0x2 != 0 + lac.MFSI = data[offset]>>6&0x3 + data[offset+1]&0x1<<3 + if data[offset]&0x3C == 0x38 { // ASEL + lac.ASEL = &Dot11ASEL{ + Command: data[offset+1] >> 1 & 0x7, + Data: data[offset+1] >> 4 & 0xF, + } + } else { + lac.MRQ = data[offset]&0x4 != 0 + if lac.MRQ { + lac.MSI = data[offset] >> 3 & 0x7 + } + lac.MFB = createU8(data[offset+1] >> 1) + } + ht.CalibrationPosition = data[offset+2] & 0x3 + ht.CalibrationSequence = data[offset+2] >> 2 & 0x3 + ht.CSISteering = data[offset+2] >> 6 & 0x3 + ht.NDPAnnouncement = data[offset+3]&0x1 != 0 + if mainType != Dot11TypeMgmt { + ht.DEI = data[offset+3]&0x20 != 0 + } + } + + offset += 4 + } + + if len(data) < offset+4 { + df.SetTruncated() + return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+4) + } + + m.BaseLayer = BaseLayer{ + Contents: data[0:offset], + Payload: data[offset : len(data)-4], + } + + if mainType == Dot11TypeData { + d := dataDecodeMap[m.Type] + if d == nil { + return fmt.Errorf("unsupported type: %v", m.Type) + } + l := d() + err := l.DecodeFromBytes(m.BaseLayer.Payload, df) + if err != nil { + return err + } + m.DataLayer = l.(gopacket.Layer) + } + + m.Checksum = binary.LittleEndian.Uint32(data[len(data)-4 : len(data)]) + return nil +} + +func (m *Dot11) ChecksumValid() bool { + // only for CTRL and MGMT frames + h := crc32.NewIEEE() + h.Write(m.Contents) + h.Write(m.Payload) + return m.Checksum == h.Sum32() +} + +func (m Dot11) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(24) + + if err != nil { + return err + } + + buf[0] = (uint8(m.Type) << 2) | m.Proto + buf[1] = uint8(m.Flags) + + binary.LittleEndian.PutUint16(buf[2:4], m.DurationID) + + copy(buf[4:10], m.Address1) + + offset := 10 + + switch m.Type.MainType() { + case Dot11TypeCtrl: + switch m.Type { + case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck: + copy(buf[offset:offset+6], m.Address2) + offset += 6 + } + case Dot11TypeMgmt, Dot11TypeData: + copy(buf[offset:offset+6], m.Address2) + offset += 6 + copy(buf[offset:offset+6], m.Address3) + offset += 6 + + binary.LittleEndian.PutUint16(buf[offset:offset+2], (m.SequenceNumber<<4)|m.FragmentNumber) + offset += 2 + } + + if m.Type.MainType() == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() { + copy(buf[offset:offset+6], m.Address4) + offset += 6 + } + + return nil +} + +// Dot11Mgmt is a base for all IEEE 802.11 management layers. +type Dot11Mgmt struct { + BaseLayer +} + +func (m *Dot11Mgmt) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload } +func (m *Dot11Mgmt) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +// Dot11Ctrl is a base for all IEEE 802.11 control layers. +type Dot11Ctrl struct { + BaseLayer +} + +func (m *Dot11Ctrl) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload } + +func (m *Dot11Ctrl) LayerType() gopacket.LayerType { return LayerTypeDot11Ctrl } +func (m *Dot11Ctrl) CanDecode() gopacket.LayerClass { return LayerTypeDot11Ctrl } +func (m *Dot11Ctrl) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +func decodeDot11Ctrl(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11Ctrl{} + return decodingLayerDecoder(d, data, p) +} + +// Dot11WEP contains WEP encrpted IEEE 802.11 data. +type Dot11WEP struct { + BaseLayer +} + +func (m *Dot11WEP) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload } + +func (m *Dot11WEP) LayerType() gopacket.LayerType { return LayerTypeDot11WEP } +func (m *Dot11WEP) CanDecode() gopacket.LayerClass { return LayerTypeDot11WEP } +func (m *Dot11WEP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +func decodeDot11WEP(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11WEP{} + return decodingLayerDecoder(d, data, p) +} + +// Dot11Data is a base for all IEEE 802.11 data layers. +type Dot11Data struct { + BaseLayer +} + +func (m *Dot11Data) NextLayerType() gopacket.LayerType { + return LayerTypeLLC +} + +func (m *Dot11Data) LayerType() gopacket.LayerType { return LayerTypeDot11Data } +func (m *Dot11Data) CanDecode() gopacket.LayerClass { return LayerTypeDot11Data } +func (m *Dot11Data) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Payload = data + return nil +} + +func decodeDot11Data(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11Data{} + return decodingLayerDecoder(d, data, p) +} + +type Dot11DataCFAck struct { + Dot11Data +} + +func decodeDot11DataCFAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFAck) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAck } +func (m *Dot11DataCFAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAck } +func (m *Dot11DataCFAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataCFPoll struct { + Dot11Data +} + +func decodeDot11DataCFPoll(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFPoll{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFPoll) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFPoll } +func (m *Dot11DataCFPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFPoll } +func (m *Dot11DataCFPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataCFAckPoll struct { + Dot11Data +} + +func decodeDot11DataCFAckPoll(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFAckPoll{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFAckPoll) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAckPoll } +func (m *Dot11DataCFAckPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckPoll } +func (m *Dot11DataCFAckPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataNull struct { + Dot11Data +} + +func decodeDot11DataNull(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataNull{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataNull) LayerType() gopacket.LayerType { return LayerTypeDot11DataNull } +func (m *Dot11DataNull) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataNull } +func (m *Dot11DataNull) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataCFAckNoData struct { + Dot11Data +} + +func decodeDot11DataCFAckNoData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFAckNoData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFAckNoData) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFAckNoData } +func (m *Dot11DataCFAckNoData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckNoData } +func (m *Dot11DataCFAckNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataCFPollNoData struct { + Dot11Data +} + +func decodeDot11DataCFPollNoData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFPollNoData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFPollNoData) LayerType() gopacket.LayerType { return LayerTypeDot11DataCFPollNoData } +func (m *Dot11DataCFPollNoData) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataCFPollNoData +} +func (m *Dot11DataCFPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataCFAckPollNoData struct { + Dot11Data +} + +func decodeDot11DataCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataCFAckPollNoData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataCFAckPollNoData) LayerType() gopacket.LayerType { + return LayerTypeDot11DataCFAckPollNoData +} +func (m *Dot11DataCFAckPollNoData) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataCFAckPollNoData +} +func (m *Dot11DataCFAckPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Data.DecodeFromBytes(data, df) +} + +type Dot11DataQOS struct { + Dot11Ctrl +} + +func (m *Dot11DataQOS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.BaseLayer = BaseLayer{Payload: data} + return nil +} + +type Dot11DataQOSData struct { + Dot11DataQOS +} + +func decodeDot11DataQOSData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSData) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSData } +func (m *Dot11DataQOSData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataQOSData } + +func (m *Dot11DataQOSData) NextLayerType() gopacket.LayerType { + return LayerTypeDot11Data +} + +type Dot11DataQOSDataCFAck struct { + Dot11DataQOS +} + +func decodeDot11DataQOSDataCFAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSDataCFAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSDataCFAck) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSDataCFAck } +func (m *Dot11DataQOSDataCFAck) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataQOSDataCFAck +} +func (m *Dot11DataQOSDataCFAck) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFAck } + +type Dot11DataQOSDataCFPoll struct { + Dot11DataQOS +} + +func decodeDot11DataQOSDataCFPoll(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSDataCFPoll{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSDataCFPoll) LayerType() gopacket.LayerType { + return LayerTypeDot11DataQOSDataCFPoll +} +func (m *Dot11DataQOSDataCFPoll) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataQOSDataCFPoll +} +func (m *Dot11DataQOSDataCFPoll) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFPoll } + +type Dot11DataQOSDataCFAckPoll struct { + Dot11DataQOS +} + +func decodeDot11DataQOSDataCFAckPoll(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSDataCFAckPoll{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSDataCFAckPoll) LayerType() gopacket.LayerType { + return LayerTypeDot11DataQOSDataCFAckPoll +} +func (m *Dot11DataQOSDataCFAckPoll) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataQOSDataCFAckPoll +} +func (m *Dot11DataQOSDataCFAckPoll) NextLayerType() gopacket.LayerType { + return LayerTypeDot11DataCFAckPoll +} + +type Dot11DataQOSNull struct { + Dot11DataQOS +} + +func decodeDot11DataQOSNull(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSNull{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSNull) LayerType() gopacket.LayerType { return LayerTypeDot11DataQOSNull } +func (m *Dot11DataQOSNull) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataQOSNull } +func (m *Dot11DataQOSNull) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataNull } + +type Dot11DataQOSCFPollNoData struct { + Dot11DataQOS +} + +func decodeDot11DataQOSCFPollNoData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSCFPollNoData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSCFPollNoData) LayerType() gopacket.LayerType { + return LayerTypeDot11DataQOSCFPollNoData +} +func (m *Dot11DataQOSCFPollNoData) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataQOSCFPollNoData +} +func (m *Dot11DataQOSCFPollNoData) NextLayerType() gopacket.LayerType { + return LayerTypeDot11DataCFPollNoData +} + +type Dot11DataQOSCFAckPollNoData struct { + Dot11DataQOS +} + +func decodeDot11DataQOSCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11DataQOSCFAckPollNoData{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11DataQOSCFAckPollNoData) LayerType() gopacket.LayerType { + return LayerTypeDot11DataQOSCFAckPollNoData +} +func (m *Dot11DataQOSCFAckPollNoData) CanDecode() gopacket.LayerClass { + return LayerTypeDot11DataQOSCFAckPollNoData +} +func (m *Dot11DataQOSCFAckPollNoData) NextLayerType() gopacket.LayerType { + return LayerTypeDot11DataCFAckPollNoData +} + +type Dot11InformationElement struct { + BaseLayer + ID Dot11InformationElementID + Length uint8 + OUI []byte + Info []byte + ExtensionID Dot11InformationElementExtId +} + +func (m *Dot11InformationElement) LayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} +func (m *Dot11InformationElement) CanDecode() gopacket.LayerClass { + return LayerTypeDot11InformationElement +} + +func (m *Dot11InformationElement) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} + +func checkOffsetLength(start int, end int, df *gopacket.DecodeFeedback) error { + if start > end { + (*df).SetTruncated() + return fmt.Errorf("information element length %v too short, %v required", end, start) + } + + return nil +} + +func (m *Dot11InformationElement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 2 { + df.SetTruncated() + return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), 2) + } + m.ID = Dot11InformationElementID(data[0]) + m.Length = data[1] + offset := int(2) + + if len(data) < offset+int(m.Length) { + df.SetTruncated() + return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), offset+int(m.Length)) + } + + if m.ID == 221 { + if len(data) < offset+4 { + df.SetTruncated() + return fmt.Errorf("vendor extension size < %d", offset+int(m.Length)) + } + + // Vendor extension + m.OUI = data[offset : offset+4] + if err := checkOffsetLength(offset+4, offset+int(m.Length), &df); err != nil { + return err + } + m.Info = data[offset+4 : offset+int(m.Length)] + } else if m.ID == 255 { + m.ExtensionID = Dot11InformationElementExtId(data[offset]) + if err := checkOffsetLength(offset+1, offset+int(m.Length), &df); err != nil { + return err + } + m.Info = data[offset+1 : offset+int(m.Length)] + } else { + m.Info = data[offset : offset+int(m.Length)] + } + + offset += int(m.Length) + + m.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]} + return nil +} + +func (d *Dot11InformationElement) String() string { + if d.ID == 0 { + return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, SSID: %v)", d.ID, d.Length, string(d.Info)) + } else if d.ID == 1 { + rates := "" + for i := 0; i < len(d.Info); i++ { + if d.Info[i]&0x80 == 0 { + rates += fmt.Sprintf("%.1f ", float32(d.Info[i])*0.5) + } else { + rates += fmt.Sprintf("%.1f* ", float32(d.Info[i]&0x7F)*0.5) + } + } + return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Rates: %s Mbit)", d.ID, d.Length, rates) + } else if d.ID == 221 { + return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, OUI: %X, Info: %X)", d.ID, d.Length, d.OUI, d.Info) + } else if d.ID == 255 { + return fmt.Sprintf("802.11 Information Element Extension (ID: %v, Length %v, Info %X)", d.ExtensionID, d.Length, d.Info) + } else { + return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Info: %X)", d.ID, d.Length, d.Info) + } +} + +func (m Dot11InformationElement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + length := len(m.Info) + len(m.OUI) + if buf, err := b.PrependBytes(2 + length); err != nil { + return err + } else { + buf[0] = uint8(m.ID) + buf[1] = uint8(length) + copy(buf[2:], m.OUI) + copy(buf[2+len(m.OUI):], m.Info) + } + return nil +} + +func decodeDot11InformationElement(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11InformationElement{} + return decodingLayerDecoder(d, data, p) +} + +type Dot11CtrlCTS struct { + Dot11Ctrl +} + +func decodeDot11CtrlCTS(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlCTS{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlCTS) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlCTS +} +func (m *Dot11CtrlCTS) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlCTS +} +func (m *Dot11CtrlCTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlRTS struct { + Dot11Ctrl +} + +func decodeDot11CtrlRTS(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlRTS{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlRTS) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlRTS +} +func (m *Dot11CtrlRTS) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlRTS +} +func (m *Dot11CtrlRTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlBlockAckReq struct { + Dot11Ctrl +} + +func decodeDot11CtrlBlockAckReq(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlBlockAckReq{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlBlockAckReq) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlBlockAckReq +} +func (m *Dot11CtrlBlockAckReq) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlBlockAckReq +} +func (m *Dot11CtrlBlockAckReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlBlockAck struct { + Dot11Ctrl +} + +func decodeDot11CtrlBlockAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlBlockAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlBlockAck) LayerType() gopacket.LayerType { return LayerTypeDot11CtrlBlockAck } +func (m *Dot11CtrlBlockAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlBlockAck } +func (m *Dot11CtrlBlockAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlPowersavePoll struct { + Dot11Ctrl +} + +func decodeDot11CtrlPowersavePoll(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlPowersavePoll{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlPowersavePoll) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlPowersavePoll +} +func (m *Dot11CtrlPowersavePoll) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlPowersavePoll +} +func (m *Dot11CtrlPowersavePoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlAck struct { + Dot11Ctrl +} + +func decodeDot11CtrlAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlAck) LayerType() gopacket.LayerType { return LayerTypeDot11CtrlAck } +func (m *Dot11CtrlAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlAck } +func (m *Dot11CtrlAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlCFEnd struct { + Dot11Ctrl +} + +func decodeDot11CtrlCFEnd(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlCFEnd{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlCFEnd) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlCFEnd +} +func (m *Dot11CtrlCFEnd) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlCFEnd +} +func (m *Dot11CtrlCFEnd) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11CtrlCFEndAck struct { + Dot11Ctrl +} + +func decodeDot11CtrlCFEndAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11CtrlCFEndAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11CtrlCFEndAck) LayerType() gopacket.LayerType { + return LayerTypeDot11CtrlCFEndAck +} +func (m *Dot11CtrlCFEndAck) CanDecode() gopacket.LayerClass { + return LayerTypeDot11CtrlCFEndAck +} +func (m *Dot11CtrlCFEndAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + return m.Dot11Ctrl.DecodeFromBytes(data, df) +} + +type Dot11MgmtAssociationReq struct { + Dot11Mgmt + CapabilityInfo uint16 + ListenInterval uint16 +} + +func decodeDot11MgmtAssociationReq(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtAssociationReq{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtAssociationReq) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtAssociationReq +} +func (m *Dot11MgmtAssociationReq) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtAssociationReq +} +func (m *Dot11MgmtAssociationReq) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} +func (m *Dot11MgmtAssociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtAssociationReq length %v too short, %v required", len(data), 4) + } + m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) + m.ListenInterval = binary.LittleEndian.Uint16(data[2:4]) + m.Payload = data[4:] + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtAssociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(4) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo) + binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval) + + return nil +} + +type Dot11MgmtAssociationResp struct { + Dot11Mgmt + CapabilityInfo uint16 + Status Dot11Status + AID uint16 +} + +func decodeDot11MgmtAssociationResp(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtAssociationResp{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtAssociationResp) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtAssociationResp +} +func (m *Dot11MgmtAssociationResp) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtAssociationResp +} +func (m *Dot11MgmtAssociationResp) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} +func (m *Dot11MgmtAssociationResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 6 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtAssociationResp length %v too short, %v required", len(data), 6) + } + m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) + m.Status = Dot11Status(binary.LittleEndian.Uint16(data[2:4])) + m.AID = binary.LittleEndian.Uint16(data[4:6]) + m.Payload = data[6:] + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtAssociationResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(6) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo) + binary.LittleEndian.PutUint16(buf[2:4], uint16(m.Status)) + binary.LittleEndian.PutUint16(buf[4:6], m.AID) + + return nil +} + +type Dot11MgmtReassociationReq struct { + Dot11Mgmt + CapabilityInfo uint16 + ListenInterval uint16 + CurrentApAddress net.HardwareAddr +} + +func decodeDot11MgmtReassociationReq(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtReassociationReq{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtReassociationReq) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtReassociationReq +} +func (m *Dot11MgmtReassociationReq) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtReassociationReq +} +func (m *Dot11MgmtReassociationReq) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} +func (m *Dot11MgmtReassociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 10 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtReassociationReq length %v too short, %v required", len(data), 10) + } + m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) + m.ListenInterval = binary.LittleEndian.Uint16(data[2:4]) + m.CurrentApAddress = net.HardwareAddr(data[4:10]) + m.Payload = data[10:] + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtReassociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(10) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo) + binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval) + + copy(buf[4:10], m.CurrentApAddress) + + return nil +} + +type Dot11MgmtReassociationResp struct { + Dot11Mgmt +} + +func decodeDot11MgmtReassociationResp(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtReassociationResp{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtReassociationResp) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtReassociationResp +} +func (m *Dot11MgmtReassociationResp) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtReassociationResp +} +func (m *Dot11MgmtReassociationResp) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} + +type Dot11MgmtProbeReq struct { + Dot11Mgmt +} + +func decodeDot11MgmtProbeReq(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtProbeReq{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtProbeReq) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtProbeReq } +func (m *Dot11MgmtProbeReq) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeReq } +func (m *Dot11MgmtProbeReq) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} + +type Dot11MgmtProbeResp struct { + Dot11Mgmt + Timestamp uint64 + Interval uint16 + Flags uint16 +} + +func decodeDot11MgmtProbeResp(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtProbeResp{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtProbeResp) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtProbeResp } +func (m *Dot11MgmtProbeResp) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeResp } +func (m *Dot11MgmtProbeResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 12 { + df.SetTruncated() + + return fmt.Errorf("Dot11MgmtProbeResp length %v too short, %v required", len(data), 12) + } + + m.Timestamp = binary.LittleEndian.Uint64(data[0:8]) + m.Interval = binary.LittleEndian.Uint16(data[8:10]) + m.Flags = binary.LittleEndian.Uint16(data[10:12]) + m.Payload = data[12:] + + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m *Dot11MgmtProbeResp) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} + +func (m Dot11MgmtProbeResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(12) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp) + binary.LittleEndian.PutUint16(buf[8:10], m.Interval) + binary.LittleEndian.PutUint16(buf[10:12], m.Flags) + + return nil +} + +type Dot11MgmtMeasurementPilot struct { + Dot11Mgmt +} + +func decodeDot11MgmtMeasurementPilot(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtMeasurementPilot{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtMeasurementPilot) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtMeasurementPilot +} +func (m *Dot11MgmtMeasurementPilot) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtMeasurementPilot +} + +type Dot11MgmtBeacon struct { + Dot11Mgmt + Timestamp uint64 + Interval uint16 + Flags uint16 +} + +func decodeDot11MgmtBeacon(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtBeacon{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtBeacon) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtBeacon } +func (m *Dot11MgmtBeacon) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtBeacon } +func (m *Dot11MgmtBeacon) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 12 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtBeacon length %v too short, %v required", len(data), 12) + } + m.Timestamp = binary.LittleEndian.Uint64(data[0:8]) + m.Interval = binary.LittleEndian.Uint16(data[8:10]) + m.Flags = binary.LittleEndian.Uint16(data[10:12]) + m.Payload = data[12:] + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m *Dot11MgmtBeacon) NextLayerType() gopacket.LayerType { return LayerTypeDot11InformationElement } + +func (m Dot11MgmtBeacon) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(12) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp) + binary.LittleEndian.PutUint16(buf[8:10], m.Interval) + binary.LittleEndian.PutUint16(buf[10:12], m.Flags) + + return nil +} + +type Dot11MgmtATIM struct { + Dot11Mgmt +} + +func decodeDot11MgmtATIM(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtATIM{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtATIM) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtATIM } +func (m *Dot11MgmtATIM) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtATIM } + +type Dot11MgmtDisassociation struct { + Dot11Mgmt + Reason Dot11Reason +} + +func decodeDot11MgmtDisassociation(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtDisassociation{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtDisassociation) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtDisassociation +} +func (m *Dot11MgmtDisassociation) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtDisassociation +} +func (m *Dot11MgmtDisassociation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 2 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtDisassociation length %v too short, %v required", len(data), 2) + } + m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2])) + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtDisassociation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(2) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason)) + + return nil +} + +type Dot11MgmtAuthentication struct { + Dot11Mgmt + Algorithm Dot11Algorithm + Sequence uint16 + Status Dot11Status +} + +func decodeDot11MgmtAuthentication(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtAuthentication{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtAuthentication) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtAuthentication +} +func (m *Dot11MgmtAuthentication) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtAuthentication +} +func (m *Dot11MgmtAuthentication) NextLayerType() gopacket.LayerType { + return LayerTypeDot11InformationElement +} +func (m *Dot11MgmtAuthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 6 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtAuthentication length %v too short, %v required", len(data), 6) + } + m.Algorithm = Dot11Algorithm(binary.LittleEndian.Uint16(data[0:2])) + m.Sequence = binary.LittleEndian.Uint16(data[2:4]) + m.Status = Dot11Status(binary.LittleEndian.Uint16(data[4:6])) + m.Payload = data[6:] + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtAuthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(6) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Algorithm)) + binary.LittleEndian.PutUint16(buf[2:4], m.Sequence) + binary.LittleEndian.PutUint16(buf[4:6], uint16(m.Status)) + + return nil +} + +type Dot11MgmtDeauthentication struct { + Dot11Mgmt + Reason Dot11Reason +} + +func decodeDot11MgmtDeauthentication(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtDeauthentication{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtDeauthentication) LayerType() gopacket.LayerType { + return LayerTypeDot11MgmtDeauthentication +} +func (m *Dot11MgmtDeauthentication) CanDecode() gopacket.LayerClass { + return LayerTypeDot11MgmtDeauthentication +} +func (m *Dot11MgmtDeauthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 2 { + df.SetTruncated() + return fmt.Errorf("Dot11MgmtDeauthentication length %v too short, %v required", len(data), 2) + } + m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2])) + return m.Dot11Mgmt.DecodeFromBytes(data, df) +} + +func (m Dot11MgmtDeauthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(2) + + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason)) + + return nil +} + +type Dot11MgmtAction struct { + Dot11Mgmt +} + +func decodeDot11MgmtAction(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtAction{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtAction) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtAction } +func (m *Dot11MgmtAction) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtAction } + +type Dot11MgmtActionNoAck struct { + Dot11Mgmt +} + +func decodeDot11MgmtActionNoAck(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtActionNoAck{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtActionNoAck) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtActionNoAck } +func (m *Dot11MgmtActionNoAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtActionNoAck } + +type Dot11MgmtArubaWLAN struct { + Dot11Mgmt +} + +func decodeDot11MgmtArubaWLAN(data []byte, p gopacket.PacketBuilder) error { + d := &Dot11MgmtArubaWLAN{} + return decodingLayerDecoder(d, data, p) +} + +func (m *Dot11MgmtArubaWLAN) LayerType() gopacket.LayerType { return LayerTypeDot11MgmtArubaWLAN } +func (m *Dot11MgmtArubaWLAN) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtArubaWLAN } diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot1q.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot1q.go new file mode 100644 index 0000000000..ada0950f9a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/dot1q.go @@ -0,0 +1,76 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +// Dot1Q is the packet layer for 802.1Q VLAN headers. +type Dot1Q struct { + BaseLayer + Priority uint8 + DropEligible bool + VLANIdentifier uint16 + Type EthernetType +} + +// LayerType returns gopacket.LayerTypeDot1Q +func (d *Dot1Q) LayerType() gopacket.LayerType { return LayerTypeDot1Q } + +// DecodeFromBytes decodes the given bytes into this layer. +func (d *Dot1Q) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("802.1Q tag length %d too short", len(data)) + } + d.Priority = (data[0] & 0xE0) >> 5 + d.DropEligible = data[0]&0x10 != 0 + d.VLANIdentifier = binary.BigEndian.Uint16(data[:2]) & 0x0FFF + d.Type = EthernetType(binary.BigEndian.Uint16(data[2:4])) + d.BaseLayer = BaseLayer{Contents: data[:4], Payload: data[4:]} + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (d *Dot1Q) CanDecode() gopacket.LayerClass { + return LayerTypeDot1Q +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (d *Dot1Q) NextLayerType() gopacket.LayerType { + return d.Type.LayerType() +} + +func decodeDot1Q(data []byte, p gopacket.PacketBuilder) error { + d := &Dot1Q{} + return decodingLayerDecoder(d, data, p) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (d *Dot1Q) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + if d.VLANIdentifier > 0xFFF { + return fmt.Errorf("vlan identifier %v is too high", d.VLANIdentifier) + } + firstBytes := uint16(d.Priority)<<13 | d.VLANIdentifier + if d.DropEligible { + firstBytes |= 0x1000 + } + binary.BigEndian.PutUint16(bytes, firstBytes) + binary.BigEndian.PutUint16(bytes[2:], uint16(d.Type)) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eap.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eap.go new file mode 100644 index 0000000000..d8dc9a9ec3 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eap.go @@ -0,0 +1,115 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +type EAPCode uint8 +type EAPType uint8 + +const ( + EAPCodeRequest EAPCode = 1 + EAPCodeResponse EAPCode = 2 + EAPCodeSuccess EAPCode = 3 + EAPCodeFailure EAPCode = 4 + + // EAPTypeNone means that this EAP layer has no Type or TypeData. + // Success and Failure EAPs will have this set. + EAPTypeNone EAPType = 0 + + EAPTypeIdentity EAPType = 1 + EAPTypeNotification EAPType = 2 + EAPTypeNACK EAPType = 3 + EAPTypeOTP EAPType = 4 + EAPTypeTokenCard EAPType = 5 +) + +// EAP defines an Extensible Authentication Protocol (rfc 3748) layer. +type EAP struct { + BaseLayer + Code EAPCode + Id uint8 + Length uint16 + Type EAPType + TypeData []byte +} + +// LayerType returns LayerTypeEAP. +func (e *EAP) LayerType() gopacket.LayerType { return LayerTypeEAP } + +// DecodeFromBytes decodes the given bytes into this layer. +func (e *EAP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("EAP length %d too short", len(data)) + } + e.Code = EAPCode(data[0]) + e.Id = data[1] + e.Length = binary.BigEndian.Uint16(data[2:4]) + if len(data) < int(e.Length) { + df.SetTruncated() + return fmt.Errorf("EAP length %d too short, %d expected", len(data), e.Length) + } + switch { + case e.Length > 4: + e.Type = EAPType(data[4]) + e.TypeData = data[5:] + case e.Length == 4: + e.Type = 0 + e.TypeData = nil + default: + return fmt.Errorf("invalid EAP length %d", e.Length) + } + e.BaseLayer.Contents = data[:e.Length] + e.BaseLayer.Payload = data[e.Length:] // Should be 0 bytes + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (e *EAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if opts.FixLengths { + e.Length = uint16(len(e.TypeData) + 1) + } + size := len(e.TypeData) + 4 + if size > 4 { + size++ + } + bytes, err := b.PrependBytes(size) + if err != nil { + return err + } + bytes[0] = byte(e.Code) + bytes[1] = e.Id + binary.BigEndian.PutUint16(bytes[2:], e.Length) + if size > 4 { + bytes[4] = byte(e.Type) + copy(bytes[5:], e.TypeData) + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (e *EAP) CanDecode() gopacket.LayerClass { + return LayerTypeEAP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (e *EAP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +func decodeEAP(data []byte, p gopacket.PacketBuilder) error { + e := &EAP{} + return decodingLayerDecoder(e, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eapol.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eapol.go new file mode 100644 index 0000000000..1016e1d4bb --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/eapol.go @@ -0,0 +1,303 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +// EAPOL defines an EAP over LAN (802.1x) layer. +type EAPOL struct { + BaseLayer + Version uint8 + Type EAPOLType + Length uint16 +} + +// LayerType returns LayerTypeEAPOL. +func (e *EAPOL) LayerType() gopacket.LayerType { return LayerTypeEAPOL } + +// DecodeFromBytes decodes the given bytes into this layer. +func (e *EAPOL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("EAPOL length %d too short", len(data)) + } + e.Version = data[0] + e.Type = EAPOLType(data[1]) + e.Length = binary.BigEndian.Uint16(data[2:4]) + e.BaseLayer = BaseLayer{data[:4], data[4:]} + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer +func (e *EAPOL) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, _ := b.PrependBytes(4) + bytes[0] = e.Version + bytes[1] = byte(e.Type) + binary.BigEndian.PutUint16(bytes[2:], e.Length) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (e *EAPOL) CanDecode() gopacket.LayerClass { + return LayerTypeEAPOL +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (e *EAPOL) NextLayerType() gopacket.LayerType { + return e.Type.LayerType() +} + +func decodeEAPOL(data []byte, p gopacket.PacketBuilder) error { + e := &EAPOL{} + return decodingLayerDecoder(e, data, p) +} + +// EAPOLKeyDescriptorType is an enumeration of key descriptor types +// as specified by 802.1x in the EAPOL-Key frame +type EAPOLKeyDescriptorType uint8 + +// Enumeration of EAPOLKeyDescriptorType +const ( + EAPOLKeyDescriptorTypeRC4 EAPOLKeyDescriptorType = 1 + EAPOLKeyDescriptorTypeDot11 EAPOLKeyDescriptorType = 2 + EAPOLKeyDescriptorTypeWPA EAPOLKeyDescriptorType = 254 +) + +func (kdt EAPOLKeyDescriptorType) String() string { + switch kdt { + case EAPOLKeyDescriptorTypeRC4: + return "RC4" + case EAPOLKeyDescriptorTypeDot11: + return "802.11" + case EAPOLKeyDescriptorTypeWPA: + return "WPA" + default: + return fmt.Sprintf("unknown descriptor type %d", kdt) + } +} + +// EAPOLKeyDescriptorVersion is an enumeration of versions specifying the +// encryption algorithm for the key data and the authentication for the +// message integrity code (MIC) +type EAPOLKeyDescriptorVersion uint8 + +// Enumeration of EAPOLKeyDescriptorVersion +const ( + EAPOLKeyDescriptorVersionOther EAPOLKeyDescriptorVersion = 0 + EAPOLKeyDescriptorVersionRC4HMACMD5 EAPOLKeyDescriptorVersion = 1 + EAPOLKeyDescriptorVersionAESHMACSHA1 EAPOLKeyDescriptorVersion = 2 + EAPOLKeyDescriptorVersionAES128CMAC EAPOLKeyDescriptorVersion = 3 +) + +func (v EAPOLKeyDescriptorVersion) String() string { + switch v { + case EAPOLKeyDescriptorVersionOther: + return "Other" + case EAPOLKeyDescriptorVersionRC4HMACMD5: + return "RC4-HMAC-MD5" + case EAPOLKeyDescriptorVersionAESHMACSHA1: + return "AES-HMAC-SHA1-128" + case EAPOLKeyDescriptorVersionAES128CMAC: + return "AES-128-CMAC" + default: + return fmt.Sprintf("unknown version %d", v) + } +} + +// EAPOLKeyType is an enumeration of key derivation types describing +// the purpose of the keys being derived. +type EAPOLKeyType uint8 + +// Enumeration of EAPOLKeyType +const ( + EAPOLKeyTypeGroupSMK EAPOLKeyType = 0 + EAPOLKeyTypePairwise EAPOLKeyType = 1 +) + +func (kt EAPOLKeyType) String() string { + switch kt { + case EAPOLKeyTypeGroupSMK: + return "Group/SMK" + case EAPOLKeyTypePairwise: + return "Pairwise" + default: + return fmt.Sprintf("unknown key type %d", kt) + } +} + +// EAPOLKey defines an EAPOL-Key frame for 802.1x authentication +type EAPOLKey struct { + BaseLayer + KeyDescriptorType EAPOLKeyDescriptorType + KeyDescriptorVersion EAPOLKeyDescriptorVersion + KeyType EAPOLKeyType + KeyIndex uint8 + Install bool + KeyACK bool + KeyMIC bool + Secure bool + MICError bool + Request bool + HasEncryptedKeyData bool + SMKMessage bool + KeyLength uint16 + ReplayCounter uint64 + Nonce []byte + IV []byte + RSC uint64 + ID uint64 + MIC []byte + KeyDataLength uint16 + EncryptedKeyData []byte +} + +// LayerType returns LayerTypeEAPOLKey. +func (ek *EAPOLKey) LayerType() gopacket.LayerType { + return LayerTypeEAPOLKey +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (ek *EAPOLKey) CanDecode() gopacket.LayerType { + return LayerTypeEAPOLKey +} + +// NextLayerType returns layers.LayerTypeDot11InformationElement if the key +// data exists and is unencrypted, otherwise it does not expect a next layer. +func (ek *EAPOLKey) NextLayerType() gopacket.LayerType { + if !ek.HasEncryptedKeyData && ek.KeyDataLength > 0 { + return LayerTypeDot11InformationElement + } + return gopacket.LayerTypePayload +} + +const eapolKeyFrameLen = 95 + +// DecodeFromBytes decodes the given bytes into this layer. +func (ek *EAPOLKey) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < eapolKeyFrameLen { + df.SetTruncated() + return fmt.Errorf("EAPOLKey length %v too short, %v required", + len(data), eapolKeyFrameLen) + } + + ek.KeyDescriptorType = EAPOLKeyDescriptorType(data[0]) + + info := binary.BigEndian.Uint16(data[1:3]) + ek.KeyDescriptorVersion = EAPOLKeyDescriptorVersion(info & 0x0007) + ek.KeyType = EAPOLKeyType((info & 0x0008) >> 3) + ek.KeyIndex = uint8((info & 0x0030) >> 4) + ek.Install = (info & 0x0040) != 0 + ek.KeyACK = (info & 0x0080) != 0 + ek.KeyMIC = (info & 0x0100) != 0 + ek.Secure = (info & 0x0200) != 0 + ek.MICError = (info & 0x0400) != 0 + ek.Request = (info & 0x0800) != 0 + ek.HasEncryptedKeyData = (info & 0x1000) != 0 + ek.SMKMessage = (info & 0x2000) != 0 + + ek.KeyLength = binary.BigEndian.Uint16(data[3:5]) + ek.ReplayCounter = binary.BigEndian.Uint64(data[5:13]) + + ek.Nonce = data[13:45] + ek.IV = data[45:61] + ek.RSC = binary.BigEndian.Uint64(data[61:69]) + ek.ID = binary.BigEndian.Uint64(data[69:77]) + ek.MIC = data[77:93] + + ek.KeyDataLength = binary.BigEndian.Uint16(data[93:95]) + + totalLength := eapolKeyFrameLen + int(ek.KeyDataLength) + if len(data) < totalLength { + df.SetTruncated() + return fmt.Errorf("EAPOLKey data length %d too short, %d required", + len(data)-eapolKeyFrameLen, ek.KeyDataLength) + } + + if ek.HasEncryptedKeyData { + ek.EncryptedKeyData = data[eapolKeyFrameLen:totalLength] + ek.BaseLayer = BaseLayer{ + Contents: data[:totalLength], + Payload: data[totalLength:], + } + } else { + ek.BaseLayer = BaseLayer{ + Contents: data[:eapolKeyFrameLen], + Payload: data[eapolKeyFrameLen:], + } + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (ek *EAPOLKey) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(eapolKeyFrameLen + len(ek.EncryptedKeyData)) + if err != nil { + return err + } + + buf[0] = byte(ek.KeyDescriptorType) + + var info uint16 + info |= uint16(ek.KeyDescriptorVersion) + info |= uint16(ek.KeyType) << 3 + info |= uint16(ek.KeyIndex) << 4 + if ek.Install { + info |= 0x0040 + } + if ek.KeyACK { + info |= 0x0080 + } + if ek.KeyMIC { + info |= 0x0100 + } + if ek.Secure { + info |= 0x0200 + } + if ek.MICError { + info |= 0x0400 + } + if ek.Request { + info |= 0x0800 + } + if ek.HasEncryptedKeyData { + info |= 0x1000 + } + if ek.SMKMessage { + info |= 0x2000 + } + binary.BigEndian.PutUint16(buf[1:3], info) + + binary.BigEndian.PutUint16(buf[3:5], ek.KeyLength) + binary.BigEndian.PutUint64(buf[5:13], ek.ReplayCounter) + + copy(buf[13:45], ek.Nonce) + copy(buf[45:61], ek.IV) + binary.BigEndian.PutUint64(buf[61:69], ek.RSC) + binary.BigEndian.PutUint64(buf[69:77], ek.ID) + copy(buf[77:93], ek.MIC) + + binary.BigEndian.PutUint16(buf[93:95], ek.KeyDataLength) + if len(ek.EncryptedKeyData) > 0 { + copy(buf[95:95+len(ek.EncryptedKeyData)], ek.EncryptedKeyData) + } + + return nil +} + +func decodeEAPOLKey(data []byte, p gopacket.PacketBuilder) error { + ek := &EAPOLKey{} + return decodingLayerDecoder(ek, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/endpoints.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/endpoints.go new file mode 100644 index 0000000000..f2cec019dc --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/endpoints.go @@ -0,0 +1,98 @@ +// 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 layers + +import ( + "encoding/binary" + "net" + "strconv" + + "github.com/gopacket/gopacket" +) + +var ( + // We use two different endpoint types for IPv4 vs IPv6 addresses, so that + // ordering with endpointA.LessThan(endpointB) sanely groups all IPv4 + // addresses and all IPv6 addresses, such that IPv6 > IPv4 for all addresses. + EndpointIPv4 = gopacket.RegisterEndpointType(1, gopacket.EndpointTypeMetadata{Name: "IPv4", Formatter: func(b []byte) string { + return net.IP(b).String() + }}) + EndpointIPv6 = gopacket.RegisterEndpointType(2, gopacket.EndpointTypeMetadata{Name: "IPv6", Formatter: func(b []byte) string { + return net.IP(b).String() + }}) + + EndpointMAC = gopacket.RegisterEndpointType(3, gopacket.EndpointTypeMetadata{Name: "MAC", Formatter: func(b []byte) string { + return net.HardwareAddr(b).String() + }}) + EndpointTCPPort = gopacket.RegisterEndpointType(4, gopacket.EndpointTypeMetadata{Name: "TCP", Formatter: func(b []byte) string { + return strconv.Itoa(int(binary.BigEndian.Uint16(b))) + }}) + EndpointUDPPort = gopacket.RegisterEndpointType(5, gopacket.EndpointTypeMetadata{Name: "UDP", Formatter: func(b []byte) string { + return strconv.Itoa(int(binary.BigEndian.Uint16(b))) + }}) + EndpointSCTPPort = gopacket.RegisterEndpointType(6, gopacket.EndpointTypeMetadata{Name: "SCTP", Formatter: func(b []byte) string { + return strconv.Itoa(int(binary.BigEndian.Uint16(b))) + }}) + EndpointRUDPPort = gopacket.RegisterEndpointType(7, gopacket.EndpointTypeMetadata{Name: "RUDP", Formatter: func(b []byte) string { + return strconv.Itoa(int(b[0])) + }}) + EndpointUDPLitePort = gopacket.RegisterEndpointType(8, gopacket.EndpointTypeMetadata{Name: "UDPLite", Formatter: func(b []byte) string { + return strconv.Itoa(int(binary.BigEndian.Uint16(b))) + }}) + EndpointPPP = gopacket.RegisterEndpointType(9, gopacket.EndpointTypeMetadata{Name: "PPP", Formatter: func([]byte) string { + return "point" + }}) +) + +// NewIPEndpoint creates a new IP (v4 or v6) endpoint from a net.IP address. +// It returns gopacket.InvalidEndpoint if the IP address is invalid. +func NewIPEndpoint(a net.IP) gopacket.Endpoint { + ipv4 := a.To4() + if ipv4 != nil { + return gopacket.NewEndpoint(EndpointIPv4, []byte(ipv4)) + } + + ipv6 := a.To16() + if ipv6 != nil { + return gopacket.NewEndpoint(EndpointIPv6, []byte(ipv6)) + } + + return gopacket.InvalidEndpoint +} + +// NewMACEndpoint returns a new MAC address endpoint. +func NewMACEndpoint(a net.HardwareAddr) gopacket.Endpoint { + return gopacket.NewEndpoint(EndpointMAC, []byte(a)) +} +func newPortEndpoint(t gopacket.EndpointType, p uint16) gopacket.Endpoint { + return gopacket.NewEndpoint(t, []byte{byte(p >> 8), byte(p)}) +} + +// NewTCPPortEndpoint returns an endpoint based on a TCP port. +func NewTCPPortEndpoint(p TCPPort) gopacket.Endpoint { + return newPortEndpoint(EndpointTCPPort, uint16(p)) +} + +// NewUDPPortEndpoint returns an endpoint based on a UDP port. +func NewUDPPortEndpoint(p UDPPort) gopacket.Endpoint { + return newPortEndpoint(EndpointUDPPort, uint16(p)) +} + +// NewSCTPPortEndpoint returns an endpoint based on a SCTP port. +func NewSCTPPortEndpoint(p SCTPPort) gopacket.Endpoint { + return newPortEndpoint(EndpointSCTPPort, uint16(p)) +} + +// NewRUDPPortEndpoint returns an endpoint based on a RUDP port. +func NewRUDPPortEndpoint(p RUDPPort) gopacket.Endpoint { + return gopacket.NewEndpoint(EndpointRUDPPort, []byte{byte(p)}) +} + +// NewUDPLitePortEndpoint returns an endpoint based on a UDPLite port. +func NewUDPLitePortEndpoint(p UDPLitePort) gopacket.Endpoint { + return newPortEndpoint(EndpointUDPLitePort, uint16(p)) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enip.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enip.go new file mode 100644 index 0000000000..86e2f8e218 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enip.go @@ -0,0 +1,229 @@ +// Copyright 2018, 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. +// +//****************************************************************************** + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +//****************************************************************************** +// +// ENIP (Ethernet/IP) Decoding Layer +// ------------------------------------------ +// This file provides a GoPacket decoding layer for ENIP (Ethernet/IP). +// Ethernet/IP is an industrial protocol that encapsulates CIP (Common Industrial Protocol) +// +//****************************************************************************** + +const enipHeaderSize = 24 + +// ENIPCommand represents the command code in an ENIP packet +type ENIPCommand uint16 + +// ENIP Command codes +const ( + ENIPCommandNOP ENIPCommand = 0x0000 + ENIPCommandListServices ENIPCommand = 0x0004 + ENIPCommandListIdentity ENIPCommand = 0x0063 + ENIPCommandListInterfaces ENIPCommand = 0x0064 + ENIPCommandRegisterSession ENIPCommand = 0x0065 + ENIPCommandUnregisterSession ENIPCommand = 0x0066 + ENIPCommandSendRRData ENIPCommand = 0x006F + ENIPCommandSendUnitData ENIPCommand = 0x0070 + ENIPCommandIndicateStatus ENIPCommand = 0x0072 + ENIPCommandCancel ENIPCommand = 0x0073 +) + +func (ec ENIPCommand) String() string { + switch ec { + case ENIPCommandNOP: + return "NOP" + case ENIPCommandListServices: + return "ListServices" + case ENIPCommandListIdentity: + return "ListIdentity" + case ENIPCommandListInterfaces: + return "ListInterfaces" + case ENIPCommandRegisterSession: + return "RegisterSession" + case ENIPCommandUnregisterSession: + return "UnregisterSession" + case ENIPCommandSendRRData: + return "SendRRData" + case ENIPCommandSendUnitData: + return "SendUnitData" + case ENIPCommandIndicateStatus: + return "IndicateStatus" + case ENIPCommandCancel: + return "Cancel" + default: + return fmt.Sprintf("Unknown Command (0x%04x)", uint16(ec)) + } +} + +// ENIPStatus represents the status code in an ENIP packet +type ENIPStatus uint32 + +// ENIP Status codes +const ( + ENIPStatusSuccess ENIPStatus = 0x0000 + ENIPStatusInvalidCommand ENIPStatus = 0x0001 + ENIPStatusInsufficientMemory ENIPStatus = 0x0002 + ENIPStatusIncorrectData ENIPStatus = 0x0003 + ENIPStatusInvalidSessionHandle ENIPStatus = 0x0064 + ENIPStatusInvalidLength ENIPStatus = 0x0065 + ENIPStatusUnsupportedProtocol ENIPStatus = 0x0069 +) + +func (es ENIPStatus) String() string { + switch es { + case ENIPStatusSuccess: + return "Success" + case ENIPStatusInvalidCommand: + return "Invalid Command" + case ENIPStatusInsufficientMemory: + return "Insufficient Memory" + case ENIPStatusIncorrectData: + return "Incorrect Data" + case ENIPStatusInvalidSessionHandle: + return "Invalid Session Handle" + case ENIPStatusInvalidLength: + return "Invalid Length" + case ENIPStatusUnsupportedProtocol: + return "Unsupported Protocol" + default: + return fmt.Sprintf("Unknown Status (0x%08x)", uint32(es)) + } +} + +//****************************************************************************** + +// ENIP represents an Ethernet/IP packet +type ENIP struct { + BaseLayer + + Command ENIPCommand // Command code + Length uint16 // Length of data portion in bytes + SessionHandle uint32 // Session identification + Status ENIPStatus // Status code + SenderContext uint64 // Sender context + Options uint32 // Options flags +} + +//****************************************************************************** + +// LayerType returns the layer type of the ENIP object +func (e *ENIP) LayerType() gopacket.LayerType { + return LayerTypeENIP +} + +//****************************************************************************** + +// decodeENIP analyses a byte slice and attempts to decode it as an ENIP packet +func decodeENIP(data []byte, p gopacket.PacketBuilder) error { + enip := &ENIP{} + err := enip.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(enip) + p.SetApplicationLayer(enip) + return p.NextDecoder(enip.NextLayerType()) +} + +//****************************************************************************** + +// DecodeFromBytes analyses a byte slice and attempts to decode it as an ENIP packet +func (e *ENIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < enipHeaderSize { + df.SetTruncated() + return errors.New("ENIP packet too short") + } + + // Parse ENIP header + e.Command = ENIPCommand(binary.LittleEndian.Uint16(data[0:2])) + e.Length = binary.LittleEndian.Uint16(data[2:4]) + e.SessionHandle = binary.LittleEndian.Uint32(data[4:8]) + e.Status = ENIPStatus(binary.LittleEndian.Uint32(data[8:12])) + + // Sender context is 8 bytes at offset 12 + e.SenderContext = binary.LittleEndian.Uint64(data[12:20]) + + e.Options = binary.LittleEndian.Uint32(data[20:24]) + + // Check if we have enough data for the payload + totalLength := enipHeaderSize + int(e.Length) + if len(data) < totalLength { + df.SetTruncated() + return fmt.Errorf("ENIP packet truncated: expected %d bytes, got %d", totalLength, len(data)) + } + + e.BaseLayer = BaseLayer{ + Contents: data[:enipHeaderSize], + Payload: data[enipHeaderSize:totalLength], + } + + return nil +} + +//****************************************************************************** + +// NextLayerType returns the layer type of the ENIP payload +// For SendRRData and SendUnitData commands, the payload typically contains CIP data +func (e *ENIP) NextLayerType() gopacket.LayerType { + // Commands that typically contain CIP data + switch e.Command { + case ENIPCommandSendRRData, ENIPCommandSendUnitData: + // The payload contains CIP encapsulation, but we'll simplify and try to decode as CIP + // In reality, SendRRData and SendUnitData have additional encapsulation headers + // For now, we'll just return CIP and let it handle what it can + if len(e.Payload()) > 0 { + return LayerTypeCIP + } + } + return gopacket.LayerTypePayload +} + +//****************************************************************************** + +// Payload returns the ENIP payload bytes +func (e *ENIP) Payload() []byte { + return e.BaseLayer.Payload +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode +func (e *ENIP) CanDecode() gopacket.LayerClass { + return LayerTypeENIP +} + +// SerializeTo writes the serialized form of this layer into the SerializationBuffer +func (e *ENIP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(enipHeaderSize) + if err != nil { + return err + } + + binary.LittleEndian.PutUint16(bytes[0:2], uint16(e.Command)) + + if opts.FixLengths { + e.Length = uint16(len(b.Bytes()) - enipHeaderSize) + } + binary.LittleEndian.PutUint16(bytes[2:4], e.Length) + + binary.LittleEndian.PutUint32(bytes[4:8], e.SessionHandle) + binary.LittleEndian.PutUint32(bytes[8:12], uint32(e.Status)) + binary.LittleEndian.PutUint64(bytes[12:20], e.SenderContext) + binary.LittleEndian.PutUint32(bytes[20:24], e.Options) + + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums.go new file mode 100644 index 0000000000..7d6f9cee80 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums.go @@ -0,0 +1,452 @@ +// 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 layers + +import ( + "fmt" + "runtime" + + "github.com/gopacket/gopacket" +) + +// EnumMetadata keeps track of a set of metadata for each enumeration value +// for protocol enumerations. +type EnumMetadata struct { + // DecodeWith is the decoder to use to decode this protocol's data. + DecodeWith gopacket.Decoder + // Name is the name of the enumeration value. + Name string + // LayerType is the layer type implied by the given enum. + LayerType gopacket.LayerType +} + +// EthernetType is an enumeration of ethernet type values, and acts as a decoder +// for any type it supports. +type EthernetType uint16 + +const ( + // EthernetTypeLLC is not an actual ethernet type. It is instead a + // placeholder we use in Ethernet frames that use the 802.3 standard of + // srcmac|dstmac|length|LLC instead of srcmac|dstmac|ethertype. + EthernetTypeLLC EthernetType = 0 + EthernetTypeIPv4 EthernetType = 0x0800 + EthernetTypeARP EthernetType = 0x0806 + EthernetTypeIPv6 EthernetType = 0x86DD + EthernetTypeCiscoDiscovery EthernetType = 0x2000 + EthernetTypeNortelDiscovery EthernetType = 0x01a2 + EthernetTypeTransparentEthernetBridging EthernetType = 0x6558 + EthernetTypeMerakiDiscoveryProtocol EthernetType = 0x712 + EthernetTypeDot1Q EthernetType = 0x8100 + EthernetTypePPP EthernetType = 0x880b + EthernetTypePPPoEDiscovery EthernetType = 0x8863 + EthernetTypePPPoESession EthernetType = 0x8864 + EthernetTypeMPLSUnicast EthernetType = 0x8847 + EthernetTypeMPLSMulticast EthernetType = 0x8848 + EthernetTypeEAPOL EthernetType = 0x888e + EthernetTypeQinQ EthernetType = 0x88a8 + EthernetTypeERSPAN EthernetType = 0x88be + EthernetTypeLinkLayerDiscovery EthernetType = 0x88cc + EthernetTypeEthernetCTP EthernetType = 0x9000 + EthernetTypeRaw EthernetType = 0xFFFF // Special case for raw IP +) + +// IPProtocol is an enumeration of IP protocol values, and acts as a decoder +// for any type it supports. +type IPProtocol uint8 + +const ( + IPProtocolIPv6HopByHop IPProtocol = 0 + IPProtocolICMPv4 IPProtocol = 1 + IPProtocolIGMP IPProtocol = 2 + IPProtocolIPv4 IPProtocol = 4 + IPProtocolTCP IPProtocol = 6 + IPProtocolUDP IPProtocol = 17 + IPProtocolRUDP IPProtocol = 27 + IPProtocolIPv6 IPProtocol = 41 + IPProtocolIPv6Routing IPProtocol = 43 + IPProtocolIPv6Fragment IPProtocol = 44 + IPProtocolGRE IPProtocol = 47 + IPProtocolESP IPProtocol = 50 + IPProtocolAH IPProtocol = 51 + IPProtocolICMPv6 IPProtocol = 58 + IPProtocolNoNextHeader IPProtocol = 59 + IPProtocolIPv6Destination IPProtocol = 60 + IPProtocolOSPF IPProtocol = 89 + IPProtocolIPIP IPProtocol = 94 + IPProtocolEtherIP IPProtocol = 97 + IPProtocolVRRP IPProtocol = 112 + IPProtocolSCTP IPProtocol = 132 + IPProtocolUDPLite IPProtocol = 136 + IPProtocolMPLSInIP IPProtocol = 137 +) + +// LinkType is an enumeration of link types, and acts as a decoder for any +// link type it supports. +type LinkType uint16 + +const ( + // According to pcap-linktype(7) and http://www.tcpdump.org/linktypes.html + LinkTypeNull LinkType = iota + LinkTypeEthernet LinkType = 1 + LinkTypeAX25 LinkType = 3 + LinkTypeTokenRing LinkType = 6 + LinkTypeArcNet LinkType = 7 + LinkTypeSLIP LinkType = 8 + LinkTypePPP LinkType = 9 + LinkTypeFDDI LinkType = 10 + LinkTypePPP_HDLC LinkType = 50 + LinkTypePPPEthernet LinkType = 51 + LinkTypeATM_RFC1483 LinkType = 100 + LinkTypeRaw LinkType = 101 + LinkTypeC_HDLC LinkType = 104 + LinkTypeIEEE802_11 LinkType = 105 + LinkTypeFRelay LinkType = 107 + LinkTypeLoop LinkType = 108 + LinkTypeLinuxSLL LinkType = 113 + LinkTypeLTalk LinkType = 114 + LinkTypePFLog LinkType = 117 + LinkTypePrismHeader LinkType = 119 + LinkTypeIPOverFC LinkType = 122 + LinkTypeSunATM LinkType = 123 + LinkTypeIEEE80211Radio LinkType = 127 + LinkTypeARCNetLinux LinkType = 129 + LinkTypeIPOver1394 LinkType = 138 + LinkTypeMTP2Phdr LinkType = 139 + LinkTypeMTP2 LinkType = 140 + LinkTypeMTP3 LinkType = 141 + LinkTypeSCCP LinkType = 142 + LinkTypeDOCSIS LinkType = 143 + LinkTypeLinuxIRDA LinkType = 144 + LinkTypeLinuxLAPD LinkType = 177 + LinkTypeLinuxUSB LinkType = 220 + LinkTypeFC2 LinkType = 224 + LinkTypeFC2Framed LinkType = 225 + LinkTypeIPv4 LinkType = 228 + LinkTypeIPv6 LinkType = 229 + LinkTypeLinuxSLL2 LinkType = 276 + + // Warning: this const should always be 1 larger than the largest valid value + LinkTypeMax LinkType = 277 +) + +// PPPoECode is the PPPoE code enum, taken from http://tools.ietf.org/html/rfc2516 +type PPPoECode uint8 + +const ( + PPPoECodePADI PPPoECode = 0x09 + PPPoECodePADO PPPoECode = 0x07 + PPPoECodePADR PPPoECode = 0x19 + PPPoECodePADS PPPoECode = 0x65 + PPPoECodePADT PPPoECode = 0xA7 + PPPoECodeSession PPPoECode = 0x00 +) + +// PPPType is an enumeration of PPP type values, and acts as a decoder for any +// type it supports. +type PPPType uint16 + +const ( + PPPTypeIPv4 PPPType = 0x0021 + PPPTypeIPv6 PPPType = 0x0057 + PPPTypeMPLSUnicast PPPType = 0x0281 + PPPTypeMPLSMulticast PPPType = 0x0283 +) + +// SCTPChunkType is an enumeration of chunk types inside SCTP packets. +type SCTPChunkType uint8 + +const ( + SCTPChunkTypeData SCTPChunkType = 0 + SCTPChunkTypeInit SCTPChunkType = 1 + SCTPChunkTypeInitAck SCTPChunkType = 2 + SCTPChunkTypeSack SCTPChunkType = 3 + SCTPChunkTypeHeartbeat SCTPChunkType = 4 + SCTPChunkTypeHeartbeatAck SCTPChunkType = 5 + SCTPChunkTypeAbort SCTPChunkType = 6 + SCTPChunkTypeShutdown SCTPChunkType = 7 + SCTPChunkTypeShutdownAck SCTPChunkType = 8 + SCTPChunkTypeError SCTPChunkType = 9 + SCTPChunkTypeCookieEcho SCTPChunkType = 10 + SCTPChunkTypeCookieAck SCTPChunkType = 11 + SCTPChunkTypeShutdownComplete SCTPChunkType = 14 +) + +// FDDIFrameControl is an enumeration of FDDI frame control bytes. +type FDDIFrameControl uint8 + +const ( + FDDIFrameControlLLC FDDIFrameControl = 0x50 +) + +// EAPOLType is an enumeration of EAPOL packet types. +type EAPOLType uint8 + +const ( + EAPOLTypeEAP EAPOLType = 0 + EAPOLTypeStart EAPOLType = 1 + EAPOLTypeLogOff EAPOLType = 2 + EAPOLTypeKey EAPOLType = 3 + EAPOLTypeASFAlert EAPOLType = 4 +) + +// ProtocolFamily is the set of values defined as PF_* in sys/socket.h +type ProtocolFamily uint8 + +const ( + ProtocolFamilyIPv4 ProtocolFamily = 2 + // BSDs use different values for INET6... glory be. These values taken from + // tcpdump 4.3.0. + ProtocolFamilyIPv6BSD ProtocolFamily = 24 + ProtocolFamilyIPv6FreeBSD ProtocolFamily = 28 + ProtocolFamilyIPv6Darwin ProtocolFamily = 30 + ProtocolFamilyIPv6Linux ProtocolFamily = 10 +) + +// Dot11Type is a combination of IEEE 802.11 frame's Type and Subtype fields. +// By combining these two fields together into a single type, we're able to +// provide a String function that correctly displays the subtype given the +// top-level type. +// +// If you just care about the top-level type, use the MainType function. +type Dot11Type uint8 + +// MainType strips the subtype information from the given type, +// returning just the overarching type (Mgmt, Ctrl, Data, Reserved). +func (d Dot11Type) MainType() Dot11Type { + return d & dot11TypeMask +} + +func (d Dot11Type) QOS() bool { + return d&dot11QOSMask == Dot11TypeDataQOSData +} + +const ( + Dot11TypeMgmt Dot11Type = 0x00 + Dot11TypeCtrl Dot11Type = 0x01 + Dot11TypeData Dot11Type = 0x02 + Dot11TypeReserved Dot11Type = 0x03 + dot11TypeMask = 0x03 + dot11QOSMask = 0x23 + + // The following are type/subtype conglomerations. + + // Management + Dot11TypeMgmtAssociationReq Dot11Type = 0x00 + Dot11TypeMgmtAssociationResp Dot11Type = 0x04 + Dot11TypeMgmtReassociationReq Dot11Type = 0x08 + Dot11TypeMgmtReassociationResp Dot11Type = 0x0c + Dot11TypeMgmtProbeReq Dot11Type = 0x10 + Dot11TypeMgmtProbeResp Dot11Type = 0x14 + Dot11TypeMgmtMeasurementPilot Dot11Type = 0x18 + Dot11TypeMgmtBeacon Dot11Type = 0x20 + Dot11TypeMgmtATIM Dot11Type = 0x24 + Dot11TypeMgmtDisassociation Dot11Type = 0x28 + Dot11TypeMgmtAuthentication Dot11Type = 0x2c + Dot11TypeMgmtDeauthentication Dot11Type = 0x30 + Dot11TypeMgmtAction Dot11Type = 0x34 + Dot11TypeMgmtActionNoAck Dot11Type = 0x38 + + // Control + Dot11TypeCtrlWrapper Dot11Type = 0x1d + Dot11TypeCtrlBlockAckReq Dot11Type = 0x21 + Dot11TypeCtrlBlockAck Dot11Type = 0x25 + Dot11TypeCtrlPowersavePoll Dot11Type = 0x29 + Dot11TypeCtrlRTS Dot11Type = 0x2d + Dot11TypeCtrlCTS Dot11Type = 0x31 + Dot11TypeCtrlAck Dot11Type = 0x35 + Dot11TypeCtrlCFEnd Dot11Type = 0x39 + Dot11TypeCtrlCFEndAck Dot11Type = 0x3d + + // Data + Dot11TypeDataCFAck Dot11Type = 0x06 + Dot11TypeDataCFPoll Dot11Type = 0x0a + Dot11TypeDataCFAckPoll Dot11Type = 0x0e + Dot11TypeDataNull Dot11Type = 0x12 + Dot11TypeDataCFAckNoData Dot11Type = 0x16 + Dot11TypeDataCFPollNoData Dot11Type = 0x1a + Dot11TypeDataCFAckPollNoData Dot11Type = 0x1e + Dot11TypeDataQOSData Dot11Type = 0x22 + Dot11TypeDataQOSDataCFAck Dot11Type = 0x26 + Dot11TypeDataQOSDataCFPoll Dot11Type = 0x2a + Dot11TypeDataQOSDataCFAckPoll Dot11Type = 0x2e + Dot11TypeDataQOSNull Dot11Type = 0x32 + Dot11TypeDataQOSCFPollNoData Dot11Type = 0x3a + Dot11TypeDataQOSCFAckPollNoData Dot11Type = 0x3e +) + +// Decode a raw v4 or v6 IP packet. +func decodeIPv4or6(data []byte, p gopacket.PacketBuilder) error { + version := data[0] >> 4 + switch version { + case 4: + return decodeIPv4(data, p) + case 6: + return decodeIPv6(data, p) + } + return fmt.Errorf("Invalid IP packet version %v", version) +} + +func initActualTypeData() { + // Each of the XXXTypeMetadata arrays contains mappings of how to handle enum + // values for various enum types in gopacket/layers. + // These arrays are actually created by gen2.go and stored in + // enums_generated.go. + // + // So, EthernetTypeMetadata[2] contains information on how to handle EthernetType + // 2, including which name to give it and which decoder to use to decode + // packet data of that type. These arrays are filled by default with all of the + // protocols gopacket/layers knows how to handle, but users of the library can + // add new decoders or override existing ones. For example, if you write a better + // TCP decoder, you can override IPProtocolMetadata[IPProtocolTCP].DecodeWith + // with your new decoder, and all gopacket/layers decoding will use your new + // decoder whenever they encounter that IPProtocol. + + // Here we link up all enumerations with their respective names and decoders. + EthernetTypeMetadata[EthernetTypeLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC", LayerType: LayerTypeLLC} + EthernetTypeMetadata[EthernetTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4} + EthernetTypeMetadata[EthernetTypeRaw] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "Raw", LayerType: LayerTypeIPv4} + EthernetTypeMetadata[EthernetTypeIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + EthernetTypeMetadata[EthernetTypeARP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeARP), Name: "ARP", LayerType: LayerTypeARP} + EthernetTypeMetadata[EthernetTypeDot1Q] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot1Q), Name: "Dot1Q", LayerType: LayerTypeDot1Q} + EthernetTypeMetadata[EthernetTypePPP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP", LayerType: LayerTypePPP} + EthernetTypeMetadata[EthernetTypePPPoEDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoEDiscovery", LayerType: LayerTypePPPoE} + EthernetTypeMetadata[EthernetTypePPPoESession] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPPoE), Name: "PPPoESession", LayerType: LayerTypePPPoE} + EthernetTypeMetadata[EthernetTypeEthernetCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernetCTP), Name: "EthernetCTP", LayerType: LayerTypeEthernetCTP} + EthernetTypeMetadata[EthernetTypeCiscoDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeCiscoDiscovery), Name: "CiscoDiscovery", LayerType: LayerTypeCiscoDiscovery} + EthernetTypeMetadata[EthernetTypeNortelDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeNortelDiscovery), Name: "NortelDiscovery", LayerType: LayerTypeNortelDiscovery} + EthernetTypeMetadata[EthernetTypeLinkLayerDiscovery] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLinkLayerDiscovery), Name: "LinkLayerDiscovery", LayerType: LayerTypeLinkLayerDiscovery} + EthernetTypeMetadata[EthernetTypeMPLSUnicast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSUnicast", LayerType: LayerTypeMPLS} + EthernetTypeMetadata[EthernetTypeMPLSMulticast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSMulticast", LayerType: LayerTypeMPLS} + EthernetTypeMetadata[EthernetTypeEAPOL] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAPOL), Name: "EAPOL", LayerType: LayerTypeEAPOL} + EthernetTypeMetadata[EthernetTypeQinQ] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot1Q), Name: "Dot1Q", LayerType: LayerTypeDot1Q} + EthernetTypeMetadata[EthernetTypeTransparentEthernetBridging] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernet), Name: "TransparentEthernetBridging", LayerType: LayerTypeEthernet} + EthernetTypeMetadata[EthernetTypeERSPAN] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeERSPANII), Name: "ERSPAN Type II", LayerType: LayerTypeERSPANII} + EthernetTypeMetadata[EthernetTypeMerakiDiscoveryProtocol] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMDP), Name: "MDP", LayerType: LayerTypeMDP} + + IPProtocolMetadata[IPProtocolIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4} + IPProtocolMetadata[IPProtocolTCP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeTCP), Name: "TCP", LayerType: LayerTypeTCP} + IPProtocolMetadata[IPProtocolUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDP), Name: "UDP", LayerType: LayerTypeUDP} + IPProtocolMetadata[IPProtocolICMPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeICMPv4), Name: "ICMPv4", LayerType: LayerTypeICMPv4} + IPProtocolMetadata[IPProtocolICMPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeICMPv6), Name: "ICMPv6", LayerType: LayerTypeICMPv6} + IPProtocolMetadata[IPProtocolSCTP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTP), Name: "SCTP", LayerType: LayerTypeSCTP} + IPProtocolMetadata[IPProtocolIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + IPProtocolMetadata[IPProtocolIPIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4} + IPProtocolMetadata[IPProtocolEtherIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEtherIP), Name: "EtherIP", LayerType: LayerTypeEtherIP} + IPProtocolMetadata[IPProtocolRUDP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRUDP), Name: "RUDP", LayerType: LayerTypeRUDP} + IPProtocolMetadata[IPProtocolGRE] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeGRE), Name: "GRE", LayerType: LayerTypeGRE} + IPProtocolMetadata[IPProtocolIPv6HopByHop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6HopByHop), Name: "IPv6HopByHop", LayerType: LayerTypeIPv6HopByHop} + IPProtocolMetadata[IPProtocolIPv6Routing] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Routing), Name: "IPv6Routing", LayerType: LayerTypeIPv6Routing} + IPProtocolMetadata[IPProtocolIPv6Fragment] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Fragment), Name: "IPv6Fragment", LayerType: LayerTypeIPv6Fragment} + IPProtocolMetadata[IPProtocolIPv6Destination] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6Destination), Name: "IPv6Destination", LayerType: LayerTypeIPv6Destination} + IPProtocolMetadata[IPProtocolOSPF] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeOSPF), Name: "OSPF", LayerType: LayerTypeOSPF} + IPProtocolMetadata[IPProtocolAH] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecAH), Name: "IPSecAH", LayerType: LayerTypeIPSecAH} + IPProtocolMetadata[IPProtocolESP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPSecESP), Name: "IPSecESP", LayerType: LayerTypeIPSecESP} + IPProtocolMetadata[IPProtocolUDPLite] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUDPLite), Name: "UDPLite", LayerType: LayerTypeUDPLite} + IPProtocolMetadata[IPProtocolMPLSInIP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLS", LayerType: LayerTypeMPLS} + IPProtocolMetadata[IPProtocolNoNextHeader] = EnumMetadata{DecodeWith: gopacket.DecodePayload, Name: "NoNextHeader", LayerType: gopacket.LayerTypePayload} + IPProtocolMetadata[IPProtocolIGMP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIGMP), Name: "IGMP", LayerType: LayerTypeIGMP} + IPProtocolMetadata[IPProtocolVRRP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeVRRP), Name: "VRRP", LayerType: LayerTypeVRRP} + + SCTPChunkTypeMetadata[SCTPChunkTypeData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPData), Name: "Data"} + SCTPChunkTypeMetadata[SCTPChunkTypeInit] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPInit), Name: "Init"} + SCTPChunkTypeMetadata[SCTPChunkTypeInitAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPInit), Name: "InitAck"} + SCTPChunkTypeMetadata[SCTPChunkTypeSack] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPSack), Name: "Sack"} + SCTPChunkTypeMetadata[SCTPChunkTypeHeartbeat] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPHeartbeat), Name: "Heartbeat"} + SCTPChunkTypeMetadata[SCTPChunkTypeHeartbeatAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPHeartbeat), Name: "HeartbeatAck"} + SCTPChunkTypeMetadata[SCTPChunkTypeAbort] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPError), Name: "Abort"} + SCTPChunkTypeMetadata[SCTPChunkTypeError] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPError), Name: "Error"} + SCTPChunkTypeMetadata[SCTPChunkTypeShutdown] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPShutdown), Name: "Shutdown"} + SCTPChunkTypeMetadata[SCTPChunkTypeShutdownAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPShutdownAck), Name: "ShutdownAck"} + SCTPChunkTypeMetadata[SCTPChunkTypeCookieEcho] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPCookieEcho), Name: "CookieEcho"} + SCTPChunkTypeMetadata[SCTPChunkTypeCookieAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPEmptyLayer), Name: "CookieAck"} + SCTPChunkTypeMetadata[SCTPChunkTypeShutdownComplete] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeSCTPEmptyLayer), Name: "ShutdownComplete"} + + PPPTypeMetadata[PPPTypeIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4"} + PPPTypeMetadata[PPPTypeIPv6] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6"} + PPPTypeMetadata[PPPTypeMPLSUnicast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSUnicast"} + PPPTypeMetadata[PPPTypeMPLSMulticast] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeMPLS), Name: "MPLSMulticast"} + + PPPoECodeMetadata[PPPoECodeSession] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP"} + + LinkTypeMetadata[LinkTypeEthernet] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEthernet), Name: "Ethernet"} + LinkTypeMetadata[LinkTypePPP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePPP), Name: "PPP"} + LinkTypeMetadata[LinkTypeFDDI] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeFDDI), Name: "FDDI"} + LinkTypeMetadata[LinkTypeNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Null"} + LinkTypeMetadata[LinkTypeIEEE802_11] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11), Name: "Dot11"} + LinkTypeMetadata[LinkTypeLoop] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLoopback), Name: "Loop"} + LinkTypeMetadata[LinkTypeIEEE802_11] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11), Name: "802.11"} + LinkTypeMetadata[LinkTypeRaw] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"} + // See https://github.com/the-tcpdump-group/libpcap/blob/170f717e6e818cdc4bcbbfd906b63088eaa88fa0/pcap/dlt.h#L85 + // Or https://github.com/wireshark/wireshark/blob/854cfe53efe44080609c78053ecfb2342ad84a08/wiretap/pcap-common.c#L508 + if runtime.GOOS == "openbsd" { + LinkTypeMetadata[14] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"} + } else { + LinkTypeMetadata[12] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4or6), Name: "Raw"} + } + LinkTypeMetadata[LinkTypePFLog] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePFLog), Name: "PFLog"} + LinkTypeMetadata[LinkTypeIEEE80211Radio] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeRadioTap), Name: "RadioTap"} + LinkTypeMetadata[LinkTypeLinuxUSB] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSB), Name: "USB"} + LinkTypeMetadata[LinkTypeLinuxSLL] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLinuxSLL), Name: "Linux SLL"} + LinkTypeMetadata[LinkTypePrismHeader] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodePrismHeader), Name: "Prism"} + LinkTypeMetadata[LinkTypeLinuxSLL2] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLinuxSLL2), Name: "Linux SLL2"} + + FDDIFrameControlMetadata[FDDIFrameControlLLC] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeLLC), Name: "LLC"} + + EAPOLTypeMetadata[EAPOLTypeEAP] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAP), Name: "EAP", LayerType: LayerTypeEAP} + EAPOLTypeMetadata[EAPOLTypeKey] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeEAPOLKey), Name: "EAPOLKey", LayerType: LayerTypeEAPOLKey} + + ProtocolFamilyMetadata[ProtocolFamilyIPv4] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv4), Name: "IPv4", LayerType: LayerTypeIPv4} + ProtocolFamilyMetadata[ProtocolFamilyIPv6BSD] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + ProtocolFamilyMetadata[ProtocolFamilyIPv6FreeBSD] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + ProtocolFamilyMetadata[ProtocolFamilyIPv6Darwin] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + ProtocolFamilyMetadata[ProtocolFamilyIPv6Linux] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeIPv6), Name: "IPv6", LayerType: LayerTypeIPv6} + + Dot11TypeMetadata[Dot11TypeMgmtAssociationReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAssociationReq), Name: "MgmtAssociationReq", LayerType: LayerTypeDot11MgmtAssociationReq} + Dot11TypeMetadata[Dot11TypeMgmtAssociationResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAssociationResp), Name: "MgmtAssociationResp", LayerType: LayerTypeDot11MgmtAssociationResp} + Dot11TypeMetadata[Dot11TypeMgmtReassociationReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtReassociationReq), Name: "MgmtReassociationReq", LayerType: LayerTypeDot11MgmtReassociationReq} + Dot11TypeMetadata[Dot11TypeMgmtReassociationResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtReassociationResp), Name: "MgmtReassociationResp", LayerType: LayerTypeDot11MgmtReassociationResp} + Dot11TypeMetadata[Dot11TypeMgmtProbeReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtProbeReq), Name: "MgmtProbeReq", LayerType: LayerTypeDot11MgmtProbeReq} + Dot11TypeMetadata[Dot11TypeMgmtProbeResp] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtProbeResp), Name: "MgmtProbeResp", LayerType: LayerTypeDot11MgmtProbeResp} + Dot11TypeMetadata[Dot11TypeMgmtMeasurementPilot] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtMeasurementPilot), Name: "MgmtMeasurementPilot", LayerType: LayerTypeDot11MgmtMeasurementPilot} + Dot11TypeMetadata[Dot11TypeMgmtBeacon] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtBeacon), Name: "MgmtBeacon", LayerType: LayerTypeDot11MgmtBeacon} + Dot11TypeMetadata[Dot11TypeMgmtATIM] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtATIM), Name: "MgmtATIM", LayerType: LayerTypeDot11MgmtATIM} + Dot11TypeMetadata[Dot11TypeMgmtDisassociation] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtDisassociation), Name: "MgmtDisassociation", LayerType: LayerTypeDot11MgmtDisassociation} + Dot11TypeMetadata[Dot11TypeMgmtAuthentication] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAuthentication), Name: "MgmtAuthentication", LayerType: LayerTypeDot11MgmtAuthentication} + Dot11TypeMetadata[Dot11TypeMgmtDeauthentication] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtDeauthentication), Name: "MgmtDeauthentication", LayerType: LayerTypeDot11MgmtDeauthentication} + Dot11TypeMetadata[Dot11TypeMgmtAction] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtAction), Name: "MgmtAction", LayerType: LayerTypeDot11MgmtAction} + Dot11TypeMetadata[Dot11TypeMgmtActionNoAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11MgmtActionNoAck), Name: "MgmtActionNoAck", LayerType: LayerTypeDot11MgmtActionNoAck} + Dot11TypeMetadata[Dot11TypeCtrl] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Ctrl), Name: "Ctrl", LayerType: LayerTypeDot11Ctrl} + Dot11TypeMetadata[Dot11TypeCtrlWrapper] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Ctrl), Name: "CtrlWrapper", LayerType: LayerTypeDot11Ctrl} + Dot11TypeMetadata[Dot11TypeCtrlBlockAckReq] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlBlockAckReq), Name: "CtrlBlockAckReq", LayerType: LayerTypeDot11CtrlBlockAckReq} + Dot11TypeMetadata[Dot11TypeCtrlBlockAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlBlockAck), Name: "CtrlBlockAck", LayerType: LayerTypeDot11CtrlBlockAck} + Dot11TypeMetadata[Dot11TypeCtrlPowersavePoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlPowersavePoll), Name: "CtrlPowersavePoll", LayerType: LayerTypeDot11CtrlPowersavePoll} + Dot11TypeMetadata[Dot11TypeCtrlRTS] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlRTS), Name: "CtrlRTS", LayerType: LayerTypeDot11CtrlRTS} + Dot11TypeMetadata[Dot11TypeCtrlCTS] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCTS), Name: "CtrlCTS", LayerType: LayerTypeDot11CtrlCTS} + Dot11TypeMetadata[Dot11TypeCtrlAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlAck), Name: "CtrlAck", LayerType: LayerTypeDot11CtrlAck} + Dot11TypeMetadata[Dot11TypeCtrlCFEnd] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCFEnd), Name: "CtrlCFEnd", LayerType: LayerTypeDot11CtrlCFEnd} + Dot11TypeMetadata[Dot11TypeCtrlCFEndAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11CtrlCFEndAck), Name: "CtrlCFEndAck", LayerType: LayerTypeDot11CtrlCFEndAck} + Dot11TypeMetadata[Dot11TypeData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11Data), Name: "Data", LayerType: LayerTypeDot11Data} + Dot11TypeMetadata[Dot11TypeDataCFAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAck), Name: "DataCFAck", LayerType: LayerTypeDot11DataCFAck} + Dot11TypeMetadata[Dot11TypeDataCFPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFPoll), Name: "DataCFPoll", LayerType: LayerTypeDot11DataCFPoll} + Dot11TypeMetadata[Dot11TypeDataCFAckPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckPoll), Name: "DataCFAckPoll", LayerType: LayerTypeDot11DataCFAckPoll} + Dot11TypeMetadata[Dot11TypeDataNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataNull), Name: "DataNull", LayerType: LayerTypeDot11DataNull} + Dot11TypeMetadata[Dot11TypeDataCFAckNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckNoData), Name: "DataCFAckNoData", LayerType: LayerTypeDot11DataCFAckNoData} + Dot11TypeMetadata[Dot11TypeDataCFPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFPollNoData), Name: "DataCFPollNoData", LayerType: LayerTypeDot11DataCFPollNoData} + Dot11TypeMetadata[Dot11TypeDataCFAckPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataCFAckPollNoData), Name: "DataCFAckPollNoData", LayerType: LayerTypeDot11DataCFAckPollNoData} + Dot11TypeMetadata[Dot11TypeDataQOSData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSData), Name: "DataQOSData", LayerType: LayerTypeDot11DataQOSData} + Dot11TypeMetadata[Dot11TypeDataQOSDataCFAck] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAck), Name: "DataQOSDataCFAck", LayerType: LayerTypeDot11DataQOSDataCFAck} + Dot11TypeMetadata[Dot11TypeDataQOSDataCFPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFPoll), Name: "DataQOSDataCFPoll", LayerType: LayerTypeDot11DataQOSDataCFPoll} + Dot11TypeMetadata[Dot11TypeDataQOSDataCFAckPoll] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAckPoll), Name: "DataQOSDataCFAckPoll", LayerType: LayerTypeDot11DataQOSDataCFAckPoll} + Dot11TypeMetadata[Dot11TypeDataQOSNull] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSNull), Name: "DataQOSNull", LayerType: LayerTypeDot11DataQOSNull} + Dot11TypeMetadata[Dot11TypeDataQOSCFPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSCFPollNoData), Name: "DataQOSCFPollNoData", LayerType: LayerTypeDot11DataQOSCFPollNoData} + Dot11TypeMetadata[Dot11TypeDataQOSCFAckPollNoData] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeDot11DataQOSCFAckPollNoData), Name: "DataQOSCFAckPollNoData", LayerType: LayerTypeDot11DataQOSCFAckPollNoData} + + USBTransportTypeMetadata[USBTransportTypeInterrupt] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBInterrupt), Name: "Interrupt", LayerType: LayerTypeUSBInterrupt} + USBTransportTypeMetadata[USBTransportTypeControl] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBControl), Name: "Control", LayerType: LayerTypeUSBControl} + USBTransportTypeMetadata[USBTransportTypeBulk] = EnumMetadata{DecodeWith: gopacket.DecodeFunc(decodeUSBBulk), Name: "Bulk", LayerType: LayerTypeUSBBulk} +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums_generated.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums_generated.go new file mode 100644 index 0000000000..64f5bf3800 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/enums_generated.go @@ -0,0 +1,401 @@ +// Copyright 2012 Google, Inc. All rights reserved. + +package layers + +// Created by gen2.go, don't edit manually +// Generated at 2023-09-26 15:45:59.728838421 +0400 +04 m=+0.000090902 + +import ( + "fmt" + + "github.com/gopacket/gopacket" +) + +func init() { + initActualTypeData() +} + +// Decoder calls LinkTypeMetadata.DecodeWith's decoder. +func (a LinkType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 277 { + if metadata := LinkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode LinkType %d", a) +} + +// String returns LinkTypeMetadata.Name. +func (a LinkType) String() string { + if int(a) < 277 { + if metadata := LinkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownLinkType" +} + +// LayerType returns LinkTypeMetadata.LayerType. +func (a LinkType) LayerType() gopacket.LayerType { + if int(a) < 277 { + if metadata := LinkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var LinkTypeMetadata [277]EnumMetadata + +// Decoder calls EthernetTypeMetadata.DecodeWith's decoder. +func (a EthernetType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 65536 { + if metadata := EthernetTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode EthernetType %d", a) +} + +// String returns EthernetTypeMetadata.Name. +func (a EthernetType) String() string { + if int(a) < 65536 { + if metadata := EthernetTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownEthernetType" +} + +// LayerType returns EthernetTypeMetadata.LayerType. +func (a EthernetType) LayerType() gopacket.LayerType { + if int(a) < 65536 { + if metadata := EthernetTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var EthernetTypeMetadata [65536]EnumMetadata + +// Decoder calls PPPTypeMetadata.DecodeWith's decoder. +func (a PPPType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 65536 { + if metadata := PPPTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode PPPType %d", a) +} + +// String returns PPPTypeMetadata.Name. +func (a PPPType) String() string { + if int(a) < 65536 { + if metadata := PPPTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownPPPType" +} + +// LayerType returns PPPTypeMetadata.LayerType. +func (a PPPType) LayerType() gopacket.LayerType { + if int(a) < 65536 { + if metadata := PPPTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var PPPTypeMetadata [65536]EnumMetadata + +// Decoder calls IPProtocolMetadata.DecodeWith's decoder. +func (a IPProtocol) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := IPProtocolMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode IPProtocol %d", a) +} + +// String returns IPProtocolMetadata.Name. +func (a IPProtocol) String() string { + if int(a) < 256 { + if metadata := IPProtocolMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownIPProtocol" +} + +// LayerType returns IPProtocolMetadata.LayerType. +func (a IPProtocol) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := IPProtocolMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var IPProtocolMetadata [256]EnumMetadata + +// Decoder calls SCTPChunkTypeMetadata.DecodeWith's decoder. +func (a SCTPChunkType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := SCTPChunkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode SCTPChunkType %d", a) +} + +// String returns SCTPChunkTypeMetadata.Name. +func (a SCTPChunkType) String() string { + if int(a) < 256 { + if metadata := SCTPChunkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownSCTPChunkType" +} + +// LayerType returns SCTPChunkTypeMetadata.LayerType. +func (a SCTPChunkType) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := SCTPChunkTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var SCTPChunkTypeMetadata [256]EnumMetadata + +// Decoder calls PPPoECodeMetadata.DecodeWith's decoder. +func (a PPPoECode) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := PPPoECodeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode PPPoECode %d", a) +} + +// String returns PPPoECodeMetadata.Name. +func (a PPPoECode) String() string { + if int(a) < 256 { + if metadata := PPPoECodeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownPPPoECode" +} + +// LayerType returns PPPoECodeMetadata.LayerType. +func (a PPPoECode) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := PPPoECodeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var PPPoECodeMetadata [256]EnumMetadata + +// Decoder calls FDDIFrameControlMetadata.DecodeWith's decoder. +func (a FDDIFrameControl) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := FDDIFrameControlMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode FDDIFrameControl %d", a) +} + +// String returns FDDIFrameControlMetadata.Name. +func (a FDDIFrameControl) String() string { + if int(a) < 256 { + if metadata := FDDIFrameControlMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownFDDIFrameControl" +} + +// LayerType returns FDDIFrameControlMetadata.LayerType. +func (a FDDIFrameControl) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := FDDIFrameControlMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var FDDIFrameControlMetadata [256]EnumMetadata + +// Decoder calls EAPOLTypeMetadata.DecodeWith's decoder. +func (a EAPOLType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := EAPOLTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode EAPOLType %d", a) +} + +// String returns EAPOLTypeMetadata.Name. +func (a EAPOLType) String() string { + if int(a) < 256 { + if metadata := EAPOLTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownEAPOLType" +} + +// LayerType returns EAPOLTypeMetadata.LayerType. +func (a EAPOLType) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := EAPOLTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var EAPOLTypeMetadata [256]EnumMetadata + +// Decoder calls ProtocolFamilyMetadata.DecodeWith's decoder. +func (a ProtocolFamily) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := ProtocolFamilyMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode ProtocolFamily %d", a) +} + +// String returns ProtocolFamilyMetadata.Name. +func (a ProtocolFamily) String() string { + if int(a) < 256 { + if metadata := ProtocolFamilyMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownProtocolFamily" +} + +// LayerType returns ProtocolFamilyMetadata.LayerType. +func (a ProtocolFamily) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := ProtocolFamilyMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var ProtocolFamilyMetadata [256]EnumMetadata + +// Decoder calls Dot11TypeMetadata.DecodeWith's decoder. +func (a Dot11Type) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := Dot11TypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode Dot11Type %d", a) +} + +// String returns Dot11TypeMetadata.Name. +func (a Dot11Type) String() string { + if int(a) < 256 { + if metadata := Dot11TypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownDot11Type" +} + +// LayerType returns Dot11TypeMetadata.LayerType. +func (a Dot11Type) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := Dot11TypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var Dot11TypeMetadata [256]EnumMetadata + +// Decoder calls USBTransportTypeMetadata.DecodeWith's decoder. +func (a USBTransportType) Decode(data []byte, p gopacket.PacketBuilder) error { + if int(a) < 256 { + if metadata := USBTransportTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.DecodeWith.Decode(data, p) + } + } + + return fmt.Errorf("Unable to decode USBTransportType %d", a) +} + +// String returns USBTransportTypeMetadata.Name. +func (a USBTransportType) String() string { + if int(a) < 256 { + if metadata := USBTransportTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.Name + } + } + + return "UnknownUSBTransportType" +} + +// LayerType returns USBTransportTypeMetadata.LayerType. +func (a USBTransportType) LayerType() gopacket.LayerType { + if int(a) < 256 { + if metadata := USBTransportTypeMetadata[a]; metadata.DecodeWith != nil { + return metadata.LayerType + } + } + + return 0 +} + +var USBTransportTypeMetadata [256]EnumMetadata diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/erspan2.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/erspan2.go new file mode 100644 index 0000000000..dae2b30c8e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/erspan2.go @@ -0,0 +1,86 @@ +// Copyright 2018 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 layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +const ( + //ERSPANIIVersionObsolete - The obsolete value for the version field + ERSPANIIVersionObsolete = 0x0 + // ERSPANIIVersion - The current value for the version field + ERSPANIIVersion = 0x1 +) + +// ERSPANII contains all of the fields found in an ERSPAN Type II header +// https://tools.ietf.org/html/draft-foschiano-erspan-03 +type ERSPANII struct { + BaseLayer + IsTruncated bool + Version, CoS, TrunkEncap uint8 + VLANIdentifier, SessionID, Reserved uint16 + Index uint32 +} + +func (erspan2 *ERSPANII) LayerType() gopacket.LayerType { return LayerTypeERSPANII } + +// DecodeFromBytes decodes the given bytes into this layer. +func (erspan2 *ERSPANII) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + erspan2Length := 8 + erspan2.Version = data[0] & 0xF0 >> 4 + erspan2.VLANIdentifier = binary.BigEndian.Uint16(data[:2]) & 0x0FFF + erspan2.CoS = data[2] & 0xE0 >> 5 + erspan2.TrunkEncap = data[2] & 0x18 >> 3 + erspan2.IsTruncated = data[2]&0x4>>2 != 0 + erspan2.SessionID = binary.BigEndian.Uint16(data[2:4]) & 0x03FF + erspan2.Reserved = binary.BigEndian.Uint16(data[4:6]) & 0xFFF0 >> 4 + erspan2.Index = binary.BigEndian.Uint32(data[4:8]) & 0x000FFFFF + erspan2.Contents = data[:erspan2Length] + erspan2.Payload = data[erspan2Length:] + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (erspan2 *ERSPANII) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + + twoByteInt := uint16(erspan2.Version&0xF)<<12 | erspan2.VLANIdentifier&0x0FFF + binary.BigEndian.PutUint16(bytes, twoByteInt) + + twoByteInt = uint16(erspan2.CoS&0x7)<<13 | uint16(erspan2.TrunkEncap&0x3)<<11 | erspan2.SessionID&0x03FF + if erspan2.IsTruncated { + twoByteInt |= 0x400 + } + binary.BigEndian.PutUint16(bytes[2:], twoByteInt) + + fourByteInt := uint32(erspan2.Reserved&0x0FFF)<<20 | erspan2.Index&0x000FFFFF + binary.BigEndian.PutUint32(bytes[4:], fourByteInt) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (erspan2 *ERSPANII) CanDecode() gopacket.LayerClass { + return LayerTypeERSPANII +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (erspan2 *ERSPANII) NextLayerType() gopacket.LayerType { + return LayerTypeEthernet +} + +func decodeERSPANII(data []byte, p gopacket.PacketBuilder) error { + erspan2 := &ERSPANII{} + return decodingLayerDecoder(erspan2, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/etherip.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/etherip.go new file mode 100644 index 0000000000..d290e3036e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/etherip.go @@ -0,0 +1,46 @@ +// 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 layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +// EtherIP is the struct for storing RFC 3378 EtherIP packet headers. +type EtherIP struct { + BaseLayer + Version uint8 + Reserved uint16 +} + +// LayerType returns gopacket.LayerTypeEtherIP. +func (e *EtherIP) LayerType() gopacket.LayerType { return LayerTypeEtherIP } + +// DecodeFromBytes decodes the given bytes into this layer. +func (e *EtherIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + e.Version = data[0] >> 4 + e.Reserved = binary.BigEndian.Uint16(data[:2]) & 0x0fff + e.BaseLayer = BaseLayer{data[:2], data[2:]} + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (e *EtherIP) CanDecode() gopacket.LayerClass { + return LayerTypeEtherIP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (e *EtherIP) NextLayerType() gopacket.LayerType { + return LayerTypeEthernet +} + +func decodeEtherIP(data []byte, p gopacket.PacketBuilder) error { + e := &EtherIP{} + return decodingLayerDecoder(e, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ethernet.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ethernet.go new file mode 100644 index 0000000000..eb787a40ef --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ethernet.go @@ -0,0 +1,124 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// EthernetBroadcast is the broadcast MAC address used by Ethernet. +var EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + +// Ethernet is the layer for Ethernet frame headers. +type Ethernet struct { + BaseLayer + SrcMAC, DstMAC net.HardwareAddr + EthernetType EthernetType + // Length is only set if a length field exists within this header. Ethernet + // headers follow two different standards, one that uses an EthernetType, the + // other which defines a length the follows with a LLC header (802.3). If the + // former is the case, we set EthernetType and Length stays 0. In the latter + // case, we set Length and EthernetType = EthernetTypeLLC. + Length uint16 +} + +// LayerType returns LayerTypeEthernet +func (e *Ethernet) LayerType() gopacket.LayerType { return LayerTypeEthernet } + +func (e *Ethernet) LinkFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointMAC, e.SrcMAC, e.DstMAC) +} + +func (eth *Ethernet) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 14 { + return errors.New("Ethernet packet too small") + } + eth.DstMAC = net.HardwareAddr(data[0:6]) + eth.SrcMAC = net.HardwareAddr(data[6:12]) + eth.EthernetType = EthernetType(binary.BigEndian.Uint16(data[12:14])) + eth.BaseLayer = BaseLayer{data[:14], data[14:]} + eth.Length = 0 + if eth.EthernetType < 0x0600 { + eth.Length = uint16(eth.EthernetType) + eth.EthernetType = EthernetTypeLLC + if cmp := len(eth.Payload) - int(eth.Length); cmp < 0 { + df.SetTruncated() + } else if cmp > 0 { + // Strip off bytes at the end, since we have too many bytes + eth.Payload = eth.Payload[:len(eth.Payload)-cmp] + } + // fmt.Println(eth) + } + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (eth *Ethernet) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if len(eth.DstMAC) != 6 { + return fmt.Errorf("invalid dst MAC: %v", eth.DstMAC) + } + if len(eth.SrcMAC) != 6 { + return fmt.Errorf("invalid src MAC: %v", eth.SrcMAC) + } + payload := b.Bytes() + bytes, err := b.PrependBytes(14) + if err != nil { + return err + } + copy(bytes, eth.DstMAC) + copy(bytes[6:], eth.SrcMAC) + if eth.Length != 0 || eth.EthernetType == EthernetTypeLLC { + if opts.FixLengths { + eth.Length = uint16(len(payload)) + } + if eth.EthernetType != EthernetTypeLLC { + return fmt.Errorf("ethernet type %v not compatible with length value %v", eth.EthernetType, eth.Length) + } else if eth.Length > 0x0600 { + return fmt.Errorf("invalid ethernet length %v", eth.Length) + } + binary.BigEndian.PutUint16(bytes[12:], eth.Length) + } else { + binary.BigEndian.PutUint16(bytes[12:], uint16(eth.EthernetType)) + } + length := len(b.Bytes()) + if length < 60 { + // Pad out to 60 bytes. + padding, err := b.AppendBytes(60 - length) + if err != nil { + return err + } + copy(padding, lotsOfZeros[:]) + } + return nil +} + +func (eth *Ethernet) CanDecode() gopacket.LayerClass { + return LayerTypeEthernet +} + +func (eth *Ethernet) NextLayerType() gopacket.LayerType { + return eth.EthernetType.LayerType() +} + +func decodeEthernet(data []byte, p gopacket.PacketBuilder) error { + eth := &Ethernet{} + err := eth.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(eth) + p.SetLinkLayer(eth) + return p.NextDecoder(eth.EthernetType) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fddi.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fddi.go new file mode 100644 index 0000000000..a99bdd0042 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fddi.go @@ -0,0 +1,42 @@ +// 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 layers + +import ( + "net" + + "github.com/gopacket/gopacket" +) + +// FDDI contains the header for FDDI frames. +type FDDI struct { + BaseLayer + FrameControl FDDIFrameControl + Priority uint8 + SrcMAC, DstMAC net.HardwareAddr +} + +// LayerType returns LayerTypeFDDI. +func (f *FDDI) LayerType() gopacket.LayerType { return LayerTypeFDDI } + +// LinkFlow returns a new flow of type EndpointMAC. +func (f *FDDI) LinkFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointMAC, f.SrcMAC, f.DstMAC) +} + +func decodeFDDI(data []byte, p gopacket.PacketBuilder) error { + f := &FDDI{ + FrameControl: FDDIFrameControl(data[0] & 0xF8), + Priority: data[0] & 0x07, + SrcMAC: net.HardwareAddr(data[1:7]), + DstMAC: net.HardwareAddr(data[7:13]), + BaseLayer: BaseLayer{data[:13], data[13:]}, + } + p.SetLinkLayer(f) + p.AddLayer(f) + return p.NextDecoder(f.FrameControl) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fuzz_layer.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fuzz_layer.go new file mode 100644 index 0000000000..3f6a8f65b1 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/fuzz_layer.go @@ -0,0 +1,39 @@ +// 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. + +package layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +// FuzzLayer is a fuzz target for the layers package of gopacket +// A fuzz target is a function processing a binary blob (byte slice) +// The process here is to interpret this data as a packet, and print the layers contents. +// The decoding options and the starting layer are encoded in the first bytes. +// The function returns 1 if this is a valid packet (no error layer) +func FuzzLayer(data []byte) int { + if len(data) < 3 { + return 0 + } + // use the first two bytes to choose the top level layer + startLayer := binary.BigEndian.Uint16(data[:2]) + var fuzzOpts = gopacket.DecodeOptions{ + Lazy: data[2]&0x1 != 0, + NoCopy: data[2]&0x2 != 0, + SkipDecodeRecovery: data[2]&0x4 != 0, + DecodeStreamsAsDatagrams: data[2]&0x8 != 0, + } + p := gopacket.NewPacket(data[3:], gopacket.LayerType(startLayer), fuzzOpts) + for _, l := range p.Layers() { + gopacket.LayerString(l) + } + if p.ErrorLayer() != nil { + return 0 + } + return 1 +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gen_linted.sh b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gen_linted.sh new file mode 100644 index 0000000000..75c701f4d5 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gen_linted.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +for i in *.go; do golint $i | grep -q . || echo $i; done > .linted diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/geneve.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/geneve.go new file mode 100644 index 0000000000..bb1318a454 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/geneve.go @@ -0,0 +1,202 @@ +// Copyright 2016 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// Geneve is specifed here https://tools.ietf.org/html/draft-ietf-nvo3-geneve-03 +// Geneve Header: +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |Ver| Opt Len |O|C| Rsvd. | Protocol Type | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Virtual Network Identifier (VNI) | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Variable Length Options | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +type Geneve struct { + BaseLayer + Version uint8 // 2 bits + OptionsLength uint8 // 6 bits + OAMPacket bool // 1 bits + CriticalOption bool // 1 bits + Protocol EthernetType // 16 bits + VNI uint32 // 24bits + Options []*GeneveOption +} + +// Geneve Tunnel Options +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Option Class | Type |R|R|R| Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Variable Option Data | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +type GeneveOption struct { + Class uint16 // 16 bits + Type uint8 // 8 bits + Flags uint8 // 3 bits + Length uint8 // 5 bits + Data []byte +} + +// ensure Geneve implements DecodingLayer. +var _ gopacket.DecodingLayer = (*Geneve)(nil) + +// LayerType returns LayerTypeGeneve +func (gn *Geneve) LayerType() gopacket.LayerType { return LayerTypeGeneve } + +func decodeGeneveOption(data []byte, gn *Geneve, df gopacket.DecodeFeedback) (*GeneveOption, uint8, error) { + if len(data) < 3 { + df.SetTruncated() + return nil, 0, errors.New("geneve option too small") + } + opt := &GeneveOption{} + + opt.Class = binary.BigEndian.Uint16(data[0:2]) + opt.Type = data[2] + opt.Flags = data[3] >> 5 + opt.Length = (data[3]&0x1f)*4 + 4 + + if len(data) < int(opt.Length) { + df.SetTruncated() + return nil, 0, errors.New("geneve option too small") + } + opt.Data = make([]byte, opt.Length-4) + copy(opt.Data, data[4:opt.Length]) + + return opt, opt.Length, nil +} + +func (gn *Geneve) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 7 { + df.SetTruncated() + return errors.New("geneve packet too short") + } + + gn.Version = data[0] >> 7 + gn.OptionsLength = (data[0] & 0x3f) * 4 + + gn.OAMPacket = data[1]&0x80 > 0 + gn.CriticalOption = data[1]&0x40 > 0 + gn.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) + + var buf [4]byte + copy(buf[1:], data[4:7]) + gn.VNI = binary.BigEndian.Uint32(buf[:]) + + offset, length := uint8(8), int32(gn.OptionsLength) + if len(data) < int(length+7) { + df.SetTruncated() + return errors.New("geneve packet too short") + } + + for length > 0 { + opt, len, err := decodeGeneveOption(data[offset:], gn, df) + if err != nil { + return err + } + gn.Options = append(gn.Options, opt) + + length -= int32(len) + offset += len + } + + gn.BaseLayer = BaseLayer{data[:offset], data[offset:]} + + return nil +} + +func (gn *Geneve) NextLayerType() gopacket.LayerType { + return gn.Protocol.LayerType() +} + +func decodeGeneve(data []byte, p gopacket.PacketBuilder) error { + gn := &Geneve{} + return decodingLayerDecoder(gn, data, p) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var optionsLength int + for _, o := range gn.Options { + dataLen := len(o.Data) & ^3 + optionsLength += 4 + dataLen + } + if opts.FixLengths { + gn.OptionsLength = uint8(optionsLength) + } + + plen := int(8 + optionsLength) + bytes, err := b.PrependBytes(plen) + if err != nil { + return err + } + + // PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero + bytes[0] = 0 + bytes[1] = 0 + + // Construct Geneve + + bytes[0] |= gn.Version << 6 + bytes[0] |= ((gn.OptionsLength >> 2) & 0x3f) + + if gn.OAMPacket { + bytes[1] |= 0x80 + } + + if gn.CriticalOption { + bytes[1] |= 0x40 + } + + binary.BigEndian.PutUint16(bytes[2:4], uint16(gn.Protocol)) + + if gn.VNI >= 1<<24 { + return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", gn.VNI) + } + binary.BigEndian.PutUint32(bytes[4:8], gn.VNI<<8) + + // Construct Options + + offset := 8 + for _, o := range gn.Options { + dataLen := len(o.Data) & ^3 + if opts.FixLengths { + o.Length = uint8(4 + dataLen) + } + + binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class)) + + offset += 2 + bytes[offset] = o.Type + + offset += 1 + bytes[offset] = o.Flags << 5 + bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f + + offset += 1 + copy(bytes[offset:(offset+dataLen)], o.Data) + + offset += dataLen + } + + return nil +} + +// CanDecode implements DecodingLayer. +func (gn *Geneve) CanDecode() gopacket.LayerClass { + return LayerTypeGeneve +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gre.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gre.go new file mode 100644 index 0000000000..308166cc11 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gre.go @@ -0,0 +1,214 @@ +// 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 layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +// GRE is a Generic Routing Encapsulation header. +type GRE struct { + BaseLayer + ChecksumPresent, RoutingPresent, KeyPresent, SeqPresent, StrictSourceRoute, AckPresent bool + RecursionControl, Flags, Version uint8 + Protocol EthernetType + Checksum, Offset uint16 + Key, Seq, Ack uint32 + *GRERouting +} + +// GRERouting is GRE routing information, present if the RoutingPresent flag is +// set. +type GRERouting struct { + AddressFamily uint16 + SREOffset, SRELength uint8 + RoutingInformation []byte + Next *GRERouting +} + +// LayerType returns gopacket.LayerTypeGRE. +func (g *GRE) LayerType() gopacket.LayerType { return LayerTypeGRE } + +// DecodeFromBytes decodes the given bytes into this layer. +func (g *GRE) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + g.ChecksumPresent = data[0]&0x80 != 0 + g.RoutingPresent = data[0]&0x40 != 0 + g.KeyPresent = data[0]&0x20 != 0 + g.SeqPresent = data[0]&0x10 != 0 + g.StrictSourceRoute = data[0]&0x08 != 0 + g.AckPresent = data[1]&0x80 != 0 + g.RecursionControl = data[0] & 0x7 + g.Flags = data[1] >> 3 + g.Version = data[1] & 0x7 + g.Protocol = EthernetType(binary.BigEndian.Uint16(data[2:4])) + offset := 4 + if g.ChecksumPresent || g.RoutingPresent { + g.Checksum = binary.BigEndian.Uint16(data[offset : offset+2]) + g.Offset = binary.BigEndian.Uint16(data[offset+2 : offset+4]) + offset += 4 + } + if g.KeyPresent { + g.Key = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + if g.SeqPresent { + g.Seq = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + if g.RoutingPresent { + tail := &g.GRERouting + for { + sre := &GRERouting{ + AddressFamily: binary.BigEndian.Uint16(data[offset : offset+2]), + SREOffset: data[offset+2], + SRELength: data[offset+3], + } + sre.RoutingInformation = data[offset+4 : offset+4+int(sre.SRELength)] + offset += 4 + int(sre.SRELength) + if sre.AddressFamily == 0 && sre.SRELength == 0 { + break + } + (*tail) = sre + tail = &sre.Next + } + } + if g.AckPresent { + g.Ack = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + } + g.BaseLayer = BaseLayer{data[:offset], data[offset:]} + return nil +} + +// SerializeTo writes the serialized form of this layer into the SerializationBuffer, +// implementing gopacket.SerializableLayer. See the docs for gopacket.SerializableLayer for more info. +func (g *GRE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + size := 4 + if g.ChecksumPresent || g.RoutingPresent { + size += 4 + } + if g.KeyPresent { + size += 4 + } + if g.SeqPresent { + size += 4 + } + if g.RoutingPresent { + r := g.GRERouting + for r != nil { + size += 4 + int(r.SRELength) + r = r.Next + } + size += 4 + } + if g.AckPresent { + size += 4 + } + buf, err := b.PrependBytes(size) + if err != nil { + return err + } + // Reset any potentially dirty memory in the first 2 bytes, as these use OR to set flags. + buf[0] = 0 + buf[1] = 0 + if g.ChecksumPresent { + buf[0] |= 0x80 + } + if g.RoutingPresent { + buf[0] |= 0x40 + } + if g.KeyPresent { + buf[0] |= 0x20 + } + if g.SeqPresent { + buf[0] |= 0x10 + } + if g.StrictSourceRoute { + buf[0] |= 0x08 + } + if g.AckPresent { + buf[1] |= 0x80 + } + buf[0] |= g.RecursionControl + buf[1] |= g.Flags << 3 + buf[1] |= g.Version + binary.BigEndian.PutUint16(buf[2:4], uint16(g.Protocol)) + offset := 4 + if g.ChecksumPresent || g.RoutingPresent { + // Don't write the checksum value yet, as we may need to compute it, + // which requires the entire header be complete. + // Instead we zeroize the memory in case it is dirty. + buf[offset] = 0 + buf[offset+1] = 0 + binary.BigEndian.PutUint16(buf[offset+2:offset+4], g.Offset) + offset += 4 + } + if g.KeyPresent { + binary.BigEndian.PutUint32(buf[offset:offset+4], g.Key) + offset += 4 + } + if g.SeqPresent { + binary.BigEndian.PutUint32(buf[offset:offset+4], g.Seq) + offset += 4 + } + if g.RoutingPresent { + sre := g.GRERouting + for sre != nil { + binary.BigEndian.PutUint16(buf[offset:offset+2], sre.AddressFamily) + buf[offset+2] = sre.SREOffset + buf[offset+3] = sre.SRELength + copy(buf[offset+4:offset+4+int(sre.SRELength)], sre.RoutingInformation) + offset += 4 + int(sre.SRELength) + sre = sre.Next + } + // Terminate routing field with a "NULL" SRE. + binary.BigEndian.PutUint32(buf[offset:offset+4], 0) + } + if g.AckPresent { + binary.BigEndian.PutUint32(buf[offset:offset+4], g.Ack) + offset += 4 + } + if g.ChecksumPresent { + if opts.ComputeChecksums { + csum := gopacket.ComputeChecksum(b.Bytes(), 0) + g.Checksum = gopacket.FoldChecksum(csum) + } + + binary.BigEndian.PutUint16(buf[4:6], g.Checksum) + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (g *GRE) CanDecode() gopacket.LayerClass { + return LayerTypeGRE +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (g *GRE) NextLayerType() gopacket.LayerType { + return g.Protocol.LayerType() +} + +func (g *GRE) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + bytes := append(g.Contents, g.Payload...) + + existing := g.Checksum + verification := gopacket.ComputeChecksum(bytes, 0) + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: !g.ChecksumPresent || correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} + +func decodeGRE(data []byte, p gopacket.PacketBuilder) error { + g := &GRE{} + return decodingLayerDecoder(g, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp.go new file mode 100644 index 0000000000..f2bc5464e0 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp.go @@ -0,0 +1,200 @@ +// Copyright 2017 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +const gtpMinimumSizeInBytes int = 8 + +// GTPExtensionHeader is used to carry extra data and enable future extensions of the GTP without the need to use another version number. +type GTPExtensionHeader struct { + Type uint8 + Content []byte +} + +// GTPv1U protocol is used to exchange user data over GTP tunnels across the Sx interfaces. +// Defined in https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1595 +type GTPv1U struct { + BaseLayer + Version uint8 + ProtocolType uint8 + Reserved uint8 + ExtensionHeaderFlag bool + SequenceNumberFlag bool + NPDUFlag bool + MessageType uint8 + MessageLength uint16 + TEID uint32 + SequenceNumber uint16 + NPDU uint8 + GTPExtensionHeaders []GTPExtensionHeader +} + +// LayerType returns LayerTypeGTPV1U +func (g *GTPv1U) LayerType() gopacket.LayerType { return LayerTypeGTPv1U } + +// DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv1U packet +func (g *GTPv1U) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + hLen := gtpMinimumSizeInBytes + dLen := len(data) + if dLen < hLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + g.Version = (data[0] >> 5) & 0x07 + g.ProtocolType = (data[0] >> 4) & 0x01 + g.Reserved = (data[0] >> 3) & 0x01 + g.SequenceNumberFlag = ((data[0] >> 1) & 0x01) == 1 + g.NPDUFlag = (data[0] & 0x01) == 1 + g.ExtensionHeaderFlag = ((data[0] >> 2) & 0x01) == 1 + g.MessageType = data[1] + g.MessageLength = binary.BigEndian.Uint16(data[2:4]) + pLen := 8 + g.MessageLength + if uint16(dLen) < pLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + // Field used to multiplex different connections in the same GTP tunnel. + g.TEID = binary.BigEndian.Uint32(data[4:8]) + cIndex := uint16(hLen) + if g.SequenceNumberFlag || g.NPDUFlag || g.ExtensionHeaderFlag { + hLen += 4 + cIndex += 4 + if dLen < hLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + if g.SequenceNumberFlag { + g.SequenceNumber = binary.BigEndian.Uint16(data[8:10]) + } + if g.NPDUFlag { + g.NPDU = data[10] + } + if g.ExtensionHeaderFlag { + extensionFlag := true + for extensionFlag { + extensionType := uint8(data[cIndex-1]) + extensionLength := uint(data[cIndex]) + if extensionLength == 0 { + return fmt.Errorf("GTP packet with invalid extension header") + } + // extensionLength is in 4-octet units + lIndex := cIndex + (uint16(extensionLength) * 4) + if uint16(dLen) < lIndex { + return fmt.Errorf("GTP packet with small extension header: %d bytes", dLen) + } + content := data[cIndex+1 : lIndex-1] + eh := GTPExtensionHeader{Type: extensionType, Content: content} + g.GTPExtensionHeaders = append(g.GTPExtensionHeaders, eh) + cIndex = lIndex + // Check if coming bytes are from an extension header + extensionFlag = data[cIndex-1] != 0 + + } + } + } + g.BaseLayer = BaseLayer{Contents: data[:cIndex], Payload: data[cIndex:]} + return nil + +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (g *GTPv1U) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var nextExtensionHeaderType byte + for i := len(g.GTPExtensionHeaders) - 1; i >= 0; i-- { + g.ExtensionHeaderFlag = true + eh := g.GTPExtensionHeaders[i] + lContent := len(eh.Content) + if lContent%4 != 2 { + return fmt.Errorf("GTP packet extension header %d has invalid length: %d bytes", i, lContent) + } + + data, err := b.PrependBytes(lContent + 2) // two extra bytes for length and next extension header type + if err != nil { + return err + } + + data[0] = byte((lContent + 2) / 4) // in 4-octet units + data[lContent+1] = nextExtensionHeaderType + copy(data[1:lContent+1], eh.Content) + + nextExtensionHeaderType = eh.Type + } + + if g.ExtensionHeaderFlag || g.SequenceNumberFlag || g.NPDUFlag { + data, err := b.PrependBytes(4) + if err != nil { + return err + } + + binary.BigEndian.PutUint16(data[:2], g.SequenceNumber) + data[2] = g.NPDU + data[3] = nextExtensionHeaderType + } + + if opts.FixLengths { + g.MessageLength = uint16(len(b.Bytes())) + } + + data, err := b.PrependBytes(gtpMinimumSizeInBytes) + if err != nil { + return err + } + data[0] = (g.Version << 5) + data[0] |= (1 << 4) + if g.ExtensionHeaderFlag { + data[0] |= 0x04 + } + if g.SequenceNumberFlag { + data[0] |= 0x02 + } + if g.NPDUFlag { + data[0] |= 0x01 + } + data[1] = g.MessageType + binary.BigEndian.PutUint16(data[2:4], g.MessageLength) + binary.BigEndian.PutUint32(data[4:8], g.TEID) + return nil +} + +// CanDecode returns a set of layers that GTP objects can decode. +func (g *GTPv1U) CanDecode() gopacket.LayerClass { + return LayerTypeGTPv1U +} + +// NextLayerType specifies the next layer that GoPacket should attempt to +func (g *GTPv1U) NextLayerType() gopacket.LayerType { + if len(g.LayerPayload()) == 0 { + return gopacket.LayerTypeZero + } + if g.MessageType != 255 { + return gopacket.LayerTypePayload + } + version := uint8(g.LayerPayload()[0]) >> 4 + if version == 4 { + return LayerTypeIPv4 + } else if version == 6 { + return LayerTypeIPv6 + } else { + return LayerTypePPP + } +} + +func decodeGTPv1u(data []byte, p gopacket.PacketBuilder) error { + gtp := >Pv1U{} + err := gtp.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(gtp) + return p.NextDecoder(gtp.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp2.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp2.go new file mode 100644 index 0000000000..05f1cc5350 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/gtp2.go @@ -0,0 +1,123 @@ +package layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +const gtp2MinimumSizeInBytes int = 4 + +// IE represents an Information Element in GTPv2, a key component for message structure +type IE struct { + Type uint8 + Content []byte +} + +// GTPv2 is designed for the control plane of the Evolved Packet System, +// facilitating various control and mobility management messages between gateways and MME/S-GW. +// Defined in the 3GPP TS 29.274 specification +type GTPv2 struct { + BaseLayer + Version uint8 + PiggybackingFlag bool + TEIDflag bool + MessagePriority uint8 + MessageType uint8 + MessageLength uint16 + TEID uint32 + SequenceNumber uint32 + Spare uint8 + IEs []IE +} + +// DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv2 packet +func (g *GTPv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + hLen := gtp2MinimumSizeInBytes + dLen := len(data) + if dLen < hLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + g.Version = (data[0] >> 5) & 0x07 + g.PiggybackingFlag = ((data[0] >> 4) & 0x01) == 1 + g.TEIDflag = ((data[0] >> 3) & 0x01) == 1 + g.MessagePriority = (data[0] >> 2) & 0x01 + g.MessageType = data[1] + g.MessageLength = binary.BigEndian.Uint16(data[2:4]) + + pLen := 4 + g.MessageLength + if uint16(dLen) < pLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + + cIndex := uint16(hLen) + if g.TEIDflag { + hLen += 4 + cIndex += 4 + if dLen < hLen { + return fmt.Errorf("GTP packet too small: %d bytes", dLen) + } + g.TEID = binary.BigEndian.Uint32(data[4:8]) + } + + if len(data) < int(cIndex)+3 { + return fmt.Errorf("GTP packet too small for SequenceNumber: %d bytes", len(data)) + } + g.SequenceNumber = uint32(data[cIndex])<<16 | uint32(data[cIndex+1])<<8 | uint32(data[cIndex+2]) + g.Spare = data[cIndex+3] + hLen += 4 + cIndex += 4 + + for cIndex < uint16(dLen) { + ieType := data[cIndex] + ieLength := binary.BigEndian.Uint16(data[cIndex+1 : cIndex+3]) + if cIndex+4+uint16(ieLength) > uint16(dLen) { + return fmt.Errorf("IE %d exceeds packet length", ieType) + } + ieContent := data[cIndex+4 : cIndex+4+uint16(ieLength)] + g.IEs = append(g.IEs, IE{Type: ieType, Content: ieContent}) + cIndex += 4 + uint16(ieLength) + } + + g.BaseLayer = BaseLayer{Contents: data[:cIndex], Payload: data[cIndex:]} + return nil + +} + +// decodeGTPv2 is a utility function to facilitate the decoding of GTPv2 packets within GoPacket's framework +func decodeGTPv2(data []byte, p gopacket.PacketBuilder) error { + gtp := >Pv2{} + + if err := gtp.DecodeFromBytes(data, p); err != nil { + return err + } + + p.AddLayer(gtp) + return p.NextDecoder(gtp.NextLayerType()) +} + +// LayerType returns LayerTypeGTPv2 +func (g *GTPv2) LayerType() gopacket.LayerType { + return LayerTypeGTPv2 +} + +// LayerContents returns the contents of the GTPv2 layer. +func (g *GTPv2) LayerContents() []byte { + return g.Contents +} + +// LayerPayload returns the payload of the GTPv2 layer. +func (g *GTPv2) LayerPayload() []byte { + return g.Payload +} + +// CanDecode returns a set of layers that GTP objects can decode +func (g *GTPv2) CanDecode() gopacket.LayerClass { + return LayerTypeGTPv2 +} + +// NextLayerType specifies the next layer that GoPacket should attempt to +func (g *GTPv2) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/iana_ports.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/iana_ports.go new file mode 100644 index 0000000000..73e892227e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/iana_ports.go @@ -0,0 +1,22944 @@ +// Copyright 2012 Google, Inc. All rights reserved. + +package layers + +// Created by gen.go, don't edit manually +// Generated at 2023-07-28 17:00:37.114586196 +0400 +04 m=+2.218439472 +// Fetched from "http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml" + +// TCPPortNames contains the port names for all TCP ports. +func TCPPortNames(port TCPPort) (string, bool) { + switch port { + case 1: + return "tcpmux", true + case 2: + return "compressnet", true + case 3: + return "compressnet", true + case 5: + return "rje", true + case 7: + return "echo", true + case 9: + return "discard", true + case 11: + return "systat", true + case 13: + return "daytime", true + case 17: + return "qotd", true + case 18: + return "msp", true + case 19: + return "chargen", true + case 20: + return "ftp-data", true + case 21: + return "ftp", true + case 22: + return "ssh", true + case 23: + return "telnet", true + case 25: + return "smtp", true + case 27: + return "nsw-fe", true + case 29: + return "msg-icp", true + case 31: + return "msg-auth", true + case 33: + return "dsp", true + case 37: + return "time", true + case 38: + return "rap", true + case 39: + return "rlp", true + case 41: + return "graphics", true + case 42: + return "name", true + case 43: + return "nicname", true + case 44: + return "mpm-flags", true + case 45: + return "mpm", true + case 46: + return "mpm-snd", true + case 48: + return "auditd", true + case 49: + return "tacacs", true + case 50: + return "re-mail-ck", true + case 52: + return "xns-time", true + case 53: + return "domain", true + case 54: + return "xns-ch", true + case 55: + return "isi-gl", true + case 56: + return "xns-auth", true + case 58: + return "xns-mail", true + case 62: + return "acas", true + case 63: + return "whoispp", true + case 64: + return "covia", true + case 65: + return "tacacs-ds", true + case 66: + return "sql-net", true + case 67: + return "bootps", true + case 68: + return "bootpc", true + case 69: + return "tftp", true + case 70: + return "gopher", true + case 71: + return "netrjs-1", true + case 72: + return "netrjs-2", true + case 73: + return "netrjs-3", true + case 74: + return "netrjs-4", true + case 76: + return "deos", true + case 78: + return "vettcp", true + case 79: + return "finger", true + case 80: + return "http", true + case 82: + return "xfer", true + case 83: + return "mit-ml-dev", true + case 84: + return "ctf", true + case 85: + return "mit-ml-dev", true + case 86: + return "mfcobol", true + case 88: + return "kerberos", true + case 89: + return "su-mit-tg", true + case 90: + return "dnsix", true + case 91: + return "mit-dov", true + case 92: + return "npp", true + case 93: + return "dcp", true + case 94: + return "objcall", true + case 95: + return "supdup", true + case 96: + return "dixie", true + case 97: + return "swift-rvf", true + case 98: + return "tacnews", true + case 99: + return "metagram", true + case 101: + return "hostname", true + case 102: + return "iso-tsap", true + case 103: + return "gppitnp", true + case 104: + return "acr-nema", true + case 105: + return "cso", true + case 106: + return "3com-tsmux", true + case 107: + return "rtelnet", true + case 108: + return "snagas", true + case 109: + return "pop2", true + case 110: + return "pop3", true + case 111: + return "sunrpc", true + case 112: + return "mcidas", true + case 113: + return "ident", true + case 115: + return "sftp", true + case 116: + return "ansanotify", true + case 117: + return "uucp-path", true + case 118: + return "sqlserv", true + case 119: + return "nntp", true + case 120: + return "cfdptkt", true + case 121: + return "erpc", true + case 122: + return "smakynet", true + case 123: + return "ntp", true + case 124: + return "ansatrader", true + case 125: + return "locus-map", true + case 126: + return "nxedit", true + case 127: + return "locus-con", true + case 128: + return "gss-xlicen", true + case 129: + return "pwdgen", true + case 130: + return "cisco-fna", true + case 131: + return "cisco-tna", true + case 132: + return "cisco-sys", true + case 133: + return "statsrv", true + case 134: + return "ingres-net", true + case 135: + return "epmap", true + case 136: + return "profile", true + case 137: + return "netbios-ns", true + case 138: + return "netbios-dgm", true + case 139: + return "netbios-ssn", true + case 140: + return "emfis-data", true + case 141: + return "emfis-cntl", true + case 142: + return "bl-idm", true + case 143: + return "imap", true + case 144: + return "uma", true + case 145: + return "uaac", true + case 146: + return "iso-tp0", true + case 147: + return "iso-ip", true + case 148: + return "jargon", true + case 149: + return "aed-512", true + case 150: + return "sql-net", true + case 151: + return "hems", true + case 152: + return "bftp", true + case 153: + return "sgmp", true + case 154: + return "netsc-prod", true + case 155: + return "netsc-dev", true + case 156: + return "sqlsrv", true + case 157: + return "knet-cmp", true + case 158: + return "pcmail-srv", true + case 159: + return "nss-routing", true + case 160: + return "sgmp-traps", true + case 161: + return "snmp", true + case 162: + return "snmptrap", true + case 163: + return "cmip-man", true + case 164: + return "cmip-agent", true + case 165: + return "xns-courier", true + case 166: + return "s-net", true + case 167: + return "namp", true + case 168: + return "rsvd", true + case 169: + return "send", true + case 170: + return "print-srv", true + case 171: + return "multiplex", true + case 172: + return "cl-1", true + case 173: + return "xyplex-mux", true + case 174: + return "mailq", true + case 175: + return "vmnet", true + case 176: + return "genrad-mux", true + case 177: + return "xdmcp", true + case 178: + return "nextstep", true + case 179: + return "bgp", true + case 180: + return "ris", true + case 181: + return "unify", true + case 182: + return "audit", true + case 183: + return "ocbinder", true + case 184: + return "ocserver", true + case 185: + return "remote-kis", true + case 186: + return "kis", true + case 187: + return "aci", true + case 188: + return "mumps", true + case 189: + return "qft", true + case 190: + return "gacp", true + case 191: + return "prospero", true + case 192: + return "osu-nms", true + case 193: + return "srmp", true + case 194: + return "irc", true + case 195: + return "dn6-nlm-aud", true + case 196: + return "dn6-smm-red", true + case 197: + return "dls", true + case 198: + return "dls-mon", true + case 199: + return "smux", true + case 200: + return "src", true + case 201: + return "at-rtmp", true + case 202: + return "at-nbp", true + case 203: + return "at-3", true + case 204: + return "at-echo", true + case 205: + return "at-5", true + case 206: + return "at-zis", true + case 207: + return "at-7", true + case 208: + return "at-8", true + case 209: + return "qmtp", true + case 210: + return "z39-50", true + case 211: + return "914c-g", true + case 212: + return "anet", true + case 213: + return "ipx", true + case 214: + return "vmpwscs", true + case 215: + return "softpc", true + case 216: + return "CAIlic", true + case 217: + return "dbase", true + case 218: + return "mpp", true + case 219: + return "uarps", true + case 220: + return "imap3", true + case 221: + return "fln-spx", true + case 222: + return "rsh-spx", true + case 223: + return "cdc", true + case 224: + return "masqdialer", true + case 242: + return "direct", true + case 243: + return "sur-meas", true + case 244: + return "inbusiness", true + case 245: + return "link", true + case 246: + return "dsp3270", true + case 247: + return "subntbcst-tftp", true + case 248: + return "bhfhs", true + case 256: + return "rap", true + case 257: + return "set", true + case 259: + return "esro-gen", true + case 260: + return "openport", true + case 261: + return "nsiiops", true + case 262: + return "arcisdms", true + case 263: + return "hdap", true + case 264: + return "bgmp", true + case 265: + return "x-bone-ctl", true + case 266: + return "sst", true + case 267: + return "td-service", true + case 268: + return "td-replica", true + case 269: + return "manet", true + case 271: + return "pt-tls", true + case 280: + return "http-mgmt", true + case 281: + return "personal-link", true + case 282: + return "cableport-ax", true + case 283: + return "rescap", true + case 284: + return "corerjd", true + case 286: + return "fxp", true + case 287: + return "k-block", true + case 308: + return "novastorbakcup", true + case 309: + return "entrusttime", true + case 310: + return "bhmds", true + case 311: + return "asip-webadmin", true + case 312: + return "vslmp", true + case 313: + return "magenta-logic", true + case 314: + return "opalis-robot", true + case 315: + return "dpsi", true + case 316: + return "decauth", true + case 317: + return "zannet", true + case 318: + return "pkix-timestamp", true + case 319: + return "ptp-event", true + case 320: + return "ptp-general", true + case 321: + return "pip", true + case 322: + return "rtsps", true + case 323: + return "rpki-rtr", true + case 324: + return "rpki-rtr-tls", true + case 333: + return "texar", true + case 344: + return "pdap", true + case 345: + return "pawserv", true + case 346: + return "zserv", true + case 347: + return "fatserv", true + case 348: + return "csi-sgwp", true + case 349: + return "mftp", true + case 350: + return "matip-type-a", true + case 351: + return "matip-type-b", true + case 352: + return "dtag-ste-sb", true + case 353: + return "ndsauth", true + case 354: + return "bh611", true + case 355: + return "datex-asn", true + case 356: + return "cloanto-net-1", true + case 357: + return "bhevent", true + case 358: + return "shrinkwrap", true + case 359: + return "nsrmp", true + case 360: + return "scoi2odialog", true + case 361: + return "semantix", true + case 362: + return "srssend", true + case 363: + return "rsvp-tunnel", true + case 364: + return "aurora-cmgr", true + case 365: + return "dtk", true + case 366: + return "odmr", true + case 367: + return "mortgageware", true + case 368: + return "qbikgdp", true + case 369: + return "rpc2portmap", true + case 370: + return "codaauth2", true + case 371: + return "clearcase", true + case 372: + return "ulistproc", true + case 373: + return "legent-1", true + case 374: + return "legent-2", true + case 375: + return "hassle", true + case 376: + return "nip", true + case 377: + return "tnETOS", true + case 378: + return "dsETOS", true + case 379: + return "is99c", true + case 380: + return "is99s", true + case 381: + return "hp-collector", true + case 382: + return "hp-managed-node", true + case 383: + return "hp-alarm-mgr", true + case 384: + return "arns", true + case 385: + return "ibm-app", true + case 386: + return "asa", true + case 387: + return "aurp", true + case 388: + return "unidata-ldm", true + case 389: + return "ldap", true + case 390: + return "uis", true + case 391: + return "synotics-relay", true + case 392: + return "synotics-broker", true + case 393: + return "meta5", true + case 394: + return "embl-ndt", true + case 395: + return "netcp", true + case 396: + return "netware-ip", true + case 397: + return "mptn", true + case 398: + return "kryptolan", true + case 399: + return "iso-tsap-c2", true + case 400: + return "osb-sd", true + case 401: + return "ups", true + case 402: + return "genie", true + case 403: + return "decap", true + case 404: + return "nced", true + case 405: + return "ncld", true + case 406: + return "imsp", true + case 407: + return "timbuktu", true + case 408: + return "prm-sm", true + case 409: + return "prm-nm", true + case 410: + return "decladebug", true + case 411: + return "rmt", true + case 412: + return "synoptics-trap", true + case 413: + return "smsp", true + case 414: + return "infoseek", true + case 415: + return "bnet", true + case 416: + return "silverplatter", true + case 417: + return "onmux", true + case 418: + return "hyper-g", true + case 419: + return "ariel1", true + case 420: + return "smpte", true + case 421: + return "ariel2", true + case 422: + return "ariel3", true + case 423: + return "opc-job-start", true + case 424: + return "opc-job-track", true + case 425: + return "icad-el", true + case 426: + return "smartsdp", true + case 427: + return "svrloc", true + case 428: + return "ocs-cmu", true + case 429: + return "ocs-amu", true + case 430: + return "utmpsd", true + case 431: + return "utmpcd", true + case 432: + return "iasd", true + case 433: + return "nnsp", true + case 434: + return "mobileip-agent", true + case 435: + return "mobilip-mn", true + case 436: + return "dna-cml", true + case 437: + return "comscm", true + case 438: + return "dsfgw", true + case 439: + return "dasp", true + case 440: + return "sgcp", true + case 441: + return "decvms-sysmgt", true + case 442: + return "cvc-hostd", true + case 443: + return "https", true + case 444: + return "snpp", true + case 445: + return "microsoft-ds", true + case 446: + return "ddm-rdb", true + case 447: + return "ddm-dfm", true + case 448: + return "ddm-ssl", true + case 449: + return "as-servermap", true + case 450: + return "tserver", true + case 451: + return "sfs-smp-net", true + case 452: + return "sfs-config", true + case 453: + return "creativeserver", true + case 454: + return "contentserver", true + case 455: + return "creativepartnr", true + case 456: + return "macon-tcp", true + case 457: + return "scohelp", true + case 458: + return "appleqtc", true + case 459: + return "ampr-rcmd", true + case 460: + return "skronk", true + case 461: + return "datasurfsrv", true + case 462: + return "datasurfsrvsec", true + case 463: + return "alpes", true + case 464: + return "kpasswd", true + case 465: + return "urd", true + case 466: + return "digital-vrc", true + case 467: + return "mylex-mapd", true + case 468: + return "photuris", true + case 469: + return "rcp", true + case 470: + return "scx-proxy", true + case 471: + return "mondex", true + case 472: + return "ljk-login", true + case 473: + return "hybrid-pop", true + case 474: + return "tn-tl-w1", true + case 475: + return "tcpnethaspsrv", true + case 476: + return "tn-tl-fd1", true + case 477: + return "ss7ns", true + case 478: + return "spsc", true + case 479: + return "iafserver", true + case 480: + return "iafdbase", true + case 481: + return "ph", true + case 482: + return "bgs-nsi", true + case 483: + return "ulpnet", true + case 484: + return "integra-sme", true + case 485: + return "powerburst", true + case 486: + return "avian", true + case 487: + return "saft", true + case 488: + return "gss-http", true + case 489: + return "nest-protocol", true + case 490: + return "micom-pfs", true + case 491: + return "go-login", true + case 492: + return "ticf-1", true + case 493: + return "ticf-2", true + case 494: + return "pov-ray", true + case 495: + return "intecourier", true + case 496: + return "pim-rp-disc", true + case 497: + return "retrospect", true + case 498: + return "siam", true + case 499: + return "iso-ill", true + case 500: + return "isakmp", true + case 501: + return "stmf", true + case 502: + return "mbap", true + case 503: + return "intrinsa", true + case 504: + return "citadel", true + case 505: + return "mailbox-lm", true + case 506: + return "ohimsrv", true + case 507: + return "crs", true + case 508: + return "xvttp", true + case 509: + return "snare", true + case 510: + return "fcp", true + case 511: + return "passgo", true + case 512: + return "exec", true + case 513: + return "login", true + case 514: + return "shell", true + case 515: + return "printer", true + case 516: + return "videotex", true + case 517: + return "talk", true + case 518: + return "ntalk", true + case 519: + return "utime", true + case 520: + return "efs", true + case 521: + return "ripng", true + case 522: + return "ulp", true + case 523: + return "ibm-db2", true + case 524: + return "ncp", true + case 525: + return "timed", true + case 526: + return "tempo", true + case 527: + return "stx", true + case 528: + return "custix", true + case 529: + return "irc-serv", true + case 530: + return "courier", true + case 531: + return "conference", true + case 532: + return "netnews", true + case 533: + return "netwall", true + case 534: + return "windream", true + case 535: + return "iiop", true + case 536: + return "opalis-rdv", true + case 537: + return "nmsp", true + case 538: + return "gdomap", true + case 539: + return "apertus-ldp", true + case 540: + return "uucp", true + case 541: + return "uucp-rlogin", true + case 542: + return "commerce", true + case 543: + return "klogin", true + case 544: + return "kshell", true + case 545: + return "appleqtcsrvr", true + case 546: + return "dhcpv6-client", true + case 547: + return "dhcpv6-server", true + case 548: + return "afpovertcp", true + case 549: + return "idfp", true + case 550: + return "new-rwho", true + case 551: + return "cybercash", true + case 552: + return "devshr-nts", true + case 553: + return "pirp", true + case 554: + return "rtsp", true + case 555: + return "dsf", true + case 556: + return "remotefs", true + case 557: + return "openvms-sysipc", true + case 558: + return "sdnskmp", true + case 559: + return "teedtap", true + case 560: + return "rmonitor", true + case 561: + return "monitor", true + case 562: + return "chshell", true + case 563: + return "nntps", true + case 564: + return "9pfs", true + case 565: + return "whoami", true + case 566: + return "streettalk", true + case 567: + return "banyan-rpc", true + case 568: + return "ms-shuttle", true + case 569: + return "ms-rome", true + case 570: + return "meter", true + case 571: + return "meter", true + case 572: + return "sonar", true + case 573: + return "banyan-vip", true + case 574: + return "ftp-agent", true + case 575: + return "vemmi", true + case 576: + return "ipcd", true + case 577: + return "vnas", true + case 578: + return "ipdd", true + case 579: + return "decbsrv", true + case 580: + return "sntp-heartbeat", true + case 581: + return "bdp", true + case 582: + return "scc-security", true + case 583: + return "philips-vc", true + case 584: + return "keyserver", true + case 586: + return "password-chg", true + case 587: + return "submission", true + case 588: + return "cal", true + case 589: + return "eyelink", true + case 590: + return "tns-cml", true + case 591: + return "http-alt", true + case 592: + return "eudora-set", true + case 593: + return "http-rpc-epmap", true + case 594: + return "tpip", true + case 595: + return "cab-protocol", true + case 596: + return "smsd", true + case 597: + return "ptcnameservice", true + case 598: + return "sco-websrvrmg3", true + case 599: + return "acp", true + case 600: + return "ipcserver", true + case 601: + return "syslog-conn", true + case 602: + return "xmlrpc-beep", true + case 603: + return "idxp", true + case 604: + return "tunnel", true + case 605: + return "soap-beep", true + case 606: + return "urm", true + case 607: + return "nqs", true + case 608: + return "sift-uft", true + case 609: + return "npmp-trap", true + case 610: + return "npmp-local", true + case 611: + return "npmp-gui", true + case 612: + return "hmmp-ind", true + case 613: + return "hmmp-op", true + case 614: + return "sshell", true + case 615: + return "sco-inetmgr", true + case 616: + return "sco-sysmgr", true + case 617: + return "sco-dtmgr", true + case 618: + return "dei-icda", true + case 619: + return "compaq-evm", true + case 620: + return "sco-websrvrmgr", true + case 621: + return "escp-ip", true + case 622: + return "collaborator", true + case 623: + return "oob-ws-http", true + case 624: + return "cryptoadmin", true + case 625: + return "dec-dlm", true + case 626: + return "asia", true + case 627: + return "passgo-tivoli", true + case 628: + return "qmqp", true + case 629: + return "3com-amp3", true + case 630: + return "rda", true + case 631: + return "ipp", true + case 632: + return "bmpp", true + case 633: + return "servstat", true + case 634: + return "ginad", true + case 635: + return "rlzdbase", true + case 636: + return "ldaps", true + case 637: + return "lanserver", true + case 638: + return "mcns-sec", true + case 639: + return "msdp", true + case 640: + return "entrust-sps", true + case 641: + return "repcmd", true + case 642: + return "esro-emsdp", true + case 643: + return "sanity", true + case 644: + return "dwr", true + case 645: + return "pssc", true + case 646: + return "ldp", true + case 647: + return "dhcp-failover", true + case 648: + return "rrp", true + case 649: + return "cadview-3d", true + case 650: + return "obex", true + case 651: + return "ieee-mms", true + case 652: + return "hello-port", true + case 653: + return "repscmd", true + case 654: + return "aodv", true + case 655: + return "tinc", true + case 656: + return "spmp", true + case 657: + return "rmc", true + case 658: + return "tenfold", true + case 660: + return "mac-srvr-admin", true + case 661: + return "hap", true + case 662: + return "pftp", true + case 663: + return "purenoise", true + case 664: + return "oob-ws-https", true + case 665: + return "sun-dr", true + case 666: + return "mdqs", true + case 667: + return "disclose", true + case 668: + return "mecomm", true + case 669: + return "meregister", true + case 670: + return "vacdsm-sws", true + case 671: + return "vacdsm-app", true + case 672: + return "vpps-qua", true + case 673: + return "cimplex", true + case 674: + return "acap", true + case 675: + return "dctp", true + case 676: + return "vpps-via", true + case 677: + return "vpp", true + case 678: + return "ggf-ncp", true + case 679: + return "mrm", true + case 680: + return "entrust-aaas", true + case 681: + return "entrust-aams", true + case 682: + return "xfr", true + case 683: + return "corba-iiop", true + case 684: + return "corba-iiop-ssl", true + case 685: + return "mdc-portmapper", true + case 686: + return "hcp-wismar", true + case 687: + return "asipregistry", true + case 688: + return "realm-rusd", true + case 689: + return "nmap", true + case 690: + return "vatp", true + case 691: + return "msexch-routing", true + case 692: + return "hyperwave-isp", true + case 693: + return "connendp", true + case 694: + return "ha-cluster", true + case 695: + return "ieee-mms-ssl", true + case 696: + return "rushd", true + case 697: + return "uuidgen", true + case 698: + return "olsr", true + case 699: + return "accessnetwork", true + case 700: + return "epp", true + case 701: + return "lmp", true + case 702: + return "iris-beep", true + case 704: + return "elcsd", true + case 705: + return "agentx", true + case 706: + return "silc", true + case 707: + return "borland-dsj", true + case 709: + return "entrust-kmsh", true + case 710: + return "entrust-ash", true + case 711: + return "cisco-tdp", true + case 712: + return "tbrpf", true + case 713: + return "iris-xpc", true + case 714: + return "iris-xpcs", true + case 715: + return "iris-lwz", true + case 729: + return "netviewdm1", true + case 730: + return "netviewdm2", true + case 731: + return "netviewdm3", true + case 741: + return "netgw", true + case 742: + return "netrcs", true + case 744: + return "flexlm", true + case 747: + return "fujitsu-dev", true + case 748: + return "ris-cm", true + case 749: + return "kerberos-adm", true + case 750: + return "rfile", true + case 751: + return "pump", true + case 752: + return "qrh", true + case 753: + return "rrh", true + case 754: + return "tell", true + case 758: + return "nlogin", true + case 759: + return "con", true + case 760: + return "ns", true + case 761: + return "rxe", true + case 762: + return "quotad", true + case 763: + return "cycleserv", true + case 764: + return "omserv", true + case 765: + return "webster", true + case 767: + return "phonebook", true + case 769: + return "vid", true + case 770: + return "cadlock", true + case 771: + return "rtip", true + case 772: + return "cycleserv2", true + case 773: + return "submit", true + case 774: + return "rpasswd", true + case 775: + return "entomb", true + case 776: + return "wpages", true + case 777: + return "multiling-http", true + case 780: + return "wpgs", true + case 800: + return "mdbs-daemon", true + case 801: + return "device", true + case 802: + return "mbap-s", true + case 810: + return "fcp-udp", true + case 828: + return "itm-mcell-s", true + case 829: + return "pkix-3-ca-ra", true + case 830: + return "netconf-ssh", true + case 831: + return "netconf-beep", true + case 832: + return "netconfsoaphttp", true + case 833: + return "netconfsoapbeep", true + case 847: + return "dhcp-failover2", true + case 848: + return "gdoi", true + case 853: + return "domain-s", true + case 854: + return "dlep", true + case 860: + return "iscsi", true + case 861: + return "owamp-control", true + case 862: + return "twamp-control", true + case 873: + return "rsync", true + case 886: + return "iclcnet-locate", true + case 887: + return "iclcnet-svinfo", true + case 888: + return "accessbuilder", true + case 900: + return "omginitialrefs", true + case 901: + return "smpnameres", true + case 902: + return "ideafarm-door", true + case 903: + return "ideafarm-panic", true + case 910: + return "kink", true + case 911: + return "xact-backup", true + case 912: + return "apex-mesh", true + case 913: + return "apex-edge", true + case 953: + return "rndc", true + case 989: + return "ftps-data", true + case 990: + return "ftps", true + case 991: + return "nas", true + case 992: + return "telnets", true + case 993: + return "imaps", true + case 995: + return "pop3s", true + case 996: + return "vsinet", true + case 997: + return "maitrd", true + case 998: + return "busboy", true + case 999: + return "garcon", true + case 1000: + return "cadlock2", true + case 1001: + return "webpush", true + case 1010: + return "surf", true + case 1021: + return "exp1", true + case 1022: + return "exp2", true + case 1025: + return "blackjack", true + case 1026: + return "cap", true + case 1029: + return "solid-mux", true + case 1033: + return "netinfo-local", true + case 1034: + return "activesync", true + case 1035: + return "mxxrlogin", true + case 1036: + return "nsstp", true + case 1037: + return "ams", true + case 1038: + return "mtqp", true + case 1039: + return "sbl", true + case 1040: + return "netarx", true + case 1041: + return "danf-ak2", true + case 1042: + return "afrog", true + case 1043: + return "boinc-client", true + case 1044: + return "dcutility", true + case 1045: + return "fpitp", true + case 1046: + return "wfremotertm", true + case 1047: + return "neod1", true + case 1048: + return "neod2", true + case 1049: + return "td-postman", true + case 1050: + return "cma", true + case 1051: + return "optima-vnet", true + case 1052: + return "ddt", true + case 1053: + return "remote-as", true + case 1054: + return "brvread", true + case 1055: + return "ansyslmd", true + case 1056: + return "vfo", true + case 1057: + return "startron", true + case 1058: + return "nim", true + case 1059: + return "nimreg", true + case 1060: + return "polestar", true + case 1061: + return "kiosk", true + case 1062: + return "veracity", true + case 1063: + return "kyoceranetdev", true + case 1064: + return "jstel", true + case 1065: + return "syscomlan", true + case 1066: + return "fpo-fns", true + case 1067: + return "instl-boots", true + case 1068: + return "instl-bootc", true + case 1069: + return "cognex-insight", true + case 1070: + return "gmrupdateserv", true + case 1071: + return "bsquare-voip", true + case 1072: + return "cardax", true + case 1073: + return "bridgecontrol", true + case 1074: + return "warmspotMgmt", true + case 1075: + return "rdrmshc", true + case 1076: + return "dab-sti-c", true + case 1077: + return "imgames", true + case 1078: + return "avocent-proxy", true + case 1079: + return "asprovatalk", true + case 1080: + return "socks", true + case 1081: + return "pvuniwien", true + case 1082: + return "amt-esd-prot", true + case 1083: + return "ansoft-lm-1", true + case 1084: + return "ansoft-lm-2", true + case 1085: + return "webobjects", true + case 1086: + return "cplscrambler-lg", true + case 1087: + return "cplscrambler-in", true + case 1088: + return "cplscrambler-al", true + case 1089: + return "ff-annunc", true + case 1090: + return "ff-fms", true + case 1091: + return "ff-sm", true + case 1092: + return "obrpd", true + case 1093: + return "proofd", true + case 1094: + return "rootd", true + case 1095: + return "nicelink", true + case 1096: + return "cnrprotocol", true + case 1097: + return "sunclustermgr", true + case 1098: + return "rmiactivation", true + case 1099: + return "rmiregistry", true + case 1100: + return "mctp", true + case 1101: + return "pt2-discover", true + case 1102: + return "adobeserver-1", true + case 1103: + return "adobeserver-2", true + case 1104: + return "xrl", true + case 1105: + return "ftranhc", true + case 1106: + return "isoipsigport-1", true + case 1107: + return "isoipsigport-2", true + case 1108: + return "ratio-adp", true + case 1110: + return "webadmstart", true + case 1111: + return "lmsocialserver", true + case 1112: + return "icp", true + case 1113: + return "ltp-deepspace", true + case 1114: + return "mini-sql", true + case 1115: + return "ardus-trns", true + case 1116: + return "ardus-cntl", true + case 1117: + return "ardus-mtrns", true + case 1118: + return "sacred", true + case 1119: + return "bnetgame", true + case 1120: + return "bnetfile", true + case 1121: + return "rmpp", true + case 1122: + return "availant-mgr", true + case 1123: + return "murray", true + case 1124: + return "hpvmmcontrol", true + case 1125: + return "hpvmmagent", true + case 1126: + return "hpvmmdata", true + case 1127: + return "kwdb-commn", true + case 1128: + return "saphostctrl", true + case 1129: + return "saphostctrls", true + case 1130: + return "casp", true + case 1131: + return "caspssl", true + case 1132: + return "kvm-via-ip", true + case 1133: + return "dfn", true + case 1134: + return "aplx", true + case 1135: + return "omnivision", true + case 1136: + return "hhb-gateway", true + case 1137: + return "trim", true + case 1138: + return "encrypted-admin", true + case 1139: + return "evm", true + case 1140: + return "autonoc", true + case 1141: + return "mxomss", true + case 1142: + return "edtools", true + case 1143: + return "imyx", true + case 1144: + return "fuscript", true + case 1145: + return "x9-icue", true + case 1146: + return "audit-transfer", true + case 1147: + return "capioverlan", true + case 1148: + return "elfiq-repl", true + case 1149: + return "bvtsonar", true + case 1150: + return "blaze", true + case 1151: + return "unizensus", true + case 1152: + return "winpoplanmess", true + case 1153: + return "c1222-acse", true + case 1154: + return "resacommunity", true + case 1155: + return "nfa", true + case 1156: + return "iascontrol-oms", true + case 1157: + return "iascontrol", true + case 1158: + return "dbcontrol-oms", true + case 1159: + return "oracle-oms", true + case 1160: + return "olsv", true + case 1161: + return "health-polling", true + case 1162: + return "health-trap", true + case 1163: + return "sddp", true + case 1164: + return "qsm-proxy", true + case 1165: + return "qsm-gui", true + case 1166: + return "qsm-remote", true + case 1167: + return "cisco-ipsla", true + case 1168: + return "vchat", true + case 1169: + return "tripwire", true + case 1170: + return "atc-lm", true + case 1171: + return "atc-appserver", true + case 1172: + return "dnap", true + case 1173: + return "d-cinema-rrp", true + case 1174: + return "fnet-remote-ui", true + case 1175: + return "dossier", true + case 1176: + return "indigo-server", true + case 1177: + return "dkmessenger", true + case 1178: + return "sgi-storman", true + case 1179: + return "b2n", true + case 1180: + return "mc-client", true + case 1181: + return "3comnetman", true + case 1182: + return "accelenet", true + case 1183: + return "llsurfup-http", true + case 1184: + return "llsurfup-https", true + case 1185: + return "catchpole", true + case 1186: + return "mysql-cluster", true + case 1187: + return "alias", true + case 1188: + return "hp-webadmin", true + case 1189: + return "unet", true + case 1190: + return "commlinx-avl", true + case 1191: + return "gpfs", true + case 1192: + return "caids-sensor", true + case 1193: + return "fiveacross", true + case 1194: + return "openvpn", true + case 1195: + return "rsf-1", true + case 1196: + return "netmagic", true + case 1197: + return "carrius-rshell", true + case 1198: + return "cajo-discovery", true + case 1199: + return "dmidi", true + case 1200: + return "scol", true + case 1201: + return "nucleus-sand", true + case 1202: + return "caiccipc", true + case 1203: + return "ssslic-mgr", true + case 1204: + return "ssslog-mgr", true + case 1205: + return "accord-mgc", true + case 1206: + return "anthony-data", true + case 1207: + return "metasage", true + case 1208: + return "seagull-ais", true + case 1209: + return "ipcd3", true + case 1210: + return "eoss", true + case 1211: + return "groove-dpp", true + case 1212: + return "lupa", true + case 1213: + return "mpc-lifenet", true + case 1214: + return "kazaa", true + case 1215: + return "scanstat-1", true + case 1216: + return "etebac5", true + case 1217: + return "hpss-ndapi", true + case 1218: + return "aeroflight-ads", true + case 1219: + return "aeroflight-ret", true + case 1220: + return "qt-serveradmin", true + case 1221: + return "sweetware-apps", true + case 1222: + return "nerv", true + case 1223: + return "tgp", true + case 1224: + return "vpnz", true + case 1225: + return "slinkysearch", true + case 1226: + return "stgxfws", true + case 1227: + return "dns2go", true + case 1228: + return "florence", true + case 1229: + return "zented", true + case 1230: + return "periscope", true + case 1231: + return "menandmice-lpm", true + case 1232: + return "first-defense", true + case 1233: + return "univ-appserver", true + case 1234: + return "search-agent", true + case 1235: + return "mosaicsyssvc1", true + case 1236: + return "bvcontrol", true + case 1237: + return "tsdos390", true + case 1238: + return "hacl-qs", true + case 1239: + return "nmsd", true + case 1240: + return "instantia", true + case 1241: + return "nessus", true + case 1242: + return "nmasoverip", true + case 1243: + return "serialgateway", true + case 1244: + return "isbconference1", true + case 1245: + return "isbconference2", true + case 1246: + return "payrouter", true + case 1247: + return "visionpyramid", true + case 1248: + return "hermes", true + case 1249: + return "mesavistaco", true + case 1250: + return "swldy-sias", true + case 1251: + return "servergraph", true + case 1252: + return "bspne-pcc", true + case 1253: + return "q55-pcc", true + case 1254: + return "de-noc", true + case 1255: + return "de-cache-query", true + case 1256: + return "de-server", true + case 1257: + return "shockwave2", true + case 1258: + return "opennl", true + case 1259: + return "opennl-voice", true + case 1260: + return "ibm-ssd", true + case 1261: + return "mpshrsv", true + case 1262: + return "qnts-orb", true + case 1263: + return "dka", true + case 1264: + return "prat", true + case 1265: + return "dssiapi", true + case 1266: + return "dellpwrappks", true + case 1267: + return "epc", true + case 1268: + return "propel-msgsys", true + case 1269: + return "watilapp", true + case 1270: + return "opsmgr", true + case 1271: + return "excw", true + case 1272: + return "cspmlockmgr", true + case 1273: + return "emc-gateway", true + case 1274: + return "t1distproc", true + case 1275: + return "ivcollector", true + case 1277: + return "miva-mqs", true + case 1278: + return "dellwebadmin-1", true + case 1279: + return "dellwebadmin-2", true + case 1280: + return "pictrography", true + case 1281: + return "healthd", true + case 1282: + return "emperion", true + case 1283: + return "productinfo", true + case 1284: + return "iee-qfx", true + case 1285: + return "neoiface", true + case 1286: + return "netuitive", true + case 1287: + return "routematch", true + case 1288: + return "navbuddy", true + case 1289: + return "jwalkserver", true + case 1290: + return "winjaserver", true + case 1291: + return "seagulllms", true + case 1292: + return "dsdn", true + case 1293: + return "pkt-krb-ipsec", true + case 1294: + return "cmmdriver", true + case 1295: + return "ehtp", true + case 1296: + return "dproxy", true + case 1297: + return "sdproxy", true + case 1298: + return "lpcp", true + case 1299: + return "hp-sci", true + case 1300: + return "h323hostcallsc", true + case 1303: + return "sftsrv", true + case 1304: + return "boomerang", true + case 1305: + return "pe-mike", true + case 1306: + return "re-conn-proto", true + case 1307: + return "pacmand", true + case 1308: + return "odsi", true + case 1309: + return "jtag-server", true + case 1310: + return "husky", true + case 1311: + return "rxmon", true + case 1312: + return "sti-envision", true + case 1313: + return "bmc-patroldb", true + case 1314: + return "pdps", true + case 1315: + return "els", true + case 1316: + return "exbit-escp", true + case 1317: + return "vrts-ipcserver", true + case 1318: + return "krb5gatekeeper", true + case 1319: + return "amx-icsp", true + case 1320: + return "amx-axbnet", true + case 1321: + return "pip", true + case 1322: + return "novation", true + case 1323: + return "brcd", true + case 1324: + return "delta-mcp", true + case 1325: + return "dx-instrument", true + case 1326: + return "wimsic", true + case 1327: + return "ultrex", true + case 1328: + return "ewall", true + case 1329: + return "netdb-export", true + case 1330: + return "streetperfect", true + case 1331: + return "intersan", true + case 1332: + return "pcia-rxp-b", true + case 1333: + return "passwrd-policy", true + case 1334: + return "writesrv", true + case 1335: + return "digital-notary", true + case 1336: + return "ischat", true + case 1337: + return "menandmice-dns", true + case 1338: + return "wmc-log-svc", true + case 1339: + return "kjtsiteserver", true + case 1340: + return "naap", true + case 1341: + return "qubes", true + case 1342: + return "esbroker", true + case 1343: + return "re101", true + case 1344: + return "icap", true + case 1345: + return "vpjp", true + case 1346: + return "alta-ana-lm", true + case 1347: + return "bbn-mmc", true + case 1348: + return "bbn-mmx", true + case 1349: + return "sbook", true + case 1350: + return "editbench", true + case 1351: + return "equationbuilder", true + case 1352: + return "lotusnote", true + case 1353: + return "relief", true + case 1354: + return "XSIP-network", true + case 1355: + return "intuitive-edge", true + case 1356: + return "cuillamartin", true + case 1357: + return "pegboard", true + case 1358: + return "connlcli", true + case 1359: + return "ftsrv", true + case 1360: + return "mimer", true + case 1361: + return "linx", true + case 1362: + return "timeflies", true + case 1363: + return "ndm-requester", true + case 1364: + return "ndm-server", true + case 1365: + return "adapt-sna", true + case 1366: + return "netware-csp", true + case 1367: + return "dcs", true + case 1368: + return "screencast", true + case 1369: + return "gv-us", true + case 1370: + return "us-gv", true + case 1371: + return "fc-cli", true + case 1372: + return "fc-ser", true + case 1373: + return "chromagrafx", true + case 1374: + return "molly", true + case 1375: + return "bytex", true + case 1376: + return "ibm-pps", true + case 1377: + return "cichlid", true + case 1378: + return "elan", true + case 1379: + return "dbreporter", true + case 1380: + return "telesis-licman", true + case 1381: + return "apple-licman", true + case 1382: + return "udt-os", true + case 1383: + return "gwha", true + case 1384: + return "os-licman", true + case 1385: + return "atex-elmd", true + case 1386: + return "checksum", true + case 1387: + return "cadsi-lm", true + case 1388: + return "objective-dbc", true + case 1389: + return "iclpv-dm", true + case 1390: + return "iclpv-sc", true + case 1391: + return "iclpv-sas", true + case 1392: + return "iclpv-pm", true + case 1393: + return "iclpv-nls", true + case 1394: + return "iclpv-nlc", true + case 1395: + return "iclpv-wsm", true + case 1396: + return "dvl-activemail", true + case 1397: + return "audio-activmail", true + case 1398: + return "video-activmail", true + case 1399: + return "cadkey-licman", true + case 1400: + return "cadkey-tablet", true + case 1401: + return "goldleaf-licman", true + case 1402: + return "prm-sm-np", true + case 1403: + return "prm-nm-np", true + case 1404: + return "igi-lm", true + case 1405: + return "ibm-res", true + case 1406: + return "netlabs-lm", true + case 1407: + return "tibet-server", true + case 1408: + return "sophia-lm", true + case 1409: + return "here-lm", true + case 1410: + return "hiq", true + case 1411: + return "af", true + case 1412: + return "innosys", true + case 1413: + return "innosys-acl", true + case 1414: + return "ibm-mqseries", true + case 1415: + return "dbstar", true + case 1416: + return "novell-lu6-2", true + case 1417: + return "timbuktu-srv1", true + case 1418: + return "timbuktu-srv2", true + case 1419: + return "timbuktu-srv3", true + case 1420: + return "timbuktu-srv4", true + case 1421: + return "gandalf-lm", true + case 1422: + return "autodesk-lm", true + case 1423: + return "essbase", true + case 1424: + return "hybrid", true + case 1425: + return "zion-lm", true + case 1426: + return "sais", true + case 1427: + return "mloadd", true + case 1428: + return "informatik-lm", true + case 1429: + return "nms", true + case 1430: + return "tpdu", true + case 1431: + return "rgtp", true + case 1432: + return "blueberry-lm", true + case 1433: + return "ms-sql-s", true + case 1434: + return "ms-sql-m", true + case 1435: + return "ibm-cics", true + case 1436: + return "saism", true + case 1437: + return "tabula", true + case 1438: + return "eicon-server", true + case 1439: + return "eicon-x25", true + case 1440: + return "eicon-slp", true + case 1441: + return "cadis-1", true + case 1442: + return "cadis-2", true + case 1443: + return "ies-lm", true + case 1444: + return "marcam-lm", true + case 1445: + return "proxima-lm", true + case 1446: + return "ora-lm", true + case 1447: + return "apri-lm", true + case 1448: + return "oc-lm", true + case 1449: + return "peport", true + case 1450: + return "dwf", true + case 1451: + return "infoman", true + case 1452: + return "gtegsc-lm", true + case 1453: + return "genie-lm", true + case 1454: + return "interhdl-elmd", true + case 1455: + return "esl-lm", true + case 1456: + return "dca", true + case 1457: + return "valisys-lm", true + case 1458: + return "nrcabq-lm", true + case 1459: + return "proshare1", true + case 1460: + return "proshare2", true + case 1461: + return "ibm-wrless-lan", true + case 1462: + return "world-lm", true + case 1463: + return "nucleus", true + case 1464: + return "msl-lmd", true + case 1465: + return "pipes", true + case 1466: + return "oceansoft-lm", true + case 1467: + return "csdmbase", true + case 1468: + return "csdm", true + case 1469: + return "aal-lm", true + case 1470: + return "uaiact", true + case 1471: + return "csdmbase", true + case 1472: + return "csdm", true + case 1473: + return "openmath", true + case 1474: + return "telefinder", true + case 1475: + return "taligent-lm", true + case 1476: + return "clvm-cfg", true + case 1477: + return "ms-sna-server", true + case 1478: + return "ms-sna-base", true + case 1479: + return "dberegister", true + case 1480: + return "pacerforum", true + case 1481: + return "airs", true + case 1482: + return "miteksys-lm", true + case 1483: + return "afs", true + case 1484: + return "confluent", true + case 1485: + return "lansource", true + case 1486: + return "nms-topo-serv", true + case 1487: + return "localinfosrvr", true + case 1488: + return "docstor", true + case 1489: + return "dmdocbroker", true + case 1490: + return "insitu-conf", true + case 1492: + return "stone-design-1", true + case 1493: + return "netmap-lm", true + case 1494: + return "ica", true + case 1495: + return "cvc", true + case 1496: + return "liberty-lm", true + case 1497: + return "rfx-lm", true + case 1498: + return "sybase-sqlany", true + case 1499: + return "fhc", true + case 1500: + return "vlsi-lm", true + case 1501: + return "saiscm", true + case 1502: + return "shivadiscovery", true + case 1503: + return "imtc-mcs", true + case 1504: + return "evb-elm", true + case 1505: + return "funkproxy", true + case 1506: + return "utcd", true + case 1507: + return "symplex", true + case 1508: + return "diagmond", true + case 1509: + return "robcad-lm", true + case 1510: + return "mvx-lm", true + case 1511: + return "3l-l1", true + case 1512: + return "wins", true + case 1513: + return "fujitsu-dtc", true + case 1514: + return "fujitsu-dtcns", true + case 1515: + return "ifor-protocol", true + case 1516: + return "vpad", true + case 1517: + return "vpac", true + case 1518: + return "vpvd", true + case 1519: + return "vpvc", true + case 1520: + return "atm-zip-office", true + case 1521: + return "ncube-lm", true + case 1522: + return "ricardo-lm", true + case 1523: + return "cichild-lm", true + case 1524: + return "ingreslock", true + case 1525: + return "orasrv", true + case 1526: + return "pdap-np", true + case 1527: + return "tlisrv", true + case 1528: + return "norp", true + case 1529: + return "coauthor", true + case 1530: + return "rap-service", true + case 1531: + return "rap-listen", true + case 1532: + return "miroconnect", true + case 1533: + return "virtual-places", true + case 1534: + return "micromuse-lm", true + case 1535: + return "ampr-info", true + case 1536: + return "ampr-inter", true + case 1537: + return "sdsc-lm", true + case 1538: + return "3ds-lm", true + case 1539: + return "intellistor-lm", true + case 1540: + return "rds", true + case 1541: + return "rds2", true + case 1542: + return "gridgen-elmd", true + case 1543: + return "simba-cs", true + case 1544: + return "aspeclmd", true + case 1545: + return "vistium-share", true + case 1546: + return "abbaccuray", true + case 1547: + return "laplink", true + case 1548: + return "axon-lm", true + case 1549: + return "shivahose", true + case 1550: + return "3m-image-lm", true + case 1551: + return "hecmtl-db", true + case 1552: + return "pciarray", true + case 1553: + return "sna-cs", true + case 1554: + return "caci-lm", true + case 1555: + return "livelan", true + case 1556: + return "veritas-pbx", true + case 1557: + return "arbortext-lm", true + case 1558: + return "xingmpeg", true + case 1559: + return "web2host", true + case 1560: + return "asci-val", true + case 1561: + return "facilityview", true + case 1562: + return "pconnectmgr", true + case 1563: + return "cadabra-lm", true + case 1564: + return "pay-per-view", true + case 1565: + return "winddlb", true + case 1566: + return "corelvideo", true + case 1567: + return "jlicelmd", true + case 1568: + return "tsspmap", true + case 1569: + return "ets", true + case 1570: + return "orbixd", true + case 1571: + return "rdb-dbs-disp", true + case 1572: + return "chip-lm", true + case 1573: + return "itscomm-ns", true + case 1574: + return "mvel-lm", true + case 1575: + return "oraclenames", true + case 1576: + return "moldflow-lm", true + case 1577: + return "hypercube-lm", true + case 1578: + return "jacobus-lm", true + case 1579: + return "ioc-sea-lm", true + case 1580: + return "tn-tl-r1", true + case 1581: + return "mil-2045-47001", true + case 1582: + return "msims", true + case 1583: + return "simbaexpress", true + case 1584: + return "tn-tl-fd2", true + case 1585: + return "intv", true + case 1586: + return "ibm-abtact", true + case 1587: + return "pra-elmd", true + case 1588: + return "triquest-lm", true + case 1589: + return "vqp", true + case 1590: + return "gemini-lm", true + case 1591: + return "ncpm-pm", true + case 1592: + return "commonspace", true + case 1593: + return "mainsoft-lm", true + case 1594: + return "sixtrak", true + case 1595: + return "radio", true + case 1596: + return "radio-sm", true + case 1597: + return "orbplus-iiop", true + case 1598: + return "picknfs", true + case 1599: + return "simbaservices", true + case 1600: + return "issd", true + case 1601: + return "aas", true + case 1602: + return "inspect", true + case 1603: + return "picodbc", true + case 1604: + return "icabrowser", true + case 1605: + return "slp", true + case 1606: + return "slm-api", true + case 1607: + return "stt", true + case 1608: + return "smart-lm", true + case 1609: + return "isysg-lm", true + case 1610: + return "taurus-wh", true + case 1611: + return "ill", true + case 1612: + return "netbill-trans", true + case 1613: + return "netbill-keyrep", true + case 1614: + return "netbill-cred", true + case 1615: + return "netbill-auth", true + case 1616: + return "netbill-prod", true + case 1617: + return "nimrod-agent", true + case 1618: + return "skytelnet", true + case 1619: + return "xs-openstorage", true + case 1620: + return "faxportwinport", true + case 1621: + return "softdataphone", true + case 1622: + return "ontime", true + case 1623: + return "jaleosnd", true + case 1624: + return "udp-sr-port", true + case 1625: + return "svs-omagent", true + case 1626: + return "shockwave", true + case 1627: + return "t128-gateway", true + case 1628: + return "lontalk-norm", true + case 1629: + return "lontalk-urgnt", true + case 1630: + return "oraclenet8cman", true + case 1631: + return "visitview", true + case 1632: + return "pammratc", true + case 1633: + return "pammrpc", true + case 1634: + return "loaprobe", true + case 1635: + return "edb-server1", true + case 1636: + return "isdc", true + case 1637: + return "islc", true + case 1638: + return "ismc", true + case 1639: + return "cert-initiator", true + case 1640: + return "cert-responder", true + case 1641: + return "invision", true + case 1642: + return "isis-am", true + case 1643: + return "isis-ambc", true + case 1644: + return "saiseh", true + case 1645: + return "sightline", true + case 1646: + return "sa-msg-port", true + case 1647: + return "rsap", true + case 1648: + return "concurrent-lm", true + case 1649: + return "kermit", true + case 1650: + return "nkd", true + case 1651: + return "shiva-confsrvr", true + case 1652: + return "xnmp", true + case 1653: + return "alphatech-lm", true + case 1654: + return "stargatealerts", true + case 1655: + return "dec-mbadmin", true + case 1656: + return "dec-mbadmin-h", true + case 1657: + return "fujitsu-mmpdc", true + case 1658: + return "sixnetudr", true + case 1659: + return "sg-lm", true + case 1660: + return "skip-mc-gikreq", true + case 1661: + return "netview-aix-1", true + case 1662: + return "netview-aix-2", true + case 1663: + return "netview-aix-3", true + case 1664: + return "netview-aix-4", true + case 1665: + return "netview-aix-5", true + case 1666: + return "netview-aix-6", true + case 1667: + return "netview-aix-7", true + case 1668: + return "netview-aix-8", true + case 1669: + return "netview-aix-9", true + case 1670: + return "netview-aix-10", true + case 1671: + return "netview-aix-11", true + case 1672: + return "netview-aix-12", true + case 1673: + return "proshare-mc-1", true + case 1674: + return "proshare-mc-2", true + case 1675: + return "pdp", true + case 1676: + return "netcomm1", true + case 1677: + return "groupwise", true + case 1678: + return "prolink", true + case 1679: + return "darcorp-lm", true + case 1680: + return "microcom-sbp", true + case 1681: + return "sd-elmd", true + case 1682: + return "lanyon-lantern", true + case 1683: + return "ncpm-hip", true + case 1684: + return "snaresecure", true + case 1685: + return "n2nremote", true + case 1686: + return "cvmon", true + case 1687: + return "nsjtp-ctrl", true + case 1688: + return "nsjtp-data", true + case 1689: + return "firefox", true + case 1690: + return "ng-umds", true + case 1691: + return "empire-empuma", true + case 1692: + return "sstsys-lm", true + case 1693: + return "rrirtr", true + case 1694: + return "rrimwm", true + case 1695: + return "rrilwm", true + case 1696: + return "rrifmm", true + case 1697: + return "rrisat", true + case 1698: + return "rsvp-encap-1", true + case 1699: + return "rsvp-encap-2", true + case 1700: + return "mps-raft", true + case 1701: + return "l2f", true + case 1702: + return "deskshare", true + case 1703: + return "hb-engine", true + case 1704: + return "bcs-broker", true + case 1705: + return "slingshot", true + case 1706: + return "jetform", true + case 1707: + return "vdmplay", true + case 1708: + return "gat-lmd", true + case 1709: + return "centra", true + case 1710: + return "impera", true + case 1711: + return "pptconference", true + case 1712: + return "registrar", true + case 1713: + return "conferencetalk", true + case 1714: + return "sesi-lm", true + case 1715: + return "houdini-lm", true + case 1716: + return "xmsg", true + case 1717: + return "fj-hdnet", true + case 1718: + return "h323gatedisc", true + case 1719: + return "h323gatestat", true + case 1720: + return "h323hostcall", true + case 1721: + return "caicci", true + case 1722: + return "hks-lm", true + case 1723: + return "pptp", true + case 1724: + return "csbphonemaster", true + case 1725: + return "iden-ralp", true + case 1726: + return "iberiagames", true + case 1727: + return "winddx", true + case 1728: + return "telindus", true + case 1729: + return "citynl", true + case 1730: + return "roketz", true + case 1731: + return "msiccp", true + case 1732: + return "proxim", true + case 1733: + return "siipat", true + case 1734: + return "cambertx-lm", true + case 1735: + return "privatechat", true + case 1736: + return "street-stream", true + case 1737: + return "ultimad", true + case 1738: + return "gamegen1", true + case 1739: + return "webaccess", true + case 1740: + return "encore", true + case 1741: + return "cisco-net-mgmt", true + case 1742: + return "3Com-nsd", true + case 1743: + return "cinegrfx-lm", true + case 1744: + return "ncpm-ft", true + case 1745: + return "remote-winsock", true + case 1746: + return "ftrapid-1", true + case 1747: + return "ftrapid-2", true + case 1748: + return "oracle-em1", true + case 1749: + return "aspen-services", true + case 1750: + return "sslp", true + case 1751: + return "swiftnet", true + case 1752: + return "lofr-lm", true + case 1753: + return "predatar-comms", true + case 1754: + return "oracle-em2", true + case 1755: + return "ms-streaming", true + case 1756: + return "capfast-lmd", true + case 1757: + return "cnhrp", true + case 1758: + return "tftp-mcast", true + case 1759: + return "spss-lm", true + case 1760: + return "www-ldap-gw", true + case 1761: + return "cft-0", true + case 1762: + return "cft-1", true + case 1763: + return "cft-2", true + case 1764: + return "cft-3", true + case 1765: + return "cft-4", true + case 1766: + return "cft-5", true + case 1767: + return "cft-6", true + case 1768: + return "cft-7", true + case 1769: + return "bmc-net-adm", true + case 1770: + return "bmc-net-svc", true + case 1771: + return "vaultbase", true + case 1772: + return "essweb-gw", true + case 1773: + return "kmscontrol", true + case 1774: + return "global-dtserv", true + case 1775: + return "vdab", true + case 1776: + return "femis", true + case 1777: + return "powerguardian", true + case 1778: + return "prodigy-intrnet", true + case 1779: + return "pharmasoft", true + case 1780: + return "dpkeyserv", true + case 1781: + return "answersoft-lm", true + case 1782: + return "hp-hcip", true + case 1784: + return "finle-lm", true + case 1785: + return "windlm", true + case 1786: + return "funk-logger", true + case 1787: + return "funk-license", true + case 1788: + return "psmond", true + case 1789: + return "hello", true + case 1790: + return "nmsp", true + case 1791: + return "ea1", true + case 1792: + return "ibm-dt-2", true + case 1793: + return "rsc-robot", true + case 1794: + return "cera-bcm", true + case 1795: + return "dpi-proxy", true + case 1796: + return "vocaltec-admin", true + case 1797: + return "uma", true + case 1798: + return "etp", true + case 1799: + return "netrisk", true + case 1800: + return "ansys-lm", true + case 1801: + return "msmq", true + case 1802: + return "concomp1", true + case 1803: + return "hp-hcip-gwy", true + case 1804: + return "enl", true + case 1805: + return "enl-name", true + case 1806: + return "musiconline", true + case 1807: + return "fhsp", true + case 1808: + return "oracle-vp2", true + case 1809: + return "oracle-vp1", true + case 1810: + return "jerand-lm", true + case 1811: + return "scientia-sdb", true + case 1812: + return "radius", true + case 1813: + return "radius-acct", true + case 1814: + return "tdp-suite", true + case 1815: + return "mmpft", true + case 1816: + return "harp", true + case 1817: + return "rkb-oscs", true + case 1818: + return "etftp", true + case 1819: + return "plato-lm", true + case 1820: + return "mcagent", true + case 1821: + return "donnyworld", true + case 1822: + return "es-elmd", true + case 1823: + return "unisys-lm", true + case 1824: + return "metrics-pas", true + case 1825: + return "direcpc-video", true + case 1826: + return "ardt", true + case 1827: + return "asi", true + case 1828: + return "itm-mcell-u", true + case 1829: + return "optika-emedia", true + case 1830: + return "net8-cman", true + case 1831: + return "myrtle", true + case 1832: + return "tht-treasure", true + case 1833: + return "udpradio", true + case 1834: + return "ardusuni", true + case 1835: + return "ardusmul", true + case 1836: + return "ste-smsc", true + case 1837: + return "csoft1", true + case 1838: + return "talnet", true + case 1839: + return "netopia-vo1", true + case 1840: + return "netopia-vo2", true + case 1841: + return "netopia-vo3", true + case 1842: + return "netopia-vo4", true + case 1843: + return "netopia-vo5", true + case 1844: + return "direcpc-dll", true + case 1845: + return "altalink", true + case 1846: + return "tunstall-pnc", true + case 1847: + return "slp-notify", true + case 1848: + return "fjdocdist", true + case 1849: + return "alpha-sms", true + case 1850: + return "gsi", true + case 1851: + return "ctcd", true + case 1852: + return "virtual-time", true + case 1853: + return "vids-avtp", true + case 1854: + return "buddy-draw", true + case 1855: + return "fiorano-rtrsvc", true + case 1856: + return "fiorano-msgsvc", true + case 1857: + return "datacaptor", true + case 1858: + return "privateark", true + case 1859: + return "gammafetchsvr", true + case 1860: + return "sunscalar-svc", true + case 1861: + return "lecroy-vicp", true + case 1862: + return "mysql-cm-agent", true + case 1863: + return "msnp", true + case 1864: + return "paradym-31port", true + case 1865: + return "entp", true + case 1866: + return "swrmi", true + case 1867: + return "udrive", true + case 1868: + return "viziblebrowser", true + case 1869: + return "transact", true + case 1870: + return "sunscalar-dns", true + case 1871: + return "canocentral0", true + case 1872: + return "canocentral1", true + case 1873: + return "fjmpjps", true + case 1874: + return "fjswapsnp", true + case 1875: + return "westell-stats", true + case 1876: + return "ewcappsrv", true + case 1877: + return "hp-webqosdb", true + case 1878: + return "drmsmc", true + case 1879: + return "nettgain-nms", true + case 1880: + return "vsat-control", true + case 1881: + return "ibm-mqseries2", true + case 1882: + return "ecsqdmn", true + case 1883: + return "mqtt", true + case 1884: + return "idmaps", true + case 1885: + return "vrtstrapserver", true + case 1886: + return "leoip", true + case 1887: + return "filex-lport", true + case 1888: + return "ncconfig", true + case 1889: + return "unify-adapter", true + case 1890: + return "wilkenlistener", true + case 1891: + return "childkey-notif", true + case 1892: + return "childkey-ctrl", true + case 1893: + return "elad", true + case 1894: + return "o2server-port", true + case 1896: + return "b-novative-ls", true + case 1897: + return "metaagent", true + case 1898: + return "cymtec-port", true + case 1899: + return "mc2studios", true + case 1900: + return "ssdp", true + case 1901: + return "fjicl-tep-a", true + case 1902: + return "fjicl-tep-b", true + case 1903: + return "linkname", true + case 1904: + return "fjicl-tep-c", true + case 1905: + return "sugp", true + case 1906: + return "tpmd", true + case 1907: + return "intrastar", true + case 1908: + return "dawn", true + case 1909: + return "global-wlink", true + case 1910: + return "ultrabac", true + case 1911: + return "mtp", true + case 1912: + return "rhp-iibp", true + case 1913: + return "armadp", true + case 1914: + return "elm-momentum", true + case 1915: + return "facelink", true + case 1916: + return "persona", true + case 1917: + return "noagent", true + case 1918: + return "can-nds", true + case 1919: + return "can-dch", true + case 1920: + return "can-ferret", true + case 1921: + return "noadmin", true + case 1922: + return "tapestry", true + case 1923: + return "spice", true + case 1924: + return "xiip", true + case 1925: + return "discovery-port", true + case 1926: + return "egs", true + case 1927: + return "videte-cipc", true + case 1928: + return "emsd-port", true + case 1929: + return "bandwiz-system", true + case 1930: + return "driveappserver", true + case 1931: + return "amdsched", true + case 1932: + return "ctt-broker", true + case 1933: + return "xmapi", true + case 1934: + return "xaapi", true + case 1935: + return "macromedia-fcs", true + case 1936: + return "jetcmeserver", true + case 1937: + return "jwserver", true + case 1938: + return "jwclient", true + case 1939: + return "jvserver", true + case 1940: + return "jvclient", true + case 1941: + return "dic-aida", true + case 1942: + return "res", true + case 1943: + return "beeyond-media", true + case 1944: + return "close-combat", true + case 1945: + return "dialogic-elmd", true + case 1946: + return "tekpls", true + case 1947: + return "sentinelsrm", true + case 1948: + return "eye2eye", true + case 1949: + return "ismaeasdaqlive", true + case 1950: + return "ismaeasdaqtest", true + case 1951: + return "bcs-lmserver", true + case 1952: + return "mpnjsc", true + case 1953: + return "rapidbase", true + case 1954: + return "abr-api", true + case 1955: + return "abr-secure", true + case 1956: + return "vrtl-vmf-ds", true + case 1957: + return "unix-status", true + case 1958: + return "dxadmind", true + case 1959: + return "simp-all", true + case 1960: + return "nasmanager", true + case 1961: + return "bts-appserver", true + case 1962: + return "biap-mp", true + case 1963: + return "webmachine", true + case 1964: + return "solid-e-engine", true + case 1965: + return "tivoli-npm", true + case 1966: + return "slush", true + case 1967: + return "sns-quote", true + case 1968: + return "lipsinc", true + case 1969: + return "lipsinc1", true + case 1970: + return "netop-rc", true + case 1971: + return "netop-school", true + case 1972: + return "intersys-cache", true + case 1973: + return "dlsrap", true + case 1974: + return "drp", true + case 1975: + return "tcoflashagent", true + case 1976: + return "tcoregagent", true + case 1977: + return "tcoaddressbook", true + case 1978: + return "unisql", true + case 1979: + return "unisql-java", true + case 1980: + return "pearldoc-xact", true + case 1981: + return "p2pq", true + case 1982: + return "estamp", true + case 1983: + return "lhtp", true + case 1984: + return "bb", true + case 1985: + return "hsrp", true + case 1986: + return "licensedaemon", true + case 1987: + return "tr-rsrb-p1", true + case 1988: + return "tr-rsrb-p2", true + case 1989: + return "tr-rsrb-p3", true + case 1990: + return "stun-p1", true + case 1991: + return "stun-p2", true + case 1992: + return "stun-p3", true + case 1993: + return "snmp-tcp-port", true + case 1994: + return "stun-port", true + case 1995: + return "perf-port", true + case 1996: + return "tr-rsrb-port", true + case 1997: + return "gdp-port", true + case 1998: + return "x25-svc-port", true + case 1999: + return "tcp-id-port", true + case 2000: + return "cisco-sccp", true + case 2001: + return "dc", true + case 2002: + return "globe", true + case 2003: + return "brutus", true + case 2004: + return "mailbox", true + case 2005: + return "berknet", true + case 2006: + return "invokator", true + case 2007: + return "dectalk", true + case 2008: + return "conf", true + case 2009: + return "news", true + case 2010: + return "search", true + case 2011: + return "raid-cc", true + case 2012: + return "ttyinfo", true + case 2013: + return "raid-am", true + case 2014: + return "troff", true + case 2015: + return "cypress", true + case 2016: + return "bootserver", true + case 2017: + return "cypress-stat", true + case 2018: + return "terminaldb", true + case 2019: + return "whosockami", true + case 2020: + return "xinupageserver", true + case 2021: + return "servexec", true + case 2022: + return "down", true + case 2023: + return "xinuexpansion3", true + case 2024: + return "xinuexpansion4", true + case 2025: + return "ellpack", true + case 2026: + return "scrabble", true + case 2027: + return "shadowserver", true + case 2028: + return "submitserver", true + case 2029: + return "hsrpv6", true + case 2030: + return "device2", true + case 2031: + return "mobrien-chat", true + case 2032: + return "blackboard", true + case 2033: + return "glogger", true + case 2034: + return "scoremgr", true + case 2035: + return "imsldoc", true + case 2036: + return "e-dpnet", true + case 2037: + return "applus", true + case 2038: + return "objectmanager", true + case 2039: + return "prizma", true + case 2040: + return "lam", true + case 2041: + return "interbase", true + case 2042: + return "isis", true + case 2043: + return "isis-bcast", true + case 2044: + return "rimsl", true + case 2045: + return "cdfunc", true + case 2046: + return "sdfunc", true + case 2047: + return "dls", true + case 2048: + return "dls-monitor", true + case 2049: + return "shilp", true + case 2050: + return "av-emb-config", true + case 2051: + return "epnsdp", true + case 2052: + return "clearvisn", true + case 2053: + return "lot105-ds-upd", true + case 2054: + return "weblogin", true + case 2055: + return "iop", true + case 2056: + return "omnisky", true + case 2057: + return "rich-cp", true + case 2058: + return "newwavesearch", true + case 2059: + return "bmc-messaging", true + case 2060: + return "teleniumdaemon", true + case 2061: + return "netmount", true + case 2062: + return "icg-swp", true + case 2063: + return "icg-bridge", true + case 2064: + return "icg-iprelay", true + case 2065: + return "dlsrpn", true + case 2066: + return "aura", true + case 2067: + return "dlswpn", true + case 2068: + return "avauthsrvprtcl", true + case 2069: + return "event-port", true + case 2070: + return "ah-esp-encap", true + case 2071: + return "acp-port", true + case 2072: + return "msync", true + case 2073: + return "gxs-data-port", true + case 2074: + return "vrtl-vmf-sa", true + case 2075: + return "newlixengine", true + case 2076: + return "newlixconfig", true + case 2077: + return "tsrmagt", true + case 2078: + return "tpcsrvr", true + case 2079: + return "idware-router", true + case 2080: + return "autodesk-nlm", true + case 2081: + return "kme-trap-port", true + case 2082: + return "infowave", true + case 2083: + return "radsec", true + case 2084: + return "sunclustergeo", true + case 2085: + return "ada-cip", true + case 2086: + return "gnunet", true + case 2087: + return "eli", true + case 2088: + return "ip-blf", true + case 2089: + return "sep", true + case 2090: + return "lrp", true + case 2091: + return "prp", true + case 2092: + return "descent3", true + case 2093: + return "nbx-cc", true + case 2094: + return "nbx-au", true + case 2095: + return "nbx-ser", true + case 2096: + return "nbx-dir", true + case 2097: + return "jetformpreview", true + case 2098: + return "dialog-port", true + case 2099: + return "h2250-annex-g", true + case 2100: + return "amiganetfs", true + case 2101: + return "rtcm-sc104", true + case 2102: + return "zephyr-srv", true + case 2103: + return "zephyr-clt", true + case 2104: + return "zephyr-hm", true + case 2105: + return "minipay", true + case 2106: + return "mzap", true + case 2107: + return "bintec-admin", true + case 2108: + return "comcam", true + case 2109: + return "ergolight", true + case 2110: + return "umsp", true + case 2111: + return "dsatp", true + case 2112: + return "idonix-metanet", true + case 2113: + return "hsl-storm", true + case 2114: + return "ariascribe", true + case 2115: + return "kdm", true + case 2116: + return "ccowcmr", true + case 2117: + return "mentaclient", true + case 2118: + return "mentaserver", true + case 2119: + return "gsigatekeeper", true + case 2120: + return "qencp", true + case 2121: + return "scientia-ssdb", true + case 2122: + return "caupc-remote", true + case 2123: + return "gtp-control", true + case 2124: + return "elatelink", true + case 2125: + return "lockstep", true + case 2126: + return "pktcable-cops", true + case 2127: + return "index-pc-wb", true + case 2128: + return "net-steward", true + case 2129: + return "cs-live", true + case 2130: + return "xds", true + case 2131: + return "avantageb2b", true + case 2132: + return "solera-epmap", true + case 2133: + return "zymed-zpp", true + case 2134: + return "avenue", true + case 2135: + return "gris", true + case 2136: + return "appworxsrv", true + case 2137: + return "connect", true + case 2138: + return "unbind-cluster", true + case 2139: + return "ias-auth", true + case 2140: + return "ias-reg", true + case 2141: + return "ias-admind", true + case 2142: + return "tdmoip", true + case 2143: + return "lv-jc", true + case 2144: + return "lv-ffx", true + case 2145: + return "lv-pici", true + case 2146: + return "lv-not", true + case 2147: + return "lv-auth", true + case 2148: + return "veritas-ucl", true + case 2149: + return "acptsys", true + case 2150: + return "dynamic3d", true + case 2151: + return "docent", true + case 2152: + return "gtp-user", true + case 2153: + return "ctlptc", true + case 2154: + return "stdptc", true + case 2155: + return "brdptc", true + case 2156: + return "trp", true + case 2157: + return "xnds", true + case 2158: + return "touchnetplus", true + case 2159: + return "gdbremote", true + case 2160: + return "apc-2160", true + case 2161: + return "apc-2161", true + case 2162: + return "navisphere", true + case 2163: + return "navisphere-sec", true + case 2164: + return "ddns-v3", true + case 2165: + return "x-bone-api", true + case 2166: + return "iwserver", true + case 2167: + return "raw-serial", true + case 2168: + return "easy-soft-mux", true + case 2169: + return "brain", true + case 2170: + return "eyetv", true + case 2171: + return "msfw-storage", true + case 2172: + return "msfw-s-storage", true + case 2173: + return "msfw-replica", true + case 2174: + return "msfw-array", true + case 2175: + return "airsync", true + case 2176: + return "rapi", true + case 2177: + return "qwave", true + case 2178: + return "bitspeer", true + case 2179: + return "vmrdp", true + case 2180: + return "mc-gt-srv", true + case 2181: + return "eforward", true + case 2182: + return "cgn-stat", true + case 2183: + return "cgn-config", true + case 2184: + return "nvd", true + case 2185: + return "onbase-dds", true + case 2186: + return "gtaua", true + case 2187: + return "ssmc", true + case 2188: + return "radware-rpm", true + case 2189: + return "radware-rpm-s", true + case 2190: + return "tivoconnect", true + case 2191: + return "tvbus", true + case 2192: + return "asdis", true + case 2193: + return "drwcs", true + case 2197: + return "mnp-exchange", true + case 2198: + return "onehome-remote", true + case 2199: + return "onehome-help", true + case 2201: + return "ats", true + case 2202: + return "imtc-map", true + case 2203: + return "b2-runtime", true + case 2204: + return "b2-license", true + case 2205: + return "jps", true + case 2206: + return "hpocbus", true + case 2207: + return "hpssd", true + case 2208: + return "hpiod", true + case 2209: + return "rimf-ps", true + case 2210: + return "noaaport", true + case 2211: + return "emwin", true + case 2212: + return "leecoposserver", true + case 2213: + return "kali", true + case 2214: + return "rpi", true + case 2215: + return "ipcore", true + case 2216: + return "vtu-comms", true + case 2217: + return "gotodevice", true + case 2218: + return "bounzza", true + case 2219: + return "netiq-ncap", true + case 2220: + return "netiq", true + case 2221: + return "ethernet-ip-s", true + case 2222: + return "EtherNet-IP-1", true + case 2223: + return "rockwell-csp2", true + case 2224: + return "efi-mg", true + case 2225: + return "rcip-itu", true + case 2226: + return "di-drm", true + case 2227: + return "di-msg", true + case 2228: + return "ehome-ms", true + case 2229: + return "datalens", true + case 2230: + return "queueadm", true + case 2231: + return "wimaxasncp", true + case 2232: + return "ivs-video", true + case 2233: + return "infocrypt", true + case 2234: + return "directplay", true + case 2235: + return "sercomm-wlink", true + case 2236: + return "nani", true + case 2237: + return "optech-port1-lm", true + case 2238: + return "aviva-sna", true + case 2239: + return "imagequery", true + case 2240: + return "recipe", true + case 2241: + return "ivsd", true + case 2242: + return "foliocorp", true + case 2243: + return "magicom", true + case 2244: + return "nmsserver", true + case 2245: + return "hao", true + case 2246: + return "pc-mta-addrmap", true + case 2247: + return "antidotemgrsvr", true + case 2248: + return "ums", true + case 2249: + return "rfmp", true + case 2250: + return "remote-collab", true + case 2251: + return "dif-port", true + case 2252: + return "njenet-ssl", true + case 2253: + return "dtv-chan-req", true + case 2254: + return "seispoc", true + case 2255: + return "vrtp", true + case 2256: + return "pcc-mfp", true + case 2257: + return "simple-tx-rx", true + case 2258: + return "rcts", true + case 2259: + return "bid-serv", true + case 2260: + return "apc-2260", true + case 2261: + return "comotionmaster", true + case 2262: + return "comotionback", true + case 2263: + return "ecwcfg", true + case 2264: + return "apx500api-1", true + case 2265: + return "apx500api-2", true + case 2266: + return "mfserver", true + case 2267: + return "ontobroker", true + case 2268: + return "amt", true + case 2269: + return "mikey", true + case 2270: + return "starschool", true + case 2271: + return "mmcals", true + case 2272: + return "mmcal", true + case 2273: + return "mysql-im", true + case 2274: + return "pcttunnell", true + case 2275: + return "ibridge-data", true + case 2276: + return "ibridge-mgmt", true + case 2277: + return "bluectrlproxy", true + case 2278: + return "s3db", true + case 2279: + return "xmquery", true + case 2280: + return "lnvpoller", true + case 2281: + return "lnvconsole", true + case 2282: + return "lnvalarm", true + case 2283: + return "lnvstatus", true + case 2284: + return "lnvmaps", true + case 2285: + return "lnvmailmon", true + case 2286: + return "nas-metering", true + case 2287: + return "dna", true + case 2288: + return "netml", true + case 2289: + return "dict-lookup", true + case 2290: + return "sonus-logging", true + case 2291: + return "eapsp", true + case 2292: + return "mib-streaming", true + case 2293: + return "npdbgmngr", true + case 2294: + return "konshus-lm", true + case 2295: + return "advant-lm", true + case 2296: + return "theta-lm", true + case 2297: + return "d2k-datamover1", true + case 2298: + return "d2k-datamover2", true + case 2299: + return "pc-telecommute", true + case 2300: + return "cvmmon", true + case 2301: + return "cpq-wbem", true + case 2302: + return "binderysupport", true + case 2303: + return "proxy-gateway", true + case 2304: + return "attachmate-uts", true + case 2305: + return "mt-scaleserver", true + case 2306: + return "tappi-boxnet", true + case 2307: + return "pehelp", true + case 2308: + return "sdhelp", true + case 2309: + return "sdserver", true + case 2310: + return "sdclient", true + case 2311: + return "messageservice", true + case 2312: + return "wanscaler", true + case 2313: + return "iapp", true + case 2314: + return "cr-websystems", true + case 2315: + return "precise-sft", true + case 2316: + return "sent-lm", true + case 2317: + return "attachmate-g32", true + case 2318: + return "cadencecontrol", true + case 2319: + return "infolibria", true + case 2320: + return "siebel-ns", true + case 2321: + return "rdlap", true + case 2322: + return "ofsd", true + case 2323: + return "3d-nfsd", true + case 2324: + return "cosmocall", true + case 2325: + return "ansysli", true + case 2326: + return "idcp", true + case 2327: + return "xingcsm", true + case 2328: + return "netrix-sftm", true + case 2329: + return "nvd", true + case 2330: + return "tscchat", true + case 2331: + return "agentview", true + case 2332: + return "rcc-host", true + case 2333: + return "snapp", true + case 2334: + return "ace-client", true + case 2335: + return "ace-proxy", true + case 2336: + return "appleugcontrol", true + case 2337: + return "ideesrv", true + case 2338: + return "norton-lambert", true + case 2339: + return "3com-webview", true + case 2340: + return "wrs-registry", true + case 2341: + return "xiostatus", true + case 2342: + return "manage-exec", true + case 2343: + return "nati-logos", true + case 2344: + return "fcmsys", true + case 2345: + return "dbm", true + case 2346: + return "redstorm-join", true + case 2347: + return "redstorm-find", true + case 2348: + return "redstorm-info", true + case 2349: + return "redstorm-diag", true + case 2350: + return "psbserver", true + case 2351: + return "psrserver", true + case 2352: + return "pslserver", true + case 2353: + return "pspserver", true + case 2354: + return "psprserver", true + case 2355: + return "psdbserver", true + case 2356: + return "gxtelmd", true + case 2357: + return "unihub-server", true + case 2358: + return "futrix", true + case 2359: + return "flukeserver", true + case 2360: + return "nexstorindltd", true + case 2361: + return "tl1", true + case 2362: + return "digiman", true + case 2363: + return "mediacntrlnfsd", true + case 2364: + return "oi-2000", true + case 2365: + return "dbref", true + case 2366: + return "qip-login", true + case 2367: + return "service-ctrl", true + case 2368: + return "opentable", true + case 2369: + return "bif-p2p", true + case 2370: + return "l3-hbmon", true + case 2371: + return "rda", true + case 2372: + return "lanmessenger", true + case 2373: + return "remographlm", true + case 2374: + return "hydra", true + case 2375: + return "docker", true + case 2376: + return "docker-s", true + case 2377: + return "swarm", true + case 2379: + return "etcd-client", true + case 2380: + return "etcd-server", true + case 2381: + return "compaq-https", true + case 2382: + return "ms-olap3", true + case 2383: + return "ms-olap4", true + case 2384: + return "sd-request", true + case 2385: + return "sd-data", true + case 2386: + return "virtualtape", true + case 2387: + return "vsamredirector", true + case 2388: + return "mynahautostart", true + case 2389: + return "ovsessionmgr", true + case 2390: + return "rsmtp", true + case 2391: + return "3com-net-mgmt", true + case 2392: + return "tacticalauth", true + case 2393: + return "ms-olap1", true + case 2394: + return "ms-olap2", true + case 2395: + return "lan900-remote", true + case 2396: + return "wusage", true + case 2397: + return "ncl", true + case 2398: + return "orbiter", true + case 2399: + return "fmpro-fdal", true + case 2400: + return "opequus-server", true + case 2401: + return "cvspserver", true + case 2402: + return "taskmaster2000", true + case 2403: + return "taskmaster2000", true + case 2404: + return "iec-104", true + case 2405: + return "trc-netpoll", true + case 2406: + return "jediserver", true + case 2407: + return "orion", true + case 2408: + return "railgun-webaccl", true + case 2409: + return "sns-protocol", true + case 2410: + return "vrts-registry", true + case 2411: + return "netwave-ap-mgmt", true + case 2412: + return "cdn", true + case 2413: + return "orion-rmi-reg", true + case 2414: + return "beeyond", true + case 2415: + return "codima-rtp", true + case 2416: + return "rmtserver", true + case 2417: + return "composit-server", true + case 2418: + return "cas", true + case 2419: + return "attachmate-s2s", true + case 2420: + return "dslremote-mgmt", true + case 2421: + return "g-talk", true + case 2422: + return "crmsbits", true + case 2423: + return "rnrp", true + case 2424: + return "kofax-svr", true + case 2425: + return "fjitsuappmgr", true + case 2426: + return "vcmp", true + case 2427: + return "mgcp-gateway", true + case 2428: + return "ott", true + case 2429: + return "ft-role", true + case 2430: + return "venus", true + case 2431: + return "venus-se", true + case 2432: + return "codasrv", true + case 2433: + return "codasrv-se", true + case 2434: + return "pxc-epmap", true + case 2435: + return "optilogic", true + case 2436: + return "topx", true + case 2437: + return "unicontrol", true + case 2438: + return "msp", true + case 2439: + return "sybasedbsynch", true + case 2440: + return "spearway", true + case 2441: + return "pvsw-inet", true + case 2442: + return "netangel", true + case 2443: + return "powerclientcsf", true + case 2444: + return "btpp2sectrans", true + case 2445: + return "dtn1", true + case 2446: + return "bues-service", true + case 2447: + return "ovwdb", true + case 2448: + return "hpppssvr", true + case 2449: + return "ratl", true + case 2450: + return "netadmin", true + case 2451: + return "netchat", true + case 2452: + return "snifferclient", true + case 2453: + return "madge-ltd", true + case 2454: + return "indx-dds", true + case 2455: + return "wago-io-system", true + case 2456: + return "altav-remmgt", true + case 2457: + return "rapido-ip", true + case 2458: + return "griffin", true + case 2459: + return "xrpl", true + case 2460: + return "ms-theater", true + case 2461: + return "qadmifoper", true + case 2462: + return "qadmifevent", true + case 2463: + return "lsi-raid-mgmt", true + case 2464: + return "direcpc-si", true + case 2465: + return "lbm", true + case 2466: + return "lbf", true + case 2467: + return "high-criteria", true + case 2468: + return "qip-msgd", true + case 2469: + return "mti-tcs-comm", true + case 2470: + return "taskman-port", true + case 2471: + return "seaodbc", true + case 2472: + return "c3", true + case 2473: + return "aker-cdp", true + case 2474: + return "vitalanalysis", true + case 2475: + return "ace-server", true + case 2476: + return "ace-svr-prop", true + case 2477: + return "ssm-cvs", true + case 2478: + return "ssm-cssps", true + case 2479: + return "ssm-els", true + case 2480: + return "powerexchange", true + case 2481: + return "giop", true + case 2482: + return "giop-ssl", true + case 2483: + return "ttc", true + case 2484: + return "ttc-ssl", true + case 2485: + return "netobjects1", true + case 2486: + return "netobjects2", true + case 2487: + return "pns", true + case 2488: + return "moy-corp", true + case 2489: + return "tsilb", true + case 2490: + return "qip-qdhcp", true + case 2491: + return "conclave-cpp", true + case 2492: + return "groove", true + case 2493: + return "talarian-mqs", true + case 2494: + return "bmc-ar", true + case 2495: + return "fast-rem-serv", true + case 2496: + return "dirgis", true + case 2497: + return "quaddb", true + case 2498: + return "odn-castraq", true + case 2499: + return "unicontrol", true + case 2500: + return "rtsserv", true + case 2501: + return "rtsclient", true + case 2502: + return "kentrox-prot", true + case 2503: + return "nms-dpnss", true + case 2504: + return "wlbs", true + case 2505: + return "ppcontrol", true + case 2506: + return "jbroker", true + case 2507: + return "spock", true + case 2508: + return "jdatastore", true + case 2509: + return "fjmpss", true + case 2510: + return "fjappmgrbulk", true + case 2511: + return "metastorm", true + case 2512: + return "citrixima", true + case 2513: + return "citrixadmin", true + case 2514: + return "facsys-ntp", true + case 2515: + return "facsys-router", true + case 2516: + return "maincontrol", true + case 2517: + return "call-sig-trans", true + case 2518: + return "willy", true + case 2519: + return "globmsgsvc", true + case 2520: + return "pvsw", true + case 2521: + return "adaptecmgr", true + case 2522: + return "windb", true + case 2523: + return "qke-llc-v3", true + case 2524: + return "optiwave-lm", true + case 2525: + return "ms-v-worlds", true + case 2526: + return "ema-sent-lm", true + case 2527: + return "iqserver", true + case 2528: + return "ncr-ccl", true + case 2529: + return "utsftp", true + case 2530: + return "vrcommerce", true + case 2531: + return "ito-e-gui", true + case 2532: + return "ovtopmd", true + case 2533: + return "snifferserver", true + case 2534: + return "combox-web-acc", true + case 2535: + return "madcap", true + case 2536: + return "btpp2audctr1", true + case 2537: + return "upgrade", true + case 2538: + return "vnwk-prapi", true + case 2539: + return "vsiadmin", true + case 2540: + return "lonworks", true + case 2541: + return "lonworks2", true + case 2542: + return "udrawgraph", true + case 2543: + return "reftek", true + case 2544: + return "novell-zen", true + case 2545: + return "sis-emt", true + case 2546: + return "vytalvaultbrtp", true + case 2547: + return "vytalvaultvsmp", true + case 2548: + return "vytalvaultpipe", true + case 2549: + return "ipass", true + case 2550: + return "ads", true + case 2551: + return "isg-uda-server", true + case 2552: + return "call-logging", true + case 2553: + return "efidiningport", true + case 2554: + return "vcnet-link-v10", true + case 2555: + return "compaq-wcp", true + case 2556: + return "nicetec-nmsvc", true + case 2557: + return "nicetec-mgmt", true + case 2558: + return "pclemultimedia", true + case 2559: + return "lstp", true + case 2560: + return "labrat", true + case 2561: + return "mosaixcc", true + case 2562: + return "delibo", true + case 2563: + return "cti-redwood", true + case 2564: + return "hp-3000-telnet", true + case 2565: + return "coord-svr", true + case 2566: + return "pcs-pcw", true + case 2567: + return "clp", true + case 2568: + return "spamtrap", true + case 2569: + return "sonuscallsig", true + case 2570: + return "hs-port", true + case 2571: + return "cecsvc", true + case 2572: + return "ibp", true + case 2573: + return "trustestablish", true + case 2574: + return "blockade-bpsp", true + case 2575: + return "hl7", true + case 2576: + return "tclprodebugger", true + case 2577: + return "scipticslsrvr", true + case 2578: + return "rvs-isdn-dcp", true + case 2579: + return "mpfoncl", true + case 2580: + return "tributary", true + case 2581: + return "argis-te", true + case 2582: + return "argis-ds", true + case 2583: + return "mon", true + case 2584: + return "cyaserv", true + case 2585: + return "netx-server", true + case 2586: + return "netx-agent", true + case 2587: + return "masc", true + case 2588: + return "privilege", true + case 2589: + return "quartus-tcl", true + case 2590: + return "idotdist", true + case 2591: + return "maytagshuffle", true + case 2592: + return "netrek", true + case 2593: + return "mns-mail", true + case 2594: + return "dts", true + case 2595: + return "worldfusion1", true + case 2596: + return "worldfusion2", true + case 2597: + return "homesteadglory", true + case 2598: + return "citriximaclient", true + case 2599: + return "snapd", true + case 2600: + return "hpstgmgr", true + case 2601: + return "discp-client", true + case 2602: + return "discp-server", true + case 2603: + return "servicemeter", true + case 2604: + return "nsc-ccs", true + case 2605: + return "nsc-posa", true + case 2606: + return "netmon", true + case 2607: + return "connection", true + case 2608: + return "wag-service", true + case 2609: + return "system-monitor", true + case 2610: + return "versa-tek", true + case 2611: + return "lionhead", true + case 2612: + return "qpasa-agent", true + case 2613: + return "smntubootstrap", true + case 2614: + return "neveroffline", true + case 2615: + return "firepower", true + case 2616: + return "appswitch-emp", true + case 2617: + return "cmadmin", true + case 2618: + return "priority-e-com", true + case 2619: + return "bruce", true + case 2620: + return "lpsrecommender", true + case 2621: + return "miles-apart", true + case 2622: + return "metricadbc", true + case 2623: + return "lmdp", true + case 2624: + return "aria", true + case 2625: + return "blwnkl-port", true + case 2626: + return "gbjd816", true + case 2627: + return "moshebeeri", true + case 2628: + return "dict", true + case 2629: + return "sitaraserver", true + case 2630: + return "sitaramgmt", true + case 2631: + return "sitaradir", true + case 2632: + return "irdg-post", true + case 2633: + return "interintelli", true + case 2634: + return "pk-electronics", true + case 2635: + return "backburner", true + case 2636: + return "solve", true + case 2637: + return "imdocsvc", true + case 2638: + return "sybaseanywhere", true + case 2639: + return "aminet", true + case 2640: + return "ami-control", true + case 2641: + return "hdl-srv", true + case 2642: + return "tragic", true + case 2643: + return "gte-samp", true + case 2644: + return "travsoft-ipx-t", true + case 2645: + return "novell-ipx-cmd", true + case 2646: + return "and-lm", true + case 2647: + return "syncserver", true + case 2648: + return "upsnotifyprot", true + case 2649: + return "vpsipport", true + case 2650: + return "eristwoguns", true + case 2651: + return "ebinsite", true + case 2652: + return "interpathpanel", true + case 2653: + return "sonus", true + case 2654: + return "corel-vncadmin", true + case 2655: + return "unglue", true + case 2656: + return "kana", true + case 2657: + return "sns-dispatcher", true + case 2658: + return "sns-admin", true + case 2659: + return "sns-query", true + case 2660: + return "gcmonitor", true + case 2661: + return "olhost", true + case 2662: + return "bintec-capi", true + case 2663: + return "bintec-tapi", true + case 2664: + return "patrol-mq-gm", true + case 2665: + return "patrol-mq-nm", true + case 2666: + return "extensis", true + case 2667: + return "alarm-clock-s", true + case 2668: + return "alarm-clock-c", true + case 2669: + return "toad", true + case 2670: + return "tve-announce", true + case 2671: + return "newlixreg", true + case 2672: + return "nhserver", true + case 2673: + return "firstcall42", true + case 2674: + return "ewnn", true + case 2675: + return "ttc-etap", true + case 2676: + return "simslink", true + case 2677: + return "gadgetgate1way", true + case 2678: + return "gadgetgate2way", true + case 2679: + return "syncserverssl", true + case 2680: + return "pxc-sapxom", true + case 2681: + return "mpnjsomb", true + case 2683: + return "ncdloadbalance", true + case 2684: + return "mpnjsosv", true + case 2685: + return "mpnjsocl", true + case 2686: + return "mpnjsomg", true + case 2687: + return "pq-lic-mgmt", true + case 2688: + return "md-cg-http", true + case 2689: + return "fastlynx", true + case 2690: + return "hp-nnm-data", true + case 2691: + return "itinternet", true + case 2692: + return "admins-lms", true + case 2694: + return "pwrsevent", true + case 2695: + return "vspread", true + case 2696: + return "unifyadmin", true + case 2697: + return "oce-snmp-trap", true + case 2698: + return "mck-ivpip", true + case 2699: + return "csoft-plusclnt", true + case 2700: + return "tqdata", true + case 2701: + return "sms-rcinfo", true + case 2702: + return "sms-xfer", true + case 2703: + return "sms-chat", true + case 2704: + return "sms-remctrl", true + case 2705: + return "sds-admin", true + case 2706: + return "ncdmirroring", true + case 2707: + return "emcsymapiport", true + case 2708: + return "banyan-net", true + case 2709: + return "supermon", true + case 2710: + return "sso-service", true + case 2711: + return "sso-control", true + case 2712: + return "aocp", true + case 2713: + return "raventbs", true + case 2714: + return "raventdm", true + case 2715: + return "hpstgmgr2", true + case 2716: + return "inova-ip-disco", true + case 2717: + return "pn-requester", true + case 2718: + return "pn-requester2", true + case 2719: + return "scan-change", true + case 2720: + return "wkars", true + case 2721: + return "smart-diagnose", true + case 2722: + return "proactivesrvr", true + case 2723: + return "watchdog-nt", true + case 2724: + return "qotps", true + case 2725: + return "msolap-ptp2", true + case 2726: + return "tams", true + case 2727: + return "mgcp-callagent", true + case 2728: + return "sqdr", true + case 2729: + return "tcim-control", true + case 2730: + return "nec-raidplus", true + case 2731: + return "fyre-messanger", true + case 2732: + return "g5m", true + case 2733: + return "signet-ctf", true + case 2734: + return "ccs-software", true + case 2735: + return "netiq-mc", true + case 2736: + return "radwiz-nms-srv", true + case 2737: + return "srp-feedback", true + case 2738: + return "ndl-tcp-ois-gw", true + case 2739: + return "tn-timing", true + case 2740: + return "alarm", true + case 2741: + return "tsb", true + case 2742: + return "tsb2", true + case 2743: + return "murx", true + case 2744: + return "honyaku", true + case 2745: + return "urbisnet", true + case 2746: + return "cpudpencap", true + case 2747: + return "fjippol-swrly", true + case 2748: + return "fjippol-polsvr", true + case 2749: + return "fjippol-cnsl", true + case 2750: + return "fjippol-port1", true + case 2751: + return "fjippol-port2", true + case 2752: + return "rsisysaccess", true + case 2753: + return "de-spot", true + case 2754: + return "apollo-cc", true + case 2755: + return "expresspay", true + case 2756: + return "simplement-tie", true + case 2757: + return "cnrp", true + case 2758: + return "apollo-status", true + case 2759: + return "apollo-gms", true + case 2760: + return "sabams", true + case 2761: + return "dicom-iscl", true + case 2762: + return "dicom-tls", true + case 2763: + return "desktop-dna", true + case 2764: + return "data-insurance", true + case 2765: + return "qip-audup", true + case 2766: + return "compaq-scp", true + case 2767: + return "uadtc", true + case 2768: + return "uacs", true + case 2769: + return "exce", true + case 2770: + return "veronica", true + case 2771: + return "vergencecm", true + case 2772: + return "auris", true + case 2773: + return "rbakcup1", true + case 2774: + return "rbakcup2", true + case 2775: + return "smpp", true + case 2776: + return "ridgeway1", true + case 2777: + return "ridgeway2", true + case 2778: + return "gwen-sonya", true + case 2779: + return "lbc-sync", true + case 2780: + return "lbc-control", true + case 2781: + return "whosells", true + case 2782: + return "everydayrc", true + case 2783: + return "aises", true + case 2784: + return "www-dev", true + case 2785: + return "aic-np", true + case 2786: + return "aic-oncrpc", true + case 2787: + return "piccolo", true + case 2788: + return "fryeserv", true + case 2789: + return "media-agent", true + case 2790: + return "plgproxy", true + case 2791: + return "mtport-regist", true + case 2792: + return "f5-globalsite", true + case 2793: + return "initlsmsad", true + case 2795: + return "livestats", true + case 2796: + return "ac-tech", true + case 2797: + return "esp-encap", true + case 2798: + return "tmesis-upshot", true + case 2799: + return "icon-discover", true + case 2800: + return "acc-raid", true + case 2801: + return "igcp", true + case 2802: + return "veritas-tcp1", true + case 2803: + return "btprjctrl", true + case 2804: + return "dvr-esm", true + case 2805: + return "wta-wsp-s", true + case 2806: + return "cspuni", true + case 2807: + return "cspmulti", true + case 2808: + return "j-lan-p", true + case 2809: + return "corbaloc", true + case 2810: + return "netsteward", true + case 2811: + return "gsiftp", true + case 2812: + return "atmtcp", true + case 2813: + return "llm-pass", true + case 2814: + return "llm-csv", true + case 2815: + return "lbc-measure", true + case 2816: + return "lbc-watchdog", true + case 2817: + return "nmsigport", true + case 2818: + return "rmlnk", true + case 2819: + return "fc-faultnotify", true + case 2820: + return "univision", true + case 2821: + return "vrts-at-port", true + case 2822: + return "ka0wuc", true + case 2823: + return "cqg-netlan", true + case 2824: + return "cqg-netlan-1", true + case 2826: + return "slc-systemlog", true + case 2827: + return "slc-ctrlrloops", true + case 2828: + return "itm-lm", true + case 2829: + return "silkp1", true + case 2830: + return "silkp2", true + case 2831: + return "silkp3", true + case 2832: + return "silkp4", true + case 2833: + return "glishd", true + case 2834: + return "evtp", true + case 2835: + return "evtp-data", true + case 2836: + return "catalyst", true + case 2837: + return "repliweb", true + case 2838: + return "starbot", true + case 2839: + return "nmsigport", true + case 2840: + return "l3-exprt", true + case 2841: + return "l3-ranger", true + case 2842: + return "l3-hawk", true + case 2843: + return "pdnet", true + case 2844: + return "bpcp-poll", true + case 2845: + return "bpcp-trap", true + case 2846: + return "aimpp-hello", true + case 2847: + return "aimpp-port-req", true + case 2848: + return "amt-blc-port", true + case 2849: + return "fxp", true + case 2850: + return "metaconsole", true + case 2851: + return "webemshttp", true + case 2852: + return "bears-01", true + case 2853: + return "ispipes", true + case 2854: + return "infomover", true + case 2855: + return "msrp", true + case 2856: + return "cesdinv", true + case 2857: + return "simctlp", true + case 2858: + return "ecnp", true + case 2859: + return "activememory", true + case 2860: + return "dialpad-voice1", true + case 2861: + return "dialpad-voice2", true + case 2862: + return "ttg-protocol", true + case 2863: + return "sonardata", true + case 2864: + return "astronova-main", true + case 2865: + return "pit-vpn", true + case 2866: + return "iwlistener", true + case 2867: + return "esps-portal", true + case 2868: + return "npep-messaging", true + case 2869: + return "icslap", true + case 2870: + return "daishi", true + case 2871: + return "msi-selectplay", true + case 2872: + return "radix", true + case 2873: + return "psrt", true + case 2874: + return "dxmessagebase1", true + case 2875: + return "dxmessagebase2", true + case 2876: + return "sps-tunnel", true + case 2877: + return "bluelance", true + case 2878: + return "aap", true + case 2879: + return "ucentric-ds", true + case 2880: + return "synapse", true + case 2881: + return "ndsp", true + case 2882: + return "ndtp", true + case 2883: + return "ndnp", true + case 2884: + return "flashmsg", true + case 2885: + return "topflow", true + case 2886: + return "responselogic", true + case 2887: + return "aironetddp", true + case 2888: + return "spcsdlobby", true + case 2889: + return "rsom", true + case 2890: + return "cspclmulti", true + case 2891: + return "cinegrfx-elmd", true + case 2892: + return "snifferdata", true + case 2893: + return "vseconnector", true + case 2894: + return "abacus-remote", true + case 2895: + return "natuslink", true + case 2896: + return "ecovisiong6-1", true + case 2897: + return "citrix-rtmp", true + case 2898: + return "appliance-cfg", true + case 2899: + return "powergemplus", true + case 2900: + return "quicksuite", true + case 2901: + return "allstorcns", true + case 2902: + return "netaspi", true + case 2903: + return "suitcase", true + case 2904: + return "m2ua", true + case 2905: + return "m3ua", true + case 2906: + return "caller9", true + case 2907: + return "webmethods-b2b", true + case 2908: + return "mao", true + case 2909: + return "funk-dialout", true + case 2910: + return "tdaccess", true + case 2911: + return "blockade", true + case 2912: + return "epicon", true + case 2913: + return "boosterware", true + case 2914: + return "gamelobby", true + case 2915: + return "tksocket", true + case 2916: + return "elvin-server", true + case 2917: + return "elvin-client", true + case 2918: + return "kastenchasepad", true + case 2919: + return "roboer", true + case 2920: + return "roboeda", true + case 2921: + return "cesdcdman", true + case 2922: + return "cesdcdtrn", true + case 2923: + return "wta-wsp-wtp-s", true + case 2924: + return "precise-vip", true + case 2926: + return "mobile-file-dl", true + case 2927: + return "unimobilectrl", true + case 2928: + return "redstone-cpss", true + case 2929: + return "amx-webadmin", true + case 2930: + return "amx-weblinx", true + case 2931: + return "circle-x", true + case 2932: + return "incp", true + case 2933: + return "4-tieropmgw", true + case 2934: + return "4-tieropmcli", true + case 2935: + return "qtp", true + case 2936: + return "otpatch", true + case 2937: + return "pnaconsult-lm", true + case 2938: + return "sm-pas-1", true + case 2939: + return "sm-pas-2", true + case 2940: + return "sm-pas-3", true + case 2941: + return "sm-pas-4", true + case 2942: + return "sm-pas-5", true + case 2943: + return "ttnrepository", true + case 2944: + return "megaco-h248", true + case 2945: + return "h248-binary", true + case 2946: + return "fjsvmpor", true + case 2947: + return "gpsd", true + case 2948: + return "wap-push", true + case 2949: + return "wap-pushsecure", true + case 2950: + return "esip", true + case 2951: + return "ottp", true + case 2952: + return "mpfwsas", true + case 2953: + return "ovalarmsrv", true + case 2954: + return "ovalarmsrv-cmd", true + case 2955: + return "csnotify", true + case 2956: + return "ovrimosdbman", true + case 2957: + return "jmact5", true + case 2958: + return "jmact6", true + case 2959: + return "rmopagt", true + case 2960: + return "dfoxserver", true + case 2961: + return "boldsoft-lm", true + case 2962: + return "iph-policy-cli", true + case 2963: + return "iph-policy-adm", true + case 2964: + return "bullant-srap", true + case 2965: + return "bullant-rap", true + case 2966: + return "idp-infotrieve", true + case 2967: + return "ssc-agent", true + case 2968: + return "enpp", true + case 2969: + return "essp", true + case 2970: + return "index-net", true + case 2971: + return "netclip", true + case 2972: + return "pmsm-webrctl", true + case 2973: + return "svnetworks", true + case 2974: + return "signal", true + case 2975: + return "fjmpcm", true + case 2976: + return "cns-srv-port", true + case 2977: + return "ttc-etap-ns", true + case 2978: + return "ttc-etap-ds", true + case 2979: + return "h263-video", true + case 2980: + return "wimd", true + case 2981: + return "mylxamport", true + case 2982: + return "iwb-whiteboard", true + case 2983: + return "netplan", true + case 2984: + return "hpidsadmin", true + case 2985: + return "hpidsagent", true + case 2986: + return "stonefalls", true + case 2987: + return "identify", true + case 2988: + return "hippad", true + case 2989: + return "zarkov", true + case 2990: + return "boscap", true + case 2991: + return "wkstn-mon", true + case 2992: + return "avenyo", true + case 2993: + return "veritas-vis1", true + case 2994: + return "veritas-vis2", true + case 2995: + return "idrs", true + case 2996: + return "vsixml", true + case 2997: + return "rebol", true + case 2998: + return "realsecure", true + case 2999: + return "remoteware-un", true + case 3000: + return "hbci", true + case 3001: + return "origo-native", true + case 3002: + return "exlm-agent", true + case 3003: + return "cgms", true + case 3004: + return "csoftragent", true + case 3005: + return "geniuslm", true + case 3006: + return "ii-admin", true + case 3007: + return "lotusmtap", true + case 3008: + return "midnight-tech", true + case 3009: + return "pxc-ntfy", true + case 3010: + return "gw", true + case 3011: + return "trusted-web", true + case 3012: + return "twsdss", true + case 3013: + return "gilatskysurfer", true + case 3014: + return "broker-service", true + case 3015: + return "nati-dstp", true + case 3016: + return "notify-srvr", true + case 3017: + return "event-listener", true + case 3018: + return "srvc-registry", true + case 3019: + return "resource-mgr", true + case 3020: + return "cifs", true + case 3021: + return "agriserver", true + case 3022: + return "csregagent", true + case 3023: + return "magicnotes", true + case 3024: + return "nds-sso", true + case 3025: + return "arepa-raft", true + case 3026: + return "agri-gateway", true + case 3027: + return "LiebDevMgmt-C", true + case 3028: + return "LiebDevMgmt-DM", true + case 3029: + return "LiebDevMgmt-A", true + case 3030: + return "arepa-cas", true + case 3031: + return "eppc", true + case 3032: + return "redwood-chat", true + case 3033: + return "pdb", true + case 3034: + return "osmosis-aeea", true + case 3035: + return "fjsv-gssagt", true + case 3036: + return "hagel-dump", true + case 3037: + return "hp-san-mgmt", true + case 3038: + return "santak-ups", true + case 3039: + return "cogitate", true + case 3040: + return "tomato-springs", true + case 3041: + return "di-traceware", true + case 3042: + return "journee", true + case 3043: + return "brp", true + case 3044: + return "epp", true + case 3045: + return "responsenet", true + case 3046: + return "di-ase", true + case 3047: + return "hlserver", true + case 3048: + return "pctrader", true + case 3049: + return "nsws", true + case 3050: + return "gds-db", true + case 3051: + return "galaxy-server", true + case 3052: + return "apc-3052", true + case 3053: + return "dsom-server", true + case 3054: + return "amt-cnf-prot", true + case 3055: + return "policyserver", true + case 3056: + return "cdl-server", true + case 3057: + return "goahead-fldup", true + case 3058: + return "videobeans", true + case 3059: + return "qsoft", true + case 3060: + return "interserver", true + case 3061: + return "cautcpd", true + case 3062: + return "ncacn-ip-tcp", true + case 3063: + return "ncadg-ip-udp", true + case 3064: + return "rprt", true + case 3065: + return "slinterbase", true + case 3066: + return "netattachsdmp", true + case 3067: + return "fjhpjp", true + case 3068: + return "ls3bcast", true + case 3069: + return "ls3", true + case 3070: + return "mgxswitch", true + case 3071: + return "xplat-replicate", true + case 3072: + return "csd-monitor", true + case 3073: + return "vcrp", true + case 3074: + return "xbox", true + case 3075: + return "orbix-locator", true + case 3076: + return "orbix-config", true + case 3077: + return "orbix-loc-ssl", true + case 3078: + return "orbix-cfg-ssl", true + case 3079: + return "lv-frontpanel", true + case 3080: + return "stm-pproc", true + case 3081: + return "tl1-lv", true + case 3082: + return "tl1-raw", true + case 3083: + return "tl1-telnet", true + case 3084: + return "itm-mccs", true + case 3085: + return "pcihreq", true + case 3086: + return "jdl-dbkitchen", true + case 3087: + return "asoki-sma", true + case 3088: + return "xdtp", true + case 3089: + return "ptk-alink", true + case 3090: + return "stss", true + case 3091: + return "1ci-smcs", true + case 3093: + return "rapidmq-center", true + case 3094: + return "rapidmq-reg", true + case 3095: + return "panasas", true + case 3096: + return "ndl-aps", true + case 3098: + return "umm-port", true + case 3099: + return "chmd", true + case 3100: + return "opcon-xps", true + case 3101: + return "hp-pxpib", true + case 3102: + return "slslavemon", true + case 3103: + return "autocuesmi", true + case 3104: + return "autocuelog", true + case 3105: + return "cardbox", true + case 3106: + return "cardbox-http", true + case 3107: + return "business", true + case 3108: + return "geolocate", true + case 3109: + return "personnel", true + case 3110: + return "sim-control", true + case 3111: + return "wsynch", true + case 3112: + return "ksysguard", true + case 3113: + return "cs-auth-svr", true + case 3114: + return "ccmad", true + case 3115: + return "mctet-master", true + case 3116: + return "mctet-gateway", true + case 3117: + return "mctet-jserv", true + case 3118: + return "pkagent", true + case 3119: + return "d2000kernel", true + case 3120: + return "d2000webserver", true + case 3121: + return "pcmk-remote", true + case 3122: + return "vtr-emulator", true + case 3123: + return "edix", true + case 3124: + return "beacon-port", true + case 3125: + return "a13-an", true + case 3127: + return "ctx-bridge", true + case 3128: + return "ndl-aas", true + case 3129: + return "netport-id", true + case 3130: + return "icpv2", true + case 3131: + return "netbookmark", true + case 3132: + return "ms-rule-engine", true + case 3133: + return "prism-deploy", true + case 3134: + return "ecp", true + case 3135: + return "peerbook-port", true + case 3136: + return "grubd", true + case 3137: + return "rtnt-1", true + case 3138: + return "rtnt-2", true + case 3139: + return "incognitorv", true + case 3140: + return "ariliamulti", true + case 3141: + return "vmodem", true + case 3142: + return "rdc-wh-eos", true + case 3143: + return "seaview", true + case 3144: + return "tarantella", true + case 3145: + return "csi-lfap", true + case 3146: + return "bears-02", true + case 3147: + return "rfio", true + case 3148: + return "nm-game-admin", true + case 3149: + return "nm-game-server", true + case 3150: + return "nm-asses-admin", true + case 3151: + return "nm-assessor", true + case 3152: + return "feitianrockey", true + case 3153: + return "s8-client-port", true + case 3154: + return "ccmrmi", true + case 3155: + return "jpegmpeg", true + case 3156: + return "indura", true + case 3157: + return "e3consultants", true + case 3158: + return "stvp", true + case 3159: + return "navegaweb-port", true + case 3160: + return "tip-app-server", true + case 3161: + return "doc1lm", true + case 3162: + return "sflm", true + case 3163: + return "res-sap", true + case 3164: + return "imprs", true + case 3165: + return "newgenpay", true + case 3166: + return "sossecollector", true + case 3167: + return "nowcontact", true + case 3168: + return "poweronnud", true + case 3169: + return "serverview-as", true + case 3170: + return "serverview-asn", true + case 3171: + return "serverview-gf", true + case 3172: + return "serverview-rm", true + case 3173: + return "serverview-icc", true + case 3174: + return "armi-server", true + case 3175: + return "t1-e1-over-ip", true + case 3176: + return "ars-master", true + case 3177: + return "phonex-port", true + case 3178: + return "radclientport", true + case 3179: + return "h2gf-w-2m", true + case 3180: + return "mc-brk-srv", true + case 3181: + return "bmcpatrolagent", true + case 3182: + return "bmcpatrolrnvu", true + case 3183: + return "cops-tls", true + case 3184: + return "apogeex-port", true + case 3185: + return "smpppd", true + case 3186: + return "iiw-port", true + case 3187: + return "odi-port", true + case 3188: + return "brcm-comm-port", true + case 3189: + return "pcle-infex", true + case 3190: + return "csvr-proxy", true + case 3191: + return "csvr-sslproxy", true + case 3192: + return "firemonrcc", true + case 3193: + return "spandataport", true + case 3194: + return "magbind", true + case 3195: + return "ncu-1", true + case 3196: + return "ncu-2", true + case 3197: + return "embrace-dp-s", true + case 3198: + return "embrace-dp-c", true + case 3199: + return "dmod-workspace", true + case 3200: + return "tick-port", true + case 3201: + return "cpq-tasksmart", true + case 3202: + return "intraintra", true + case 3203: + return "netwatcher-mon", true + case 3204: + return "netwatcher-db", true + case 3205: + return "isns", true + case 3206: + return "ironmail", true + case 3207: + return "vx-auth-port", true + case 3208: + return "pfu-prcallback", true + case 3209: + return "netwkpathengine", true + case 3210: + return "flamenco-proxy", true + case 3211: + return "avsecuremgmt", true + case 3212: + return "surveyinst", true + case 3213: + return "neon24x7", true + case 3214: + return "jmq-daemon-1", true + case 3215: + return "jmq-daemon-2", true + case 3216: + return "ferrari-foam", true + case 3217: + return "unite", true + case 3218: + return "smartpackets", true + case 3219: + return "wms-messenger", true + case 3220: + return "xnm-ssl", true + case 3221: + return "xnm-clear-text", true + case 3222: + return "glbp", true + case 3223: + return "digivote", true + case 3224: + return "aes-discovery", true + case 3225: + return "fcip-port", true + case 3226: + return "isi-irp", true + case 3227: + return "dwnmshttp", true + case 3228: + return "dwmsgserver", true + case 3229: + return "global-cd-port", true + case 3230: + return "sftdst-port", true + case 3231: + return "vidigo", true + case 3232: + return "mdtp", true + case 3233: + return "whisker", true + case 3234: + return "alchemy", true + case 3235: + return "mdap-port", true + case 3236: + return "apparenet-ts", true + case 3237: + return "apparenet-tps", true + case 3238: + return "apparenet-as", true + case 3239: + return "apparenet-ui", true + case 3240: + return "triomotion", true + case 3241: + return "sysorb", true + case 3242: + return "sdp-id-port", true + case 3243: + return "timelot", true + case 3244: + return "onesaf", true + case 3245: + return "vieo-fe", true + case 3246: + return "dvt-system", true + case 3247: + return "dvt-data", true + case 3248: + return "procos-lm", true + case 3249: + return "ssp", true + case 3250: + return "hicp", true + case 3251: + return "sysscanner", true + case 3252: + return "dhe", true + case 3253: + return "pda-data", true + case 3254: + return "pda-sys", true + case 3255: + return "semaphore", true + case 3256: + return "cpqrpm-agent", true + case 3257: + return "cpqrpm-server", true + case 3258: + return "ivecon-port", true + case 3259: + return "epncdp2", true + case 3260: + return "iscsi-target", true + case 3261: + return "winshadow", true + case 3262: + return "necp", true + case 3263: + return "ecolor-imager", true + case 3264: + return "ccmail", true + case 3265: + return "altav-tunnel", true + case 3266: + return "ns-cfg-server", true + case 3267: + return "ibm-dial-out", true + case 3268: + return "msft-gc", true + case 3269: + return "msft-gc-ssl", true + case 3270: + return "verismart", true + case 3271: + return "csoft-prev", true + case 3272: + return "user-manager", true + case 3273: + return "sxmp", true + case 3274: + return "ordinox-server", true + case 3275: + return "samd", true + case 3276: + return "maxim-asics", true + case 3277: + return "awg-proxy", true + case 3278: + return "lkcmserver", true + case 3279: + return "admind", true + case 3280: + return "vs-server", true + case 3281: + return "sysopt", true + case 3282: + return "datusorb", true + case 3283: + return "Apple Remote Desktop (Net Assistant)", true + case 3284: + return "4talk", true + case 3285: + return "plato", true + case 3286: + return "e-net", true + case 3287: + return "directvdata", true + case 3288: + return "cops", true + case 3289: + return "enpc", true + case 3290: + return "caps-lm", true + case 3291: + return "sah-lm", true + case 3292: + return "cart-o-rama", true + case 3293: + return "fg-fps", true + case 3294: + return "fg-gip", true + case 3295: + return "dyniplookup", true + case 3296: + return "rib-slm", true + case 3297: + return "cytel-lm", true + case 3298: + return "deskview", true + case 3299: + return "pdrncs", true + case 3300: + return "ceph", true + case 3301: + return "tarantool", true + case 3302: + return "mcs-fastmail", true + case 3303: + return "opsession-clnt", true + case 3304: + return "opsession-srvr", true + case 3305: + return "odette-ftp", true + case 3306: + return "mysql", true + case 3307: + return "opsession-prxy", true + case 3308: + return "tns-server", true + case 3309: + return "tns-adv", true + case 3310: + return "dyna-access", true + case 3311: + return "mcns-tel-ret", true + case 3312: + return "appman-server", true + case 3313: + return "uorb", true + case 3314: + return "uohost", true + case 3315: + return "cdid", true + case 3316: + return "aicc-cmi", true + case 3317: + return "vsaiport", true + case 3318: + return "ssrip", true + case 3319: + return "sdt-lmd", true + case 3320: + return "officelink2000", true + case 3321: + return "vnsstr", true + case 3326: + return "sftu", true + case 3327: + return "bbars", true + case 3328: + return "egptlm", true + case 3329: + return "hp-device-disc", true + case 3330: + return "mcs-calypsoicf", true + case 3331: + return "mcs-messaging", true + case 3332: + return "mcs-mailsvr", true + case 3333: + return "dec-notes", true + case 3334: + return "directv-web", true + case 3335: + return "directv-soft", true + case 3336: + return "directv-tick", true + case 3337: + return "directv-catlg", true + case 3338: + return "anet-b", true + case 3339: + return "anet-l", true + case 3340: + return "anet-m", true + case 3341: + return "anet-h", true + case 3342: + return "webtie", true + case 3343: + return "ms-cluster-net", true + case 3344: + return "bnt-manager", true + case 3345: + return "influence", true + case 3346: + return "trnsprntproxy", true + case 3347: + return "phoenix-rpc", true + case 3348: + return "pangolin-laser", true + case 3349: + return "chevinservices", true + case 3350: + return "findviatv", true + case 3351: + return "btrieve", true + case 3352: + return "ssql", true + case 3353: + return "fatpipe", true + case 3354: + return "suitjd", true + case 3355: + return "ordinox-dbase", true + case 3356: + return "upnotifyps", true + case 3357: + return "adtech-test", true + case 3358: + return "mpsysrmsvr", true + case 3359: + return "wg-netforce", true + case 3360: + return "kv-server", true + case 3361: + return "kv-agent", true + case 3362: + return "dj-ilm", true + case 3363: + return "nati-vi-server", true + case 3364: + return "creativeserver", true + case 3365: + return "contentserver", true + case 3366: + return "creativepartnr", true + case 3372: + return "tip2", true + case 3373: + return "lavenir-lm", true + case 3374: + return "cluster-disc", true + case 3375: + return "vsnm-agent", true + case 3376: + return "cdbroker", true + case 3377: + return "cogsys-lm", true + case 3378: + return "wsicopy", true + case 3379: + return "socorfs", true + case 3380: + return "sns-channels", true + case 3381: + return "geneous", true + case 3382: + return "fujitsu-neat", true + case 3383: + return "esp-lm", true + case 3384: + return "hp-clic", true + case 3385: + return "qnxnetman", true + case 3386: + return "gprs-data", true + case 3387: + return "backroomnet", true + case 3388: + return "cbserver", true + case 3389: + return "ms-wbt-server", true + case 3390: + return "dsc", true + case 3391: + return "savant", true + case 3392: + return "efi-lm", true + case 3393: + return "d2k-tapestry1", true + case 3394: + return "d2k-tapestry2", true + case 3395: + return "dyna-lm", true + case 3396: + return "printer-agent", true + case 3397: + return "cloanto-lm", true + case 3398: + return "mercantile", true + case 3399: + return "csms", true + case 3400: + return "csms2", true + case 3401: + return "filecast", true + case 3402: + return "fxaengine-net", true + case 3405: + return "nokia-ann-ch1", true + case 3406: + return "nokia-ann-ch2", true + case 3407: + return "ldap-admin", true + case 3408: + return "BESApi", true + case 3409: + return "networklens", true + case 3410: + return "networklenss", true + case 3411: + return "biolink-auth", true + case 3412: + return "xmlblaster", true + case 3413: + return "svnet", true + case 3414: + return "wip-port", true + case 3415: + return "bcinameservice", true + case 3416: + return "commandport", true + case 3417: + return "csvr", true + case 3418: + return "rnmap", true + case 3419: + return "softaudit", true + case 3420: + return "ifcp-port", true + case 3421: + return "bmap", true + case 3422: + return "rusb-sys-port", true + case 3423: + return "xtrm", true + case 3424: + return "xtrms", true + case 3425: + return "agps-port", true + case 3426: + return "arkivio", true + case 3427: + return "websphere-snmp", true + case 3428: + return "twcss", true + case 3429: + return "gcsp", true + case 3430: + return "ssdispatch", true + case 3431: + return "ndl-als", true + case 3432: + return "osdcp", true + case 3433: + return "opnet-smp", true + case 3434: + return "opencm", true + case 3435: + return "pacom", true + case 3436: + return "gc-config", true + case 3437: + return "autocueds", true + case 3438: + return "spiral-admin", true + case 3439: + return "hri-port", true + case 3440: + return "ans-console", true + case 3441: + return "connect-client", true + case 3442: + return "connect-server", true + case 3443: + return "ov-nnm-websrv", true + case 3444: + return "denali-server", true + case 3445: + return "monp", true + case 3446: + return "3comfaxrpc", true + case 3447: + return "directnet", true + case 3448: + return "dnc-port", true + case 3449: + return "hotu-chat", true + case 3450: + return "castorproxy", true + case 3451: + return "asam", true + case 3452: + return "sabp-signal", true + case 3453: + return "pscupd", true + case 3454: + return "mira", true + case 3455: + return "prsvp", true + case 3456: + return "vat", true + case 3457: + return "vat-control", true + case 3458: + return "d3winosfi", true + case 3459: + return "integral", true + case 3460: + return "edm-manager", true + case 3461: + return "edm-stager", true + case 3462: + return "edm-std-notify", true + case 3463: + return "edm-adm-notify", true + case 3464: + return "edm-mgr-sync", true + case 3465: + return "edm-mgr-cntrl", true + case 3466: + return "workflow", true + case 3467: + return "rcst", true + case 3468: + return "ttcmremotectrl", true + case 3469: + return "pluribus", true + case 3470: + return "jt400", true + case 3471: + return "jt400-ssl", true + case 3472: + return "jaugsremotec-1", true + case 3473: + return "jaugsremotec-2", true + case 3474: + return "ttntspauto", true + case 3475: + return "genisar-port", true + case 3476: + return "nppmp", true + case 3477: + return "ecomm", true + case 3478: + return "stun", true + case 3479: + return "twrpc", true + case 3480: + return "plethora", true + case 3481: + return "cleanerliverc", true + case 3482: + return "vulture", true + case 3483: + return "slim-devices", true + case 3484: + return "gbs-stp", true + case 3485: + return "celatalk", true + case 3486: + return "ifsf-hb-port", true + case 3487: + return "ltctcp", true + case 3488: + return "fs-rh-srv", true + case 3489: + return "dtp-dia", true + case 3490: + return "colubris", true + case 3491: + return "swr-port", true + case 3492: + return "tvdumtray-port", true + case 3493: + return "nut", true + case 3494: + return "ibm3494", true + case 3495: + return "seclayer-tcp", true + case 3496: + return "seclayer-tls", true + case 3497: + return "ipether232port", true + case 3498: + return "dashpas-port", true + case 3499: + return "sccip-media", true + case 3500: + return "rtmp-port", true + case 3501: + return "isoft-p2p", true + case 3502: + return "avinstalldisc", true + case 3503: + return "lsp-ping", true + case 3504: + return "ironstorm", true + case 3505: + return "ccmcomm", true + case 3506: + return "apc-3506", true + case 3507: + return "nesh-broker", true + case 3508: + return "interactionweb", true + case 3509: + return "vt-ssl", true + case 3510: + return "xss-port", true + case 3511: + return "webmail-2", true + case 3512: + return "aztec", true + case 3513: + return "arcpd", true + case 3514: + return "must-p2p", true + case 3515: + return "must-backplane", true + case 3516: + return "smartcard-port", true + case 3517: + return "802-11-iapp", true + case 3518: + return "artifact-msg", true + case 3519: + return "nvmsgd", true + case 3520: + return "galileolog", true + case 3521: + return "mc3ss", true + case 3522: + return "nssocketport", true + case 3523: + return "odeumservlink", true + case 3524: + return "ecmport", true + case 3525: + return "eisport", true + case 3526: + return "starquiz-port", true + case 3527: + return "beserver-msg-q", true + case 3528: + return "jboss-iiop", true + case 3529: + return "jboss-iiop-ssl", true + case 3530: + return "gf", true + case 3531: + return "joltid", true + case 3532: + return "raven-rmp", true + case 3533: + return "raven-rdp", true + case 3534: + return "urld-port", true + case 3535: + return "ms-la", true + case 3536: + return "snac", true + case 3537: + return "ni-visa-remote", true + case 3538: + return "ibm-diradm", true + case 3539: + return "ibm-diradm-ssl", true + case 3540: + return "pnrp-port", true + case 3541: + return "voispeed-port", true + case 3542: + return "hacl-monitor", true + case 3543: + return "qftest-lookup", true + case 3544: + return "teredo", true + case 3545: + return "camac", true + case 3547: + return "symantec-sim", true + case 3548: + return "interworld", true + case 3549: + return "tellumat-nms", true + case 3550: + return "ssmpp", true + case 3551: + return "apcupsd", true + case 3552: + return "taserver", true + case 3553: + return "rbr-discovery", true + case 3554: + return "questnotify", true + case 3555: + return "razor", true + case 3556: + return "sky-transport", true + case 3557: + return "personalos-001", true + case 3558: + return "mcp-port", true + case 3559: + return "cctv-port", true + case 3560: + return "iniserve-port", true + case 3561: + return "bmc-onekey", true + case 3562: + return "sdbproxy", true + case 3563: + return "watcomdebug", true + case 3564: + return "esimport", true + case 3565: + return "m2pa", true + case 3566: + return "quest-data-hub", true + case 3567: + return "dof-eps", true + case 3568: + return "dof-tunnel-sec", true + case 3569: + return "mbg-ctrl", true + case 3570: + return "mccwebsvr-port", true + case 3571: + return "megardsvr-port", true + case 3572: + return "megaregsvrport", true + case 3573: + return "tag-ups-1", true + case 3574: + return "dmaf-server", true + case 3575: + return "ccm-port", true + case 3576: + return "cmc-port", true + case 3577: + return "config-port", true + case 3578: + return "data-port", true + case 3579: + return "ttat3lb", true + case 3580: + return "nati-svrloc", true + case 3581: + return "kfxaclicensing", true + case 3582: + return "press", true + case 3583: + return "canex-watch", true + case 3584: + return "u-dbap", true + case 3585: + return "emprise-lls", true + case 3586: + return "emprise-lsc", true + case 3587: + return "p2pgroup", true + case 3588: + return "sentinel", true + case 3589: + return "isomair", true + case 3590: + return "wv-csp-sms", true + case 3591: + return "gtrack-server", true + case 3592: + return "gtrack-ne", true + case 3593: + return "bpmd", true + case 3594: + return "mediaspace", true + case 3595: + return "shareapp", true + case 3596: + return "iw-mmogame", true + case 3597: + return "a14", true + case 3598: + return "a15", true + case 3599: + return "quasar-server", true + case 3600: + return "trap-daemon", true + case 3601: + return "visinet-gui", true + case 3602: + return "infiniswitchcl", true + case 3603: + return "int-rcv-cntrl", true + case 3604: + return "bmc-jmx-port", true + case 3605: + return "comcam-io", true + case 3606: + return "splitlock", true + case 3607: + return "precise-i3", true + case 3608: + return "trendchip-dcp", true + case 3609: + return "cpdi-pidas-cm", true + case 3610: + return "echonet", true + case 3611: + return "six-degrees", true + case 3612: + return "dataprotector", true + case 3613: + return "alaris-disc", true + case 3614: + return "sigma-port", true + case 3615: + return "start-network", true + case 3616: + return "cd3o-protocol", true + case 3617: + return "sharp-server", true + case 3618: + return "aairnet-1", true + case 3619: + return "aairnet-2", true + case 3620: + return "ep-pcp", true + case 3621: + return "ep-nsp", true + case 3622: + return "ff-lr-port", true + case 3623: + return "haipe-discover", true + case 3624: + return "dist-upgrade", true + case 3625: + return "volley", true + case 3626: + return "bvcdaemon-port", true + case 3627: + return "jamserverport", true + case 3628: + return "ept-machine", true + case 3629: + return "escvpnet", true + case 3630: + return "cs-remote-db", true + case 3631: + return "cs-services", true + case 3632: + return "distcc", true + case 3633: + return "wacp", true + case 3634: + return "hlibmgr", true + case 3635: + return "sdo", true + case 3636: + return "servistaitsm", true + case 3637: + return "scservp", true + case 3638: + return "ehp-backup", true + case 3639: + return "xap-ha", true + case 3640: + return "netplay-port1", true + case 3641: + return "netplay-port2", true + case 3642: + return "juxml-port", true + case 3643: + return "audiojuggler", true + case 3644: + return "ssowatch", true + case 3645: + return "cyc", true + case 3646: + return "xss-srv-port", true + case 3647: + return "splitlock-gw", true + case 3648: + return "fjcp", true + case 3649: + return "nmmp", true + case 3650: + return "prismiq-plugin", true + case 3651: + return "xrpc-registry", true + case 3652: + return "vxcrnbuport", true + case 3653: + return "tsp", true + case 3654: + return "vaprtm", true + case 3655: + return "abatemgr", true + case 3656: + return "abatjss", true + case 3657: + return "immedianet-bcn", true + case 3658: + return "ps-ams", true + case 3659: + return "apple-sasl", true + case 3660: + return "can-nds-ssl", true + case 3661: + return "can-ferret-ssl", true + case 3662: + return "pserver", true + case 3663: + return "dtp", true + case 3664: + return "ups-engine", true + case 3665: + return "ent-engine", true + case 3666: + return "eserver-pap", true + case 3667: + return "infoexch", true + case 3668: + return "dell-rm-port", true + case 3669: + return "casanswmgmt", true + case 3670: + return "smile", true + case 3671: + return "efcp", true + case 3672: + return "lispworks-orb", true + case 3673: + return "mediavault-gui", true + case 3674: + return "wininstall-ipc", true + case 3675: + return "calltrax", true + case 3676: + return "va-pacbase", true + case 3677: + return "roverlog", true + case 3678: + return "ipr-dglt", true + case 3679: + return "Escale (Newton Dock)", true + case 3680: + return "npds-tracker", true + case 3681: + return "bts-x73", true + case 3682: + return "cas-mapi", true + case 3683: + return "bmc-ea", true + case 3684: + return "faxstfx-port", true + case 3685: + return "dsx-agent", true + case 3686: + return "tnmpv2", true + case 3687: + return "simple-push", true + case 3688: + return "simple-push-s", true + case 3689: + return "daap", true + case 3690: + return "svn", true + case 3691: + return "magaya-network", true + case 3692: + return "intelsync", true + case 3693: + return "easl", true + case 3695: + return "bmc-data-coll", true + case 3696: + return "telnetcpcd", true + case 3697: + return "nw-license", true + case 3698: + return "sagectlpanel", true + case 3699: + return "kpn-icw", true + case 3700: + return "lrs-paging", true + case 3701: + return "netcelera", true + case 3702: + return "ws-discovery", true + case 3703: + return "adobeserver-3", true + case 3704: + return "adobeserver-4", true + case 3705: + return "adobeserver-5", true + case 3706: + return "rt-event", true + case 3707: + return "rt-event-s", true + case 3708: + return "sun-as-iiops", true + case 3709: + return "ca-idms", true + case 3710: + return "portgate-auth", true + case 3711: + return "edb-server2", true + case 3712: + return "sentinel-ent", true + case 3713: + return "tftps", true + case 3714: + return "delos-dms", true + case 3715: + return "anoto-rendezv", true + case 3716: + return "wv-csp-sms-cir", true + case 3717: + return "wv-csp-udp-cir", true + case 3718: + return "opus-services", true + case 3719: + return "itelserverport", true + case 3720: + return "ufastro-instr", true + case 3721: + return "xsync", true + case 3722: + return "xserveraid", true + case 3723: + return "sychrond", true + case 3724: + return "blizwow", true + case 3725: + return "na-er-tip", true + case 3726: + return "array-manager", true + case 3727: + return "e-mdu", true + case 3728: + return "e-woa", true + case 3729: + return "fksp-audit", true + case 3730: + return "client-ctrl", true + case 3731: + return "smap", true + case 3732: + return "m-wnn", true + case 3733: + return "multip-msg", true + case 3734: + return "synel-data", true + case 3735: + return "pwdis", true + case 3736: + return "rs-rmi", true + case 3737: + return "xpanel", true + case 3738: + return "versatalk", true + case 3739: + return "launchbird-lm", true + case 3740: + return "heartbeat", true + case 3741: + return "wysdma", true + case 3742: + return "cst-port", true + case 3743: + return "ipcs-command", true + case 3744: + return "sasg", true + case 3745: + return "gw-call-port", true + case 3746: + return "linktest", true + case 3747: + return "linktest-s", true + case 3748: + return "webdata", true + case 3749: + return "cimtrak", true + case 3750: + return "cbos-ip-port", true + case 3751: + return "gprs-cube", true + case 3752: + return "vipremoteagent", true + case 3753: + return "nattyserver", true + case 3754: + return "timestenbroker", true + case 3755: + return "sas-remote-hlp", true + case 3756: + return "canon-capt", true + case 3757: + return "grf-port", true + case 3758: + return "apw-registry", true + case 3759: + return "exapt-lmgr", true + case 3760: + return "adtempusclient", true + case 3761: + return "gsakmp", true + case 3762: + return "gbs-smp", true + case 3763: + return "xo-wave", true + case 3764: + return "mni-prot-rout", true + case 3765: + return "rtraceroute", true + case 3766: + return "sitewatch-s", true + case 3767: + return "listmgr-port", true + case 3768: + return "rblcheckd", true + case 3769: + return "haipe-otnk", true + case 3770: + return "cindycollab", true + case 3771: + return "paging-port", true + case 3772: + return "ctp", true + case 3773: + return "ctdhercules", true + case 3774: + return "zicom", true + case 3775: + return "ispmmgr", true + case 3776: + return "dvcprov-port", true + case 3777: + return "jibe-eb", true + case 3778: + return "c-h-it-port", true + case 3779: + return "cognima", true + case 3780: + return "nnp", true + case 3781: + return "abcvoice-port", true + case 3782: + return "iso-tp0s", true + case 3783: + return "bim-pem", true + case 3784: + return "bfd-control", true + case 3785: + return "bfd-echo", true + case 3786: + return "upstriggervsw", true + case 3787: + return "fintrx", true + case 3788: + return "isrp-port", true + case 3789: + return "remotedeploy", true + case 3790: + return "quickbooksrds", true + case 3791: + return "tvnetworkvideo", true + case 3792: + return "sitewatch", true + case 3793: + return "dcsoftware", true + case 3794: + return "jaus", true + case 3795: + return "myblast", true + case 3796: + return "spw-dialer", true + case 3797: + return "idps", true + case 3798: + return "minilock", true + case 3799: + return "radius-dynauth", true + case 3800: + return "pwgpsi", true + case 3801: + return "ibm-mgr", true + case 3802: + return "vhd", true + case 3803: + return "soniqsync", true + case 3804: + return "iqnet-port", true + case 3805: + return "tcpdataserver", true + case 3806: + return "wsmlb", true + case 3807: + return "spugna", true + case 3808: + return "sun-as-iiops-ca", true + case 3809: + return "apocd", true + case 3810: + return "wlanauth", true + case 3811: + return "amp", true + case 3812: + return "neto-wol-server", true + case 3813: + return "rap-ip", true + case 3814: + return "neto-dcs", true + case 3815: + return "lansurveyorxml", true + case 3816: + return "sunlps-http", true + case 3817: + return "tapeware", true + case 3818: + return "crinis-hb", true + case 3819: + return "epl-slp", true + case 3820: + return "scp", true + case 3821: + return "pmcp", true + case 3822: + return "acp-discovery", true + case 3823: + return "acp-conduit", true + case 3824: + return "acp-policy", true + case 3825: + return "ffserver", true + case 3826: + return "warmux", true + case 3827: + return "netmpi", true + case 3828: + return "neteh", true + case 3829: + return "neteh-ext", true + case 3830: + return "cernsysmgmtagt", true + case 3831: + return "dvapps", true + case 3832: + return "xxnetserver", true + case 3833: + return "aipn-auth", true + case 3834: + return "spectardata", true + case 3835: + return "spectardb", true + case 3836: + return "markem-dcp", true + case 3837: + return "mkm-discovery", true + case 3838: + return "sos", true + case 3839: + return "amx-rms", true + case 3840: + return "flirtmitmir", true + case 3841: + return "shiprush-db-svr", true + case 3842: + return "nhci", true + case 3843: + return "quest-agent", true + case 3844: + return "rnm", true + case 3845: + return "v-one-spp", true + case 3846: + return "an-pcp", true + case 3847: + return "msfw-control", true + case 3848: + return "item", true + case 3849: + return "spw-dnspreload", true + case 3850: + return "qtms-bootstrap", true + case 3851: + return "spectraport", true + case 3852: + return "sse-app-config", true + case 3853: + return "sscan", true + case 3854: + return "stryker-com", true + case 3855: + return "opentrac", true + case 3856: + return "informer", true + case 3857: + return "trap-port", true + case 3858: + return "trap-port-mom", true + case 3859: + return "nav-port", true + case 3860: + return "sasp", true + case 3861: + return "winshadow-hd", true + case 3862: + return "giga-pocket", true + case 3863: + return "asap-tcp", true + case 3864: + return "asap-tcp-tls", true + case 3865: + return "xpl", true + case 3866: + return "dzdaemon", true + case 3867: + return "dzoglserver", true + case 3868: + return "diameter", true + case 3869: + return "ovsam-mgmt", true + case 3870: + return "ovsam-d-agent", true + case 3871: + return "avocent-adsap", true + case 3872: + return "oem-agent", true + case 3873: + return "fagordnc", true + case 3874: + return "sixxsconfig", true + case 3875: + return "pnbscada", true + case 3876: + return "dl-agent", true + case 3877: + return "xmpcr-interface", true + case 3878: + return "fotogcad", true + case 3879: + return "appss-lm", true + case 3880: + return "igrs", true + case 3881: + return "idac", true + case 3882: + return "msdts1", true + case 3883: + return "vrpn", true + case 3884: + return "softrack-meter", true + case 3885: + return "topflow-ssl", true + case 3886: + return "nei-management", true + case 3887: + return "ciphire-data", true + case 3888: + return "ciphire-serv", true + case 3889: + return "dandv-tester", true + case 3890: + return "ndsconnect", true + case 3891: + return "rtc-pm-port", true + case 3892: + return "pcc-image-port", true + case 3893: + return "cgi-starapi", true + case 3894: + return "syam-agent", true + case 3895: + return "syam-smc", true + case 3896: + return "sdo-tls", true + case 3897: + return "sdo-ssh", true + case 3898: + return "senip", true + case 3899: + return "itv-control", true + case 3900: + return "udt-os", true + case 3901: + return "nimsh", true + case 3902: + return "nimaux", true + case 3903: + return "charsetmgr", true + case 3904: + return "omnilink-port", true + case 3905: + return "mupdate", true + case 3906: + return "topovista-data", true + case 3907: + return "imoguia-port", true + case 3908: + return "hppronetman", true + case 3909: + return "surfcontrolcpa", true + case 3910: + return "prnrequest", true + case 3911: + return "prnstatus", true + case 3912: + return "gbmt-stars", true + case 3913: + return "listcrt-port", true + case 3914: + return "listcrt-port-2", true + case 3915: + return "agcat", true + case 3916: + return "wysdmc", true + case 3917: + return "aftmux", true + case 3918: + return "pktcablemmcops", true + case 3919: + return "hyperip", true + case 3920: + return "exasoftport1", true + case 3921: + return "herodotus-net", true + case 3922: + return "sor-update", true + case 3923: + return "symb-sb-port", true + case 3924: + return "mpl-gprs-port", true + case 3925: + return "zmp", true + case 3926: + return "winport", true + case 3927: + return "natdataservice", true + case 3928: + return "netboot-pxe", true + case 3929: + return "smauth-port", true + case 3930: + return "syam-webserver", true + case 3931: + return "msr-plugin-port", true + case 3932: + return "dyn-site", true + case 3933: + return "plbserve-port", true + case 3934: + return "sunfm-port", true + case 3935: + return "sdp-portmapper", true + case 3936: + return "mailprox", true + case 3937: + return "dvbservdsc", true + case 3938: + return "dbcontrol-agent", true + case 3939: + return "aamp", true + case 3940: + return "xecp-node", true + case 3941: + return "homeportal-web", true + case 3942: + return "srdp", true + case 3943: + return "tig", true + case 3944: + return "sops", true + case 3945: + return "emcads", true + case 3946: + return "backupedge", true + case 3947: + return "ccp", true + case 3948: + return "apdap", true + case 3949: + return "drip", true + case 3950: + return "namemunge", true + case 3951: + return "pwgippfax", true + case 3952: + return "i3-sessionmgr", true + case 3953: + return "xmlink-connect", true + case 3954: + return "adrep", true + case 3955: + return "p2pcommunity", true + case 3956: + return "gvcp", true + case 3957: + return "mqe-broker", true + case 3958: + return "mqe-agent", true + case 3959: + return "treehopper", true + case 3960: + return "bess", true + case 3961: + return "proaxess", true + case 3962: + return "sbi-agent", true + case 3963: + return "thrp", true + case 3964: + return "sasggprs", true + case 3965: + return "ati-ip-to-ncpe", true + case 3966: + return "bflckmgr", true + case 3967: + return "ppsms", true + case 3968: + return "ianywhere-dbns", true + case 3969: + return "landmarks", true + case 3970: + return "lanrevagent", true + case 3971: + return "lanrevserver", true + case 3972: + return "iconp", true + case 3973: + return "progistics", true + case 3974: + return "xk22", true + case 3975: + return "airshot", true + case 3976: + return "opswagent", true + case 3977: + return "opswmanager", true + case 3978: + return "secure-cfg-svr", true + case 3979: + return "smwan", true + case 3981: + return "starfish", true + case 3982: + return "eis", true + case 3983: + return "eisp", true + case 3984: + return "mapper-nodemgr", true + case 3985: + return "mapper-mapethd", true + case 3986: + return "mapper-ws-ethd", true + case 3987: + return "centerline", true + case 3988: + return "dcs-config", true + case 3989: + return "bv-queryengine", true + case 3990: + return "bv-is", true + case 3991: + return "bv-smcsrv", true + case 3992: + return "bv-ds", true + case 3993: + return "bv-agent", true + case 3995: + return "iss-mgmt-ssl", true + case 3996: + return "abcsoftware", true + case 3997: + return "agentsease-db", true + case 3998: + return "dnx", true + case 3999: + return "nvcnet", true + case 4000: + return "terabase", true + case 4001: + return "newoak", true + case 4002: + return "pxc-spvr-ft", true + case 4003: + return "pxc-splr-ft", true + case 4004: + return "pxc-roid", true + case 4005: + return "pxc-pin", true + case 4006: + return "pxc-spvr", true + case 4007: + return "pxc-splr", true + case 4008: + return "netcheque", true + case 4009: + return "chimera-hwm", true + case 4010: + return "samsung-unidex", true + case 4011: + return "altserviceboot", true + case 4012: + return "pda-gate", true + case 4013: + return "acl-manager", true + case 4014: + return "taiclock", true + case 4015: + return "talarian-mcast1", true + case 4016: + return "talarian-mcast2", true + case 4017: + return "talarian-mcast3", true + case 4018: + return "talarian-mcast4", true + case 4019: + return "talarian-mcast5", true + case 4020: + return "trap", true + case 4021: + return "nexus-portal", true + case 4022: + return "dnox", true + case 4023: + return "esnm-zoning", true + case 4024: + return "tnp1-port", true + case 4025: + return "partimage", true + case 4026: + return "as-debug", true + case 4027: + return "bxp", true + case 4028: + return "dtserver-port", true + case 4029: + return "ip-qsig", true + case 4030: + return "jdmn-port", true + case 4031: + return "suucp", true + case 4032: + return "vrts-auth-port", true + case 4033: + return "sanavigator", true + case 4034: + return "ubxd", true + case 4035: + return "wap-push-http", true + case 4036: + return "wap-push-https", true + case 4037: + return "ravehd", true + case 4038: + return "fazzt-ptp", true + case 4039: + return "fazzt-admin", true + case 4040: + return "yo-main", true + case 4041: + return "houston", true + case 4042: + return "ldxp", true + case 4043: + return "nirp", true + case 4044: + return "ltp", true + case 4045: + return "npp", true + case 4046: + return "acp-proto", true + case 4047: + return "ctp-state", true + case 4049: + return "wafs", true + case 4050: + return "cisco-wafs", true + case 4051: + return "cppdp", true + case 4052: + return "interact", true + case 4053: + return "ccu-comm-1", true + case 4054: + return "ccu-comm-2", true + case 4055: + return "ccu-comm-3", true + case 4056: + return "lms", true + case 4057: + return "wfm", true + case 4058: + return "kingfisher", true + case 4059: + return "dlms-cosem", true + case 4060: + return "dsmeter-iatc", true + case 4061: + return "ice-location", true + case 4062: + return "ice-slocation", true + case 4063: + return "ice-router", true + case 4064: + return "ice-srouter", true + case 4065: + return "avanti-cdp", true + case 4066: + return "pmas", true + case 4067: + return "idp", true + case 4068: + return "ipfltbcst", true + case 4069: + return "minger", true + case 4070: + return "tripe", true + case 4071: + return "aibkup", true + case 4072: + return "zieto-sock", true + case 4073: + return "iRAPP", true + case 4074: + return "cequint-cityid", true + case 4075: + return "perimlan", true + case 4076: + return "seraph", true + case 4078: + return "cssp", true + case 4079: + return "santools", true + case 4080: + return "lorica-in", true + case 4081: + return "lorica-in-sec", true + case 4082: + return "lorica-out", true + case 4083: + return "lorica-out-sec", true + case 4085: + return "ezmessagesrv", true + case 4087: + return "applusservice", true + case 4088: + return "npsp", true + case 4089: + return "opencore", true + case 4090: + return "omasgport", true + case 4091: + return "ewinstaller", true + case 4092: + return "ewdgs", true + case 4093: + return "pvxpluscs", true + case 4094: + return "sysrqd", true + case 4095: + return "xtgui", true + case 4096: + return "bre", true + case 4097: + return "patrolview", true + case 4098: + return "drmsfsd", true + case 4099: + return "dpcp", true + case 4100: + return "igo-incognito", true + case 4101: + return "brlp-0", true + case 4102: + return "brlp-1", true + case 4103: + return "brlp-2", true + case 4104: + return "brlp-3", true + case 4105: + return "shofar", true + case 4106: + return "synchronite", true + case 4107: + return "j-ac", true + case 4108: + return "accel", true + case 4109: + return "izm", true + case 4110: + return "g2tag", true + case 4111: + return "xgrid", true + case 4112: + return "apple-vpns-rp", true + case 4113: + return "aipn-reg", true + case 4114: + return "jomamqmonitor", true + case 4115: + return "cds", true + case 4116: + return "smartcard-tls", true + case 4117: + return "hillrserv", true + case 4118: + return "netscript", true + case 4119: + return "assuria-slm", true + case 4120: + return "minirem", true + case 4121: + return "e-builder", true + case 4122: + return "fprams", true + case 4123: + return "z-wave", true + case 4124: + return "tigv2", true + case 4125: + return "opsview-envoy", true + case 4126: + return "ddrepl", true + case 4127: + return "unikeypro", true + case 4128: + return "nufw", true + case 4129: + return "nuauth", true + case 4130: + return "fronet", true + case 4131: + return "stars", true + case 4132: + return "nuts-dem", true + case 4133: + return "nuts-bootp", true + case 4134: + return "nifty-hmi", true + case 4135: + return "cl-db-attach", true + case 4136: + return "cl-db-request", true + case 4137: + return "cl-db-remote", true + case 4138: + return "nettest", true + case 4139: + return "thrtx", true + case 4140: + return "cedros-fds", true + case 4141: + return "oirtgsvc", true + case 4142: + return "oidocsvc", true + case 4143: + return "oidsr", true + case 4145: + return "vvr-control", true + case 4146: + return "tgcconnect", true + case 4147: + return "vrxpservman", true + case 4148: + return "hhb-handheld", true + case 4149: + return "agslb", true + case 4150: + return "PowerAlert-nsa", true + case 4151: + return "menandmice-noh", true + case 4152: + return "idig-mux", true + case 4153: + return "mbl-battd", true + case 4154: + return "atlinks", true + case 4155: + return "bzr", true + case 4156: + return "stat-results", true + case 4157: + return "stat-scanner", true + case 4158: + return "stat-cc", true + case 4159: + return "nss", true + case 4160: + return "jini-discovery", true + case 4161: + return "omscontact", true + case 4162: + return "omstopology", true + case 4163: + return "silverpeakpeer", true + case 4164: + return "silverpeakcomm", true + case 4165: + return "altcp", true + case 4166: + return "joost", true + case 4167: + return "ddgn", true + case 4168: + return "pslicser", true + case 4169: + return "iadt", true + case 4170: + return "d-cinema-csp", true + case 4171: + return "ml-svnet", true + case 4172: + return "pcoip", true + case 4174: + return "smcluster", true + case 4175: + return "bccp", true + case 4176: + return "tl-ipcproxy", true + case 4177: + return "wello", true + case 4178: + return "storman", true + case 4179: + return "MaxumSP", true + case 4180: + return "httpx", true + case 4181: + return "macbak", true + case 4182: + return "pcptcpservice", true + case 4183: + return "cyborgnet", true + case 4184: + return "universe-suite", true + case 4185: + return "wcpp", true + case 4186: + return "boxbackupstore", true + case 4187: + return "csc-proxy", true + case 4188: + return "vatata", true + case 4189: + return "pcep", true + case 4190: + return "sieve", true + case 4192: + return "azeti", true + case 4193: + return "pvxplusio", true + case 4194: + return "spdm", true + case 4195: + return "aws-wsp", true + case 4197: + return "hctl", true + case 4199: + return "eims-admin", true + case 4300: + return "corelccam", true + case 4301: + return "d-data", true + case 4302: + return "d-data-control", true + case 4303: + return "srcp", true + case 4304: + return "owserver", true + case 4305: + return "batman", true + case 4306: + return "pinghgl", true + case 4307: + return "trueconf", true + case 4308: + return "compx-lockview", true + case 4309: + return "dserver", true + case 4310: + return "mirrtex", true + case 4311: + return "p6ssmc", true + case 4312: + return "pscl-mgt", true + case 4313: + return "perrla", true + case 4314: + return "choiceview-agt", true + case 4316: + return "choiceview-clt", true + case 4317: + return "opentelemetry", true + case 4319: + return "fox-skytale", true + case 4320: + return "fdt-rcatp", true + case 4321: + return "rwhois", true + case 4322: + return "trim-event", true + case 4323: + return "trim-ice", true + case 4325: + return "geognosisadmin", true + case 4326: + return "geognosis", true + case 4327: + return "jaxer-web", true + case 4328: + return "jaxer-manager", true + case 4329: + return "publiqare-sync", true + case 4330: + return "dey-sapi", true + case 4331: + return "ktickets-rest", true + case 4332: + return "getty-focus", true + case 4333: + return "ahsp", true + case 4334: + return "netconf-ch-ssh", true + case 4335: + return "netconf-ch-tls", true + case 4336: + return "restconf-ch-tls", true + case 4340: + return "gaia", true + case 4343: + return "unicall", true + case 4344: + return "vinainstall", true + case 4345: + return "m4-network-as", true + case 4346: + return "elanlm", true + case 4347: + return "lansurveyor", true + case 4348: + return "itose", true + case 4349: + return "fsportmap", true + case 4350: + return "net-device", true + case 4351: + return "plcy-net-svcs", true + case 4352: + return "pjlink", true + case 4353: + return "f5-iquery", true + case 4354: + return "qsnet-trans", true + case 4355: + return "qsnet-workst", true + case 4356: + return "qsnet-assist", true + case 4357: + return "qsnet-cond", true + case 4358: + return "qsnet-nucl", true + case 4359: + return "omabcastltkm", true + case 4360: + return "matrix-vnet", true + case 4368: + return "wxbrief", true + case 4369: + return "epmd", true + case 4370: + return "elpro-tunnel", true + case 4371: + return "l2c-control", true + case 4372: + return "l2c-data", true + case 4373: + return "remctl", true + case 4374: + return "psi-ptt", true + case 4375: + return "tolteces", true + case 4376: + return "bip", true + case 4377: + return "cp-spxsvr", true + case 4378: + return "cp-spxdpy", true + case 4379: + return "ctdb", true + case 4389: + return "xandros-cms", true + case 4390: + return "wiegand", true + case 4391: + return "apwi-imserver", true + case 4392: + return "apwi-rxserver", true + case 4393: + return "apwi-rxspooler", true + case 4395: + return "omnivisionesx", true + case 4396: + return "fly", true + case 4400: + return "ds-srv", true + case 4401: + return "ds-srvr", true + case 4402: + return "ds-clnt", true + case 4403: + return "ds-user", true + case 4404: + return "ds-admin", true + case 4405: + return "ds-mail", true + case 4406: + return "ds-slp", true + case 4407: + return "nacagent", true + case 4408: + return "slscc", true + case 4409: + return "netcabinet-com", true + case 4410: + return "itwo-server", true + case 4411: + return "found", true + case 4413: + return "avi-nms", true + case 4414: + return "updog", true + case 4415: + return "brcd-vr-req", true + case 4416: + return "pjj-player", true + case 4417: + return "workflowdir", true + case 4419: + return "cbp", true + case 4420: + return "nvme", true + case 4421: + return "scaleft", true + case 4422: + return "tsepisp", true + case 4423: + return "thingkit", true + case 4425: + return "netrockey6", true + case 4426: + return "beacon-port-2", true + case 4427: + return "drizzle", true + case 4428: + return "omviserver", true + case 4429: + return "omviagent", true + case 4430: + return "rsqlserver", true + case 4431: + return "wspipe", true + case 4432: + return "l-acoustics", true + case 4433: + return "vop", true + case 4442: + return "saris", true + case 4443: + return "pharos", true + case 4444: + return "krb524", true + case 4445: + return "upnotifyp", true + case 4446: + return "n1-fwp", true + case 4447: + return "n1-rmgmt", true + case 4448: + return "asc-slmd", true + case 4449: + return "privatewire", true + case 4450: + return "camp", true + case 4451: + return "ctisystemmsg", true + case 4452: + return "ctiprogramload", true + case 4453: + return "nssalertmgr", true + case 4454: + return "nssagentmgr", true + case 4455: + return "prchat-user", true + case 4456: + return "prchat-server", true + case 4457: + return "prRegister", true + case 4458: + return "mcp", true + case 4460: + return "ntske", true + case 4484: + return "hpssmgmt", true + case 4485: + return "assyst-dr", true + case 4486: + return "icms", true + case 4487: + return "prex-tcp", true + case 4488: + return "awacs-ice", true + case 4500: + return "ipsec-nat-t", true + case 4535: + return "ehs", true + case 4536: + return "ehs-ssl", true + case 4537: + return "wssauthsvc", true + case 4538: + return "swx-gate", true + case 4545: + return "worldscores", true + case 4546: + return "sf-lm", true + case 4547: + return "lanner-lm", true + case 4548: + return "synchromesh", true + case 4549: + return "aegate", true + case 4550: + return "gds-adppiw-db", true + case 4551: + return "ieee-mih", true + case 4552: + return "menandmice-mon", true + case 4553: + return "icshostsvc", true + case 4554: + return "msfrs", true + case 4555: + return "rsip", true + case 4556: + return "dtn-bundle", true + case 4559: + return "hylafax", true + case 4563: + return "amahi-anywhere", true + case 4566: + return "kwtc", true + case 4567: + return "tram", true + case 4568: + return "bmc-reporting", true + case 4569: + return "iax", true + case 4570: + return "deploymentmap", true + case 4573: + return "cardifftec-back", true + case 4590: + return "rid", true + case 4591: + return "l3t-at-an", true + case 4593: + return "ipt-anri-anri", true + case 4594: + return "ias-session", true + case 4595: + return "ias-paging", true + case 4596: + return "ias-neighbor", true + case 4597: + return "a21-an-1xbs", true + case 4598: + return "a16-an-an", true + case 4599: + return "a17-an-an", true + case 4600: + return "piranha1", true + case 4601: + return "piranha2", true + case 4602: + return "mtsserver", true + case 4603: + return "menandmice-upg", true + case 4604: + return "irp", true + case 4605: + return "sixchat", true + case 4606: + return "sixid", true + case 4646: + return "dots-signal", true + case 4658: + return "playsta2-app", true + case 4659: + return "playsta2-lob", true + case 4660: + return "smaclmgr", true + case 4661: + return "kar2ouche", true + case 4662: + return "oms", true + case 4663: + return "noteit", true + case 4664: + return "ems", true + case 4665: + return "contclientms", true + case 4666: + return "eportcomm", true + case 4667: + return "mmacomm", true + case 4668: + return "mmaeds", true + case 4669: + return "eportcommdata", true + case 4670: + return "light", true + case 4671: + return "acter", true + case 4672: + return "rfa", true + case 4673: + return "cxws", true + case 4674: + return "appiq-mgmt", true + case 4675: + return "dhct-status", true + case 4676: + return "dhct-alerts", true + case 4677: + return "bcs", true + case 4678: + return "traversal", true + case 4679: + return "mgesupervision", true + case 4680: + return "mgemanagement", true + case 4681: + return "parliant", true + case 4682: + return "finisar", true + case 4683: + return "spike", true + case 4684: + return "rfid-rp1", true + case 4685: + return "autopac", true + case 4686: + return "msp-os", true + case 4687: + return "nst", true + case 4688: + return "mobile-p2p", true + case 4689: + return "altovacentral", true + case 4690: + return "prelude", true + case 4691: + return "mtn", true + case 4692: + return "conspiracy", true + case 4700: + return "netxms-agent", true + case 4701: + return "netxms-mgmt", true + case 4702: + return "netxms-sync", true + case 4703: + return "npqes-test", true + case 4704: + return "assuria-ins", true + case 4711: + return "trinity-dist", true + case 4725: + return "truckstar", true + case 4727: + return "fcis", true + case 4728: + return "capmux", true + case 4730: + return "gearman", true + case 4731: + return "remcap", true + case 4733: + return "resorcs", true + case 4737: + return "ipdr-sp", true + case 4738: + return "solera-lpn", true + case 4739: + return "ipfix", true + case 4740: + return "ipfixs", true + case 4741: + return "lumimgrd", true + case 4742: + return "sicct", true + case 4743: + return "openhpid", true + case 4744: + return "ifsp", true + case 4745: + return "fmp", true + case 4749: + return "profilemac", true + case 4750: + return "ssad", true + case 4751: + return "spocp", true + case 4752: + return "snap", true + case 4753: + return "simon", true + case 4756: + return "RDCenter", true + case 4774: + return "converge", true + case 4784: + return "bfd-multi-ctl", true + case 4786: + return "smart-install", true + case 4787: + return "sia-ctrl-plane", true + case 4788: + return "xmcp", true + case 4792: + return "unified-bus", true + case 4800: + return "iims", true + case 4801: + return "iwec", true + case 4802: + return "ilss", true + case 4803: + return "notateit", true + case 4827: + return "htcp", true + case 4837: + return "varadero-0", true + case 4838: + return "varadero-1", true + case 4839: + return "varadero-2", true + case 4840: + return "opcua-tcp", true + case 4841: + return "quosa", true + case 4842: + return "gw-asv", true + case 4843: + return "opcua-tls", true + case 4844: + return "gw-log", true + case 4845: + return "wcr-remlib", true + case 4846: + return "contamac-icm", true + case 4847: + return "wfc", true + case 4848: + return "appserv-http", true + case 4849: + return "appserv-https", true + case 4850: + return "sun-as-nodeagt", true + case 4851: + return "derby-repli", true + case 4867: + return "unify-debug", true + case 4868: + return "phrelay", true + case 4869: + return "phrelaydbg", true + case 4870: + return "cc-tracking", true + case 4871: + return "wired", true + case 4876: + return "tritium-can", true + case 4877: + return "lmcs", true + case 4879: + return "wsdl-event", true + case 4880: + return "hislip", true + case 4883: + return "wmlserver", true + case 4884: + return "hivestor", true + case 4885: + return "abbs", true + case 4888: + return "xcap-portal", true + case 4889: + return "xcap-control", true + case 4894: + return "lyskom", true + case 4899: + return "radmin-port", true + case 4900: + return "hfcs", true + case 4901: + return "flr-agent", true + case 4902: + return "magiccontrol", true + case 4912: + return "lutap", true + case 4913: + return "lutcp", true + case 4914: + return "bones", true + case 4915: + return "frcs", true + case 4940: + return "eq-office-4940", true + case 4941: + return "eq-office-4941", true + case 4942: + return "eq-office-4942", true + case 4949: + return "munin", true + case 4950: + return "sybasesrvmon", true + case 4951: + return "pwgwims", true + case 4952: + return "sagxtsds", true + case 4953: + return "dbsyncarbiter", true + case 4969: + return "ccss-qmm", true + case 4970: + return "ccss-qsm", true + case 4971: + return "burp", true + case 4984: + return "webyast", true + case 4985: + return "gerhcs", true + case 4986: + return "mrip", true + case 4987: + return "smar-se-port1", true + case 4988: + return "smar-se-port2", true + case 4989: + return "parallel", true + case 4990: + return "busycal", true + case 4991: + return "vrt", true + case 4999: + return "hfcs-manager", true + case 5000: + return "commplex-main", true + case 5001: + return "commplex-link", true + case 5002: + return "rfe", true + case 5003: + return "fmpro-internal", true + case 5004: + return "avt-profile-1", true + case 5005: + return "avt-profile-2", true + case 5006: + return "wsm-server", true + case 5007: + return "wsm-server-ssl", true + case 5008: + return "synapsis-edge", true + case 5009: + return "winfs", true + case 5010: + return "telelpathstart", true + case 5011: + return "telelpathattack", true + case 5012: + return "nsp", true + case 5013: + return "fmpro-v6", true + case 5015: + return "fmwp", true + case 5020: + return "zenginkyo-1", true + case 5021: + return "zenginkyo-2", true + case 5022: + return "mice", true + case 5023: + return "htuilsrv", true + case 5024: + return "scpi-telnet", true + case 5025: + return "scpi-raw", true + case 5026: + return "strexec-d", true + case 5027: + return "strexec-s", true + case 5028: + return "qvr", true + case 5029: + return "infobright", true + case 5032: + return "signacert-agent", true + case 5033: + return "jtnetd-server", true + case 5034: + return "jtnetd-status", true + case 5042: + return "asnaacceler8db", true + case 5043: + return "swxadmin", true + case 5044: + return "lxi-evntsvc", true + case 5045: + return "osp", true + case 5048: + return "texai", true + case 5049: + return "ivocalize", true + case 5050: + return "mmcc", true + case 5051: + return "ita-agent", true + case 5052: + return "ita-manager", true + case 5053: + return "rlm", true + case 5054: + return "rlm-admin", true + case 5055: + return "unot", true + case 5056: + return "intecom-ps1", true + case 5057: + return "intecom-ps2", true + case 5059: + return "sds", true + case 5060: + return "sip", true + case 5061: + return "sips", true + case 5062: + return "na-localise", true + case 5063: + return "csrpc", true + case 5064: + return "ca-1", true + case 5065: + return "ca-2", true + case 5066: + return "stanag-5066", true + case 5067: + return "authentx", true + case 5068: + return "bitforestsrv", true + case 5069: + return "i-net-2000-npr", true + case 5070: + return "vtsas", true + case 5071: + return "powerschool", true + case 5072: + return "ayiya", true + case 5073: + return "tag-pm", true + case 5074: + return "alesquery", true + case 5075: + return "pvaccess", true + case 5080: + return "onscreen", true + case 5081: + return "sdl-ets", true + case 5082: + return "qcp", true + case 5083: + return "qfp", true + case 5084: + return "llrp", true + case 5085: + return "encrypted-llrp", true + case 5086: + return "aprigo-cs", true + case 5087: + return "biotic", true + case 5093: + return "sentinel-lm", true + case 5094: + return "hart-ip", true + case 5099: + return "sentlm-srv2srv", true + case 5100: + return "socalia", true + case 5101: + return "talarian-tcp", true + case 5102: + return "oms-nonsecure", true + case 5103: + return "actifio-c2c", true + case 5106: + return "actifioudsagent", true + case 5107: + return "actifioreplic", true + case 5111: + return "taep-as-svc", true + case 5112: + return "pm-cmdsvr", true + case 5114: + return "ev-services", true + case 5115: + return "autobuild", true + case 5117: + return "gradecam", true + case 5120: + return "barracuda-bbs", true + case 5133: + return "nbt-pc", true + case 5134: + return "ppactivation", true + case 5135: + return "erp-scale", true + case 5137: + return "ctsd", true + case 5145: + return "rmonitor-secure", true + case 5146: + return "social-alarm", true + case 5150: + return "atmp", true + case 5151: + return "esri-sde", true + case 5152: + return "sde-discovery", true + case 5154: + return "bzflag", true + case 5155: + return "asctrl-agent", true + case 5156: + return "rugameonline", true + case 5157: + return "mediat", true + case 5161: + return "snmpssh", true + case 5162: + return "snmpssh-trap", true + case 5163: + return "sbackup", true + case 5164: + return "vpa", true + case 5165: + return "ife-icorp", true + case 5166: + return "winpcs", true + case 5167: + return "scte104", true + case 5168: + return "scte30", true + case 5172: + return "pcoip-mgmt", true + case 5190: + return "aol", true + case 5191: + return "aol-1", true + case 5192: + return "aol-2", true + case 5193: + return "aol-3", true + case 5194: + return "cpscomm", true + case 5195: + return "ampl-lic", true + case 5196: + return "ampl-tableproxy", true + case 5197: + return "tunstall-lwp", true + case 5200: + return "targus-getdata", true + case 5201: + return "targus-getdata1", true + case 5202: + return "targus-getdata2", true + case 5203: + return "targus-getdata3", true + case 5209: + return "nomad", true + case 5215: + return "noteza", true + case 5221: + return "3exmp", true + case 5222: + return "xmpp-client", true + case 5223: + return "hpvirtgrp", true + case 5224: + return "hpvirtctrl", true + case 5225: + return "hp-server", true + case 5226: + return "hp-status", true + case 5227: + return "perfd", true + case 5228: + return "hpvroom", true + case 5229: + return "jaxflow", true + case 5230: + return "jaxflow-data", true + case 5231: + return "crusecontrol", true + case 5232: + return "csedaemon", true + case 5233: + return "enfs", true + case 5234: + return "eenet", true + case 5235: + return "galaxy-network", true + case 5236: + return "padl2sim", true + case 5237: + return "mnet-discovery", true + case 5242: + return "attune", true + case 5243: + return "xycstatus", true + case 5245: + return "downtools", true + case 5248: + return "caacws", true + case 5249: + return "caaclang2", true + case 5250: + return "soagateway", true + case 5251: + return "caevms", true + case 5252: + return "movaz-ssc", true + case 5253: + return "kpdp", true + case 5254: + return "logcabin", true + case 5264: + return "3com-njack-1", true + case 5265: + return "3com-njack-2", true + case 5269: + return "xmpp-server", true + case 5270: + return "cartographerxmp", true + case 5271: + return "cuelink", true + case 5272: + return "pk", true + case 5280: + return "xmpp-bosh", true + case 5281: + return "undo-lm", true + case 5282: + return "transmit-port", true + case 5298: + return "presence", true + case 5299: + return "nlg-data", true + case 5300: + return "hacl-hb", true + case 5301: + return "hacl-gs", true + case 5302: + return "hacl-cfg", true + case 5303: + return "hacl-probe", true + case 5304: + return "hacl-local", true + case 5305: + return "hacl-test", true + case 5306: + return "sun-mc-grp", true + case 5307: + return "sco-aip", true + case 5308: + return "cfengine", true + case 5309: + return "jprinter", true + case 5310: + return "outlaws", true + case 5312: + return "permabit-cs", true + case 5313: + return "rrdp", true + case 5314: + return "opalis-rbt-ipc", true + case 5315: + return "hacl-poll", true + case 5316: + return "hpbladems", true + case 5317: + return "hpdevms", true + case 5318: + return "pkix-cmc", true + case 5320: + return "bsfserver-zn", true + case 5321: + return "bsfsvr-zn-ssl", true + case 5343: + return "kfserver", true + case 5344: + return "xkotodrcp", true + case 5349: + return "stuns", true + case 5352: + return "dns-llq", true + case 5353: + return "mdns", true + case 5354: + return "mdnsresponder", true + case 5355: + return "llmnr", true + case 5356: + return "ms-smlbiz", true + case 5357: + return "wsdapi", true + case 5358: + return "wsdapi-s", true + case 5359: + return "ms-alerter", true + case 5360: + return "ms-sideshow", true + case 5361: + return "ms-s-sideshow", true + case 5362: + return "serverwsd2", true + case 5363: + return "net-projection", true + case 5397: + return "stresstester", true + case 5398: + return "elektron-admin", true + case 5399: + return "securitychase", true + case 5400: + return "excerpt", true + case 5401: + return "excerpts", true + case 5402: + return "mftp", true + case 5403: + return "hpoms-ci-lstn", true + case 5404: + return "hpoms-dps-lstn", true + case 5405: + return "netsupport", true + case 5406: + return "systemics-sox", true + case 5407: + return "foresyte-clear", true + case 5408: + return "foresyte-sec", true + case 5409: + return "salient-dtasrv", true + case 5410: + return "salient-usrmgr", true + case 5411: + return "actnet", true + case 5412: + return "continuus", true + case 5413: + return "wwiotalk", true + case 5414: + return "statusd", true + case 5415: + return "ns-server", true + case 5416: + return "sns-gateway", true + case 5417: + return "sns-agent", true + case 5418: + return "mcntp", true + case 5419: + return "dj-ice", true + case 5420: + return "cylink-c", true + case 5421: + return "netsupport2", true + case 5422: + return "salient-mux", true + case 5423: + return "virtualuser", true + case 5424: + return "beyond-remote", true + case 5425: + return "br-channel", true + case 5426: + return "devbasic", true + case 5427: + return "sco-peer-tta", true + case 5428: + return "telaconsole", true + case 5429: + return "base", true + case 5430: + return "radec-corp", true + case 5431: + return "park-agent", true + case 5432: + return "postgresql", true + case 5433: + return "pyrrho", true + case 5434: + return "sgi-arrayd", true + case 5435: + return "sceanics", true + case 5443: + return "spss", true + case 5445: + return "smbdirect", true + case 5450: + return "tiepie", true + case 5453: + return "surebox", true + case 5454: + return "apc-5454", true + case 5455: + return "apc-5455", true + case 5456: + return "apc-5456", true + case 5461: + return "silkmeter", true + case 5462: + return "ttl-publisher", true + case 5463: + return "ttlpriceproxy", true + case 5464: + return "quailnet", true + case 5465: + return "netops-broker", true + case 5470: + return "apsolab-col", true + case 5471: + return "apsolab-cols", true + case 5472: + return "apsolab-tag", true + case 5473: + return "apsolab-tags", true + case 5475: + return "apsolab-data", true + case 5500: + return "fcp-addr-srvr1", true + case 5501: + return "fcp-addr-srvr2", true + case 5502: + return "fcp-srvr-inst1", true + case 5503: + return "fcp-srvr-inst2", true + case 5504: + return "fcp-cics-gw1", true + case 5505: + return "checkoutdb", true + case 5506: + return "amc", true + case 5507: + return "psl-management", true + case 5540: + return "matter", true + case 5550: + return "cbus", true + case 5553: + return "sgi-eventmond", true + case 5554: + return "sgi-esphttp", true + case 5555: + return "personal-agent", true + case 5556: + return "freeciv", true + case 5557: + return "farenet", true + case 5565: + return "dp-bura", true + case 5566: + return "westec-connect", true + case 5567: + return "dof-dps-mc-sec", true + case 5568: + return "sdt", true + case 5569: + return "rdmnet-ctrl", true + case 5573: + return "sdmmp", true + case 5574: + return "lsi-bobcat", true + case 5575: + return "ora-oap", true + case 5579: + return "fdtracks", true + case 5580: + return "tmosms0", true + case 5581: + return "tmosms1", true + case 5582: + return "fac-restore", true + case 5583: + return "tmo-icon-sync", true + case 5584: + return "bis-web", true + case 5585: + return "bis-sync", true + case 5586: + return "att-mt-sms", true + case 5597: + return "ininmessaging", true + case 5598: + return "mctfeed", true + case 5599: + return "esinstall", true + case 5600: + return "esmmanager", true + case 5601: + return "esmagent", true + case 5602: + return "a1-msc", true + case 5603: + return "a1-bs", true + case 5604: + return "a3-sdunode", true + case 5605: + return "a4-sdunode", true + case 5618: + return "efr", true + case 5627: + return "ninaf", true + case 5628: + return "htrust", true + case 5629: + return "symantec-sfdb", true + case 5630: + return "precise-comm", true + case 5631: + return "pcanywheredata", true + case 5632: + return "pcanywherestat", true + case 5633: + return "beorl", true + case 5634: + return "xprtld", true + case 5635: + return "sfmsso", true + case 5636: + return "sfm-db-server", true + case 5637: + return "cssc", true + case 5638: + return "flcrs", true + case 5639: + return "ics", true + case 5646: + return "vfmobile", true + case 5666: + return "nrpe", true + case 5670: + return "filemq", true + case 5671: + return "amqps", true + case 5672: + return "amqp", true + case 5673: + return "jms", true + case 5674: + return "hyperscsi-port", true + case 5675: + return "v5ua", true + case 5676: + return "raadmin", true + case 5677: + return "questdb2-lnchr", true + case 5678: + return "rrac", true + case 5679: + return "dccm", true + case 5680: + return "auriga-router", true + case 5681: + return "ncxcp", true + case 5683: + return "coap", true + case 5684: + return "coaps", true + case 5688: + return "ggz", true + case 5689: + return "qmvideo", true + case 5693: + return "rbsystem", true + case 5696: + return "kmip", true + case 5700: + return "supportassist", true + case 5705: + return "storageos", true + case 5713: + return "proshareaudio", true + case 5714: + return "prosharevideo", true + case 5715: + return "prosharedata", true + case 5716: + return "prosharerequest", true + case 5717: + return "prosharenotify", true + case 5718: + return "dpm", true + case 5719: + return "dpm-agent", true + case 5720: + return "ms-licensing", true + case 5721: + return "dtpt", true + case 5722: + return "msdfsr", true + case 5723: + return "omhs", true + case 5724: + return "omsdk", true + case 5725: + return "ms-ilm", true + case 5726: + return "ms-ilm-sts", true + case 5727: + return "asgenf", true + case 5728: + return "io-dist-data", true + case 5729: + return "openmail", true + case 5730: + return "unieng", true + case 5741: + return "ida-discover1", true + case 5742: + return "ida-discover2", true + case 5743: + return "watchdoc-pod", true + case 5744: + return "watchdoc", true + case 5745: + return "fcopy-server", true + case 5746: + return "fcopys-server", true + case 5747: + return "tunatic", true + case 5748: + return "tunalyzer", true + case 5750: + return "rscd", true + case 5755: + return "openmailg", true + case 5757: + return "x500ms", true + case 5766: + return "openmailns", true + case 5767: + return "s-openmail", true + case 5768: + return "openmailpxy", true + case 5769: + return "spramsca", true + case 5770: + return "spramsd", true + case 5771: + return "netagent", true + case 5777: + return "starfield-io", true + case 5780: + return "vts-rpc", true + case 5781: + return "3par-evts", true + case 5782: + return "3par-mgmt", true + case 5783: + return "3par-mgmt-ssl", true + case 5785: + return "3par-rcopy", true + case 5793: + return "xtreamx", true + case 5798: + return "enlabel-dpl", true + case 5813: + return "icmpd", true + case 5814: + return "spt-automation", true + case 5820: + return "autopassdaemon", true + case 5841: + return "shiprush-d-ch", true + case 5842: + return "reversion", true + case 5859: + return "wherehoo", true + case 5863: + return "ppsuitemsg", true + case 5868: + return "diameters", true + case 5883: + return "jute", true + case 5900: + return "rfb", true + case 5903: + return "ff-ice", true + case 5904: + return "ag-swim", true + case 5905: + return "asmgcs", true + case 5906: + return "rpas-c2", true + case 5907: + return "dsd", true + case 5908: + return "ipsma", true + case 5909: + return "agma", true + case 5910: + return "ats-atn", true + case 5911: + return "ats-acars", true + case 5912: + return "ais-met", true + case 5913: + return "aoc-acars", true + case 5963: + return "indy", true + case 5968: + return "mppolicy-v5", true + case 5969: + return "mppolicy-mgr", true + case 5984: + return "couchdb", true + case 5985: + return "wsman", true + case 5986: + return "wsmans", true + case 5987: + return "wbem-rmi", true + case 5988: + return "wbem-http", true + case 5989: + return "wbem-https", true + case 5990: + return "wbem-exp-https", true + case 5991: + return "nuxsl", true + case 5992: + return "consul-insight", true + case 5993: + return "cim-rs", true + case 5994: + return "rms-agent", true + case 5999: + return "cvsup", true + case 6064: + return "ndl-ahp-svc", true + case 6065: + return "winpharaoh", true + case 6066: + return "ewctsp", true + case 6068: + return "gsmp-ancp", true + case 6069: + return "trip", true + case 6070: + return "messageasap", true + case 6071: + return "ssdtp", true + case 6072: + return "diagnose-proc", true + case 6073: + return "directplay8", true + case 6074: + return "max", true + case 6075: + return "dpm-acm", true + case 6076: + return "msft-dpm-cert", true + case 6077: + return "iconstructsrv", true + case 6084: + return "reload-config", true + case 6085: + return "konspire2b", true + case 6086: + return "pdtp", true + case 6087: + return "ldss", true + case 6088: + return "doglms", true + case 6099: + return "raxa-mgmt", true + case 6100: + return "synchronet-db", true + case 6101: + return "synchronet-rtc", true + case 6102: + return "synchronet-upd", true + case 6103: + return "rets", true + case 6104: + return "dbdb", true + case 6105: + return "primaserver", true + case 6106: + return "mpsserver", true + case 6107: + return "etc-control", true + case 6108: + return "sercomm-scadmin", true + case 6109: + return "globecast-id", true + case 6110: + return "softcm", true + case 6111: + return "spc", true + case 6112: + return "dtspcd", true + case 6113: + return "dayliteserver", true + case 6114: + return "wrspice", true + case 6115: + return "xic", true + case 6116: + return "xtlserv", true + case 6117: + return "daylitetouch", true + case 6121: + return "spdy", true + case 6122: + return "bex-webadmin", true + case 6123: + return "backup-express", true + case 6124: + return "pnbs", true + case 6130: + return "damewaremobgtwy", true + case 6133: + return "nbt-wol", true + case 6140: + return "pulsonixnls", true + case 6141: + return "meta-corp", true + case 6142: + return "aspentec-lm", true + case 6143: + return "watershed-lm", true + case 6144: + return "statsci1-lm", true + case 6145: + return "statsci2-lm", true + case 6146: + return "lonewolf-lm", true + case 6147: + return "montage-lm", true + case 6148: + return "ricardo-lm", true + case 6149: + return "tal-pod", true + case 6159: + return "efb-aci", true + case 6160: + return "ecmp", true + case 6161: + return "patrol-ism", true + case 6162: + return "patrol-coll", true + case 6163: + return "pscribe", true + case 6200: + return "lm-x", true + case 6209: + return "qmtps", true + case 6222: + return "radmind", true + case 6241: + return "jeol-nsdtp-1", true + case 6242: + return "jeol-nsdtp-2", true + case 6243: + return "jeol-nsdtp-3", true + case 6244: + return "jeol-nsdtp-4", true + case 6251: + return "tl1-raw-ssl", true + case 6252: + return "tl1-ssh", true + case 6253: + return "crip", true + case 6267: + return "gld", true + case 6268: + return "grid", true + case 6269: + return "grid-alt", true + case 6300: + return "bmc-grx", true + case 6301: + return "bmc-ctd-ldap", true + case 6306: + return "ufmp", true + case 6315: + return "scup", true + case 6316: + return "abb-escp", true + case 6317: + return "nav-data-cmd", true + case 6320: + return "repsvc", true + case 6321: + return "emp-server1", true + case 6322: + return "emp-server2", true + case 6324: + return "hrd-ncs", true + case 6325: + return "dt-mgmtsvc", true + case 6326: + return "dt-vra", true + case 6343: + return "sflow", true + case 6344: + return "streletz", true + case 6346: + return "gnutella-svc", true + case 6347: + return "gnutella-rtr", true + case 6350: + return "adap", true + case 6355: + return "pmcs", true + case 6360: + return "metaedit-mu", true + case 6370: + return "metaedit-se", true + case 6379: + return "redis", true + case 6382: + return "metatude-mds", true + case 6389: + return "clariion-evr01", true + case 6390: + return "metaedit-ws", true + case 6417: + return "faxcomservice", true + case 6418: + return "syserverremote", true + case 6419: + return "svdrp", true + case 6420: + return "nim-vdrshell", true + case 6421: + return "nim-wan", true + case 6432: + return "pgbouncer", true + case 6440: + return "heliosd", true + case 6442: + return "tarp", true + case 6443: + return "sun-sr-https", true + case 6444: + return "sge-qmaster", true + case 6445: + return "sge-execd", true + case 6446: + return "mysql-proxy", true + case 6455: + return "skip-cert-recv", true + case 6456: + return "skip-cert-send", true + case 6464: + return "ieee11073-20701", true + case 6471: + return "lvision-lm", true + case 6480: + return "sun-sr-http", true + case 6481: + return "servicetags", true + case 6482: + return "ldoms-mgmt", true + case 6483: + return "SunVTS-RMI", true + case 6484: + return "sun-sr-jms", true + case 6485: + return "sun-sr-iiop", true + case 6486: + return "sun-sr-iiops", true + case 6487: + return "sun-sr-iiop-aut", true + case 6488: + return "sun-sr-jmx", true + case 6489: + return "sun-sr-admin", true + case 6500: + return "boks", true + case 6501: + return "boks-servc", true + case 6502: + return "boks-servm", true + case 6503: + return "boks-clntd", true + case 6505: + return "badm-priv", true + case 6506: + return "badm-pub", true + case 6507: + return "bdir-priv", true + case 6508: + return "bdir-pub", true + case 6509: + return "mgcs-mfp-port", true + case 6510: + return "mcer-port", true + case 6513: + return "netconf-tls", true + case 6514: + return "syslog-tls", true + case 6515: + return "elipse-rec", true + case 6543: + return "lds-distrib", true + case 6544: + return "lds-dump", true + case 6547: + return "apc-6547", true + case 6548: + return "apc-6548", true + case 6549: + return "apc-6549", true + case 6550: + return "fg-sysupdate", true + case 6551: + return "sum", true + case 6556: + return "checkmk-agent", true + case 6558: + return "xdsxdm", true + case 6566: + return "sane-port", true + case 6568: + return "canit-store", true + case 6579: + return "affiliate", true + case 6580: + return "parsec-master", true + case 6581: + return "parsec-peer", true + case 6582: + return "parsec-game", true + case 6583: + return "joaJewelSuite", true + case 6600: + return "mshvlm", true + case 6601: + return "mstmg-sstp", true + case 6602: + return "wsscomfrmwk", true + case 6619: + return "odette-ftps", true + case 6620: + return "kftp-data", true + case 6621: + return "kftp", true + case 6622: + return "mcftp", true + case 6623: + return "ktelnet", true + case 6624: + return "datascaler-db", true + case 6625: + return "datascaler-ctl", true + case 6626: + return "wago-service", true + case 6627: + return "nexgen", true + case 6628: + return "afesc-mc", true + case 6629: + return "nexgen-aux", true + case 6632: + return "mxodbc-connect", true + case 6640: + return "ovsdb", true + case 6653: + return "openflow", true + case 6655: + return "pcs-sf-ui-man", true + case 6656: + return "emgmsg", true + case 6670: + return "vocaltec-gold", true + case 6671: + return "p4p-portal", true + case 6672: + return "vision-server", true + case 6673: + return "vision-elmd", true + case 6678: + return "vfbp", true + case 6679: + return "osaut", true + case 6687: + return "clever-ctrace", true + case 6688: + return "clever-tcpip", true + case 6689: + return "tsa", true + case 6690: + return "cleverdetect", true + case 6697: + return "ircs-u", true + case 6701: + return "kti-icad-srvr", true + case 6702: + return "e-design-net", true + case 6703: + return "e-design-web", true + case 6714: + return "ibprotocol", true + case 6715: + return "fibotrader-com", true + case 6716: + return "princity-agent", true + case 6767: + return "bmc-perf-agent", true + case 6768: + return "bmc-perf-mgrd", true + case 6769: + return "adi-gxp-srvprt", true + case 6770: + return "plysrv-http", true + case 6771: + return "plysrv-https", true + case 6777: + return "ntz-tracker", true + case 6778: + return "ntz-p2p-storage", true + case 6785: + return "dgpf-exchg", true + case 6786: + return "smc-jmx", true + case 6787: + return "smc-admin", true + case 6788: + return "smc-http", true + case 6789: + return "radg", true + case 6790: + return "hnmp", true + case 6791: + return "hnm", true + case 6801: + return "acnet", true + case 6817: + return "pentbox-sim", true + case 6831: + return "ambit-lm", true + case 6841: + return "netmo-default", true + case 6842: + return "netmo-http", true + case 6850: + return "iccrushmore", true + case 6868: + return "acctopus-cc", true + case 6888: + return "muse", true + case 6900: + return "rtimeviewer", true + case 6901: + return "jetstream", true + case 6924: + return "split-ping", true + case 6935: + return "ethoscan", true + case 6936: + return "xsmsvc", true + case 6946: + return "bioserver", true + case 6951: + return "otlp", true + case 6961: + return "jmact3", true + case 6962: + return "jmevt2", true + case 6963: + return "swismgr1", true + case 6964: + return "swismgr2", true + case 6965: + return "swistrap", true + case 6966: + return "swispol", true + case 6969: + return "acmsoda", true + case 6970: + return "conductor", true + case 6997: + return "MobilitySrv", true + case 6998: + return "iatp-highpri", true + case 6999: + return "iatp-normalpri", true + case 7000: + return "afs3-fileserver", true + case 7001: + return "afs3-callback", true + case 7002: + return "afs3-prserver", true + case 7003: + return "afs3-vlserver", true + case 7004: + return "afs3-kaserver", true + case 7005: + return "afs3-volser", true + case 7006: + return "afs3-errors", true + case 7007: + return "afs3-bos", true + case 7008: + return "afs3-update", true + case 7009: + return "afs3-rmtsys", true + case 7010: + return "ups-onlinet", true + case 7011: + return "talon-disc", true + case 7012: + return "talon-engine", true + case 7013: + return "microtalon-dis", true + case 7014: + return "microtalon-com", true + case 7015: + return "talon-webserver", true + case 7016: + return "spg", true + case 7017: + return "grasp", true + case 7018: + return "fisa-svc", true + case 7019: + return "doceri-ctl", true + case 7020: + return "dpserve", true + case 7021: + return "dpserveadmin", true + case 7022: + return "ctdp", true + case 7023: + return "ct2nmcs", true + case 7024: + return "vmsvc", true + case 7025: + return "vmsvc-2", true + case 7026: + return "loreji-panel", true + case 7030: + return "op-probe", true + case 7031: + return "iposplanet", true + case 7070: + return "arcp", true + case 7071: + return "iwg1", true + case 7072: + return "iba-cfg", true + case 7073: + return "martalk", true + case 7080: + return "empowerid", true + case 7099: + return "lazy-ptop", true + case 7100: + return "font-service", true + case 7101: + return "elcn", true + case 7117: + return "rothaga", true + case 7121: + return "virprot-lm", true + case 7123: + return "snif", true + case 7128: + return "scenidm", true + case 7129: + return "scenccs", true + case 7161: + return "cabsm-comm", true + case 7162: + return "caistoragemgr", true + case 7163: + return "cacsambroker", true + case 7164: + return "fsr", true + case 7165: + return "doc-server", true + case 7166: + return "aruba-server", true + case 7167: + return "casrmagent", true + case 7168: + return "cnckadserver", true + case 7169: + return "ccag-pib", true + case 7170: + return "nsrp", true + case 7171: + return "drm-production", true + case 7172: + return "metalbend", true + case 7173: + return "zsecure", true + case 7174: + return "clutild", true + case 7200: + return "fodms", true + case 7201: + return "dlip", true + case 7202: + return "pon-ictp", true + case 7215: + return "PS-Server", true + case 7216: + return "PS-Capture-Pro", true + case 7227: + return "ramp", true + case 7228: + return "citrixupp", true + case 7229: + return "citrixuppg", true + case 7234: + return "asa-gateways", true + case 7236: + return "display", true + case 7237: + return "pads", true + case 7244: + return "frc-hicp", true + case 7262: + return "cnap", true + case 7272: + return "watchme-7272", true + case 7273: + return "oma-rlp", true + case 7274: + return "oma-rlp-s", true + case 7275: + return "oma-ulp", true + case 7276: + return "oma-ilp", true + case 7277: + return "oma-ilp-s", true + case 7278: + return "oma-dcdocbs", true + case 7279: + return "ctxlic", true + case 7280: + return "itactionserver1", true + case 7281: + return "itactionserver2", true + case 7282: + return "mzca-action", true + case 7283: + return "genstat", true + case 7365: + return "lcm-server", true + case 7391: + return "mindfilesys", true + case 7392: + return "mrssrendezvous", true + case 7393: + return "nfoldman", true + case 7394: + return "fse", true + case 7395: + return "winqedit", true + case 7397: + return "hexarc", true + case 7400: + return "rtps-discovery", true + case 7401: + return "rtps-dd-ut", true + case 7402: + return "rtps-dd-mt", true + case 7410: + return "ionixnetmon", true + case 7411: + return "daqstream", true + case 7421: + return "mtportmon", true + case 7426: + return "pmdmgr", true + case 7427: + return "oveadmgr", true + case 7428: + return "ovladmgr", true + case 7429: + return "opi-sock", true + case 7430: + return "xmpv7", true + case 7431: + return "pmd", true + case 7437: + return "faximum", true + case 7443: + return "oracleas-https", true + case 7471: + return "sttunnel", true + case 7473: + return "rise", true + case 7474: + return "neo4j", true + case 7478: + return "openit", true + case 7491: + return "telops-lmd", true + case 7500: + return "silhouette", true + case 7501: + return "ovbus", true + case 7508: + return "adcp", true + case 7509: + return "acplt", true + case 7510: + return "ovhpas", true + case 7511: + return "pafec-lm", true + case 7542: + return "saratoga", true + case 7543: + return "atul", true + case 7544: + return "nta-ds", true + case 7545: + return "nta-us", true + case 7546: + return "cfs", true + case 7547: + return "cwmp", true + case 7548: + return "tidp", true + case 7549: + return "nls-tl", true + case 7551: + return "controlone-con", true + case 7560: + return "sncp", true + case 7563: + return "cfw", true + case 7566: + return "vsi-omega", true + case 7569: + return "dell-eql-asm", true + case 7570: + return "aries-kfinder", true + case 7574: + return "coherence", true + case 7588: + return "sun-lm", true + case 7606: + return "mipi-debug", true + case 7624: + return "indi", true + case 7626: + return "simco", true + case 7627: + return "soap-http", true + case 7628: + return "zen-pawn", true + case 7629: + return "xdas", true + case 7630: + return "hawk", true + case 7631: + return "tesla-sys-msg", true + case 7633: + return "pmdfmgt", true + case 7648: + return "cuseeme", true + case 7663: + return "rome", true + case 7672: + return "imqstomp", true + case 7673: + return "imqstomps", true + case 7674: + return "imqtunnels", true + case 7675: + return "imqtunnel", true + case 7676: + return "imqbrokerd", true + case 7677: + return "sun-user-https", true + case 7680: + return "ms-do", true + case 7683: + return "dmt", true + case 7687: + return "bolt", true + case 7689: + return "collaber", true + case 7690: + return "sovd", true + case 7697: + return "klio", true + case 7700: + return "em7-secom", true + case 7707: + return "sync-em7", true + case 7708: + return "scinet", true + case 7720: + return "medimageportal", true + case 7724: + return "nsdeepfreezectl", true + case 7725: + return "nitrogen", true + case 7726: + return "freezexservice", true + case 7727: + return "trident-data", true + case 7728: + return "osvr", true + case 7734: + return "smip", true + case 7738: + return "aiagent", true + case 7741: + return "scriptview", true + case 7742: + return "msss", true + case 7743: + return "sstp-1", true + case 7744: + return "raqmon-pdu", true + case 7747: + return "prgp", true + case 7775: + return "inetfs", true + case 7777: + return "cbt", true + case 7778: + return "interwise", true + case 7779: + return "vstat", true + case 7781: + return "accu-lmgr", true + case 7786: + return "minivend", true + case 7787: + return "popup-reminders", true + case 7789: + return "office-tools", true + case 7794: + return "q3ade", true + case 7797: + return "pnet-conn", true + case 7798: + return "pnet-enc", true + case 7799: + return "altbsdp", true + case 7800: + return "asr", true + case 7801: + return "ssp-client", true + case 7810: + return "rbt-wanopt", true + case 7845: + return "apc-7845", true + case 7846: + return "apc-7846", true + case 7847: + return "csoauth", true + case 7869: + return "mobileanalyzer", true + case 7870: + return "rbt-smc", true + case 7871: + return "mdm", true + case 7878: + return "owms", true + case 7880: + return "pss", true + case 7887: + return "ubroker", true + case 7900: + return "mevent", true + case 7901: + return "tnos-sp", true + case 7902: + return "tnos-dp", true + case 7903: + return "tnos-dps", true + case 7913: + return "qo-secure", true + case 7932: + return "t2-drm", true + case 7933: + return "t2-brm", true + case 7962: + return "generalsync", true + case 7967: + return "supercell", true + case 7979: + return "micromuse-ncps", true + case 7980: + return "quest-vista", true + case 7981: + return "sossd-collect", true + case 7982: + return "sossd-agent", true + case 7997: + return "pushns", true + case 7999: + return "irdmi2", true + case 8000: + return "irdmi", true + case 8001: + return "vcom-tunnel", true + case 8002: + return "teradataordbms", true + case 8003: + return "mcreport", true + case 8004: + return "p2pevolvenet", true + case 8005: + return "mxi", true + case 8006: + return "wpl-analytics", true + case 8007: + return "warppipe", true + case 8008: + return "http-alt", true + case 8009: + return "nvme-disc", true + case 8015: + return "cfg-cloud", true + case 8016: + return "ads-s", true + case 8019: + return "qbdb", true + case 8020: + return "intu-ec-svcdisc", true + case 8021: + return "intu-ec-client", true + case 8022: + return "oa-system", true + case 8023: + return "arca-api", true + case 8025: + return "ca-audit-da", true + case 8026: + return "ca-audit-ds", true + case 8027: + return "papachi-p2p-srv", true + case 8032: + return "pro-ed", true + case 8033: + return "mindprint", true + case 8034: + return "vantronix-mgmt", true + case 8040: + return "ampify", true + case 8041: + return "enguity-xccetp", true + case 8042: + return "fs-agent", true + case 8043: + return "fs-server", true + case 8044: + return "fs-mgmt", true + case 8051: + return "rocrail", true + case 8052: + return "senomix01", true + case 8053: + return "senomix02", true + case 8054: + return "senomix03", true + case 8055: + return "senomix04", true + case 8056: + return "senomix05", true + case 8057: + return "senomix06", true + case 8058: + return "senomix07", true + case 8059: + return "senomix08", true + case 8066: + return "toad-bi-appsrvr", true + case 8067: + return "infi-async", true + case 8070: + return "ucs-isc", true + case 8074: + return "gadugadu", true + case 8077: + return "mles", true + case 8080: + return "http-alt", true + case 8081: + return "sunproxyadmin", true + case 8082: + return "us-cli", true + case 8083: + return "us-srv", true + case 8084: + return "websnp", true + case 8086: + return "d-s-n", true + case 8087: + return "simplifymedia", true + case 8088: + return "radan-http", true + case 8090: + return "opsmessaging", true + case 8091: + return "jamlink", true + case 8097: + return "sac", true + case 8100: + return "xprint-server", true + case 8101: + return "ldoms-migr", true + case 8102: + return "kz-migr", true + case 8115: + return "mtl8000-matrix", true + case 8116: + return "cp-cluster", true + case 8117: + return "purityrpc", true + case 8118: + return "privoxy", true + case 8121: + return "apollo-data", true + case 8122: + return "apollo-admin", true + case 8128: + return "paycash-online", true + case 8129: + return "paycash-wbp", true + case 8130: + return "indigo-vrmi", true + case 8131: + return "indigo-vbcp", true + case 8132: + return "dbabble", true + case 8140: + return "puppet", true + case 8148: + return "isdd", true + case 8153: + return "quantastor", true + case 8160: + return "patrol", true + case 8161: + return "patrol-snmp", true + case 8162: + return "lpar2rrd", true + case 8181: + return "intermapper", true + case 8182: + return "vmware-fdm", true + case 8183: + return "proremote", true + case 8184: + return "itach", true + case 8190: + return "gcp-rphy", true + case 8191: + return "limnerpressure", true + case 8192: + return "spytechphone", true + case 8194: + return "blp1", true + case 8195: + return "blp2", true + case 8199: + return "vvr-data", true + case 8200: + return "trivnet1", true + case 8201: + return "trivnet2", true + case 8204: + return "lm-perfworks", true + case 8205: + return "lm-instmgr", true + case 8206: + return "lm-dta", true + case 8207: + return "lm-sserver", true + case 8208: + return "lm-webwatcher", true + case 8230: + return "rexecj", true + case 8243: + return "synapse-nhttps", true + case 8270: + return "robot-remote", true + case 8276: + return "ms-mcc", true + case 8280: + return "synapse-nhttp", true + case 8282: + return "libelle", true + case 8292: + return "blp3", true + case 8293: + return "hiperscan-id", true + case 8294: + return "blp4", true + case 8300: + return "tmi", true + case 8301: + return "amberon", true + case 8313: + return "hub-open-net", true + case 8320: + return "tnp-discover", true + case 8321: + return "tnp", true + case 8322: + return "garmin-marine", true + case 8351: + return "server-find", true + case 8376: + return "cruise-enum", true + case 8377: + return "cruise-swroute", true + case 8378: + return "cruise-config", true + case 8379: + return "cruise-diags", true + case 8380: + return "cruise-update", true + case 8383: + return "m2mservices", true + case 8400: + return "cvd", true + case 8401: + return "sabarsd", true + case 8402: + return "abarsd", true + case 8403: + return "admind", true + case 8404: + return "svcloud", true + case 8405: + return "svbackup", true + case 8415: + return "dlpx-sp", true + case 8416: + return "espeech", true + case 8417: + return "espeech-rtp", true + case 8423: + return "aritts", true + case 8432: + return "pgbackrest", true + case 8442: + return "cybro-a-bus", true + case 8443: + return "pcsync-https", true + case 8444: + return "pcsync-http", true + case 8445: + return "copy", true + case 8450: + return "npmp", true + case 8457: + return "nexentamv", true + case 8470: + return "cisco-avp", true + case 8471: + return "pim-port", true + case 8472: + return "otv", true + case 8473: + return "vp2p", true + case 8474: + return "noteshare", true + case 8500: + return "fmtp", true + case 8501: + return "cmtp-mgt", true + case 8502: + return "ftnmtp", true + case 8554: + return "rtsp-alt", true + case 8555: + return "d-fence", true + case 8567: + return "dof-tunnel", true + case 8600: + return "asterix", true + case 8610: + return "canon-mfnp", true + case 8611: + return "canon-bjnp1", true + case 8612: + return "canon-bjnp2", true + case 8613: + return "canon-bjnp3", true + case 8614: + return "canon-bjnp4", true + case 8615: + return "imink", true + case 8665: + return "monetra", true + case 8666: + return "monetra-admin", true + case 8675: + return "msi-cps-rm", true + case 8686: + return "sun-as-jmxrmi", true + case 8688: + return "openremote-ctrl", true + case 8699: + return "vnyx", true + case 8710: + return "semi-grpc", true + case 8711: + return "nvc", true + case 8733: + return "ibus", true + case 8750: + return "dey-keyneg", true + case 8763: + return "mc-appserver", true + case 8764: + return "openqueue", true + case 8765: + return "ultraseek-http", true + case 8766: + return "amcs", true + case 8767: + return "core-of-source", true + case 8768: + return "sandpolis", true + case 8769: + return "oktaauthenticat", true + case 8770: + return "dpap", true + case 8778: + return "uec", true + case 8786: + return "msgclnt", true + case 8787: + return "msgsrvr", true + case 8793: + return "acd-pm", true + case 8800: + return "sunwebadmin", true + case 8804: + return "truecm", true + case 8873: + return "dxspider", true + case 8880: + return "cddbp-alt", true + case 8881: + return "galaxy4d", true + case 8883: + return "secure-mqtt", true + case 8888: + return "ddi-tcp-1", true + case 8889: + return "ddi-tcp-2", true + case 8890: + return "ddi-tcp-3", true + case 8891: + return "ddi-tcp-4", true + case 8892: + return "ddi-tcp-5", true + case 8893: + return "ddi-tcp-6", true + case 8894: + return "ddi-tcp-7", true + case 8899: + return "ospf-lite", true + case 8900: + return "jmb-cds1", true + case 8901: + return "jmb-cds2", true + case 8908: + return "dpp", true + case 8910: + return "manyone-http", true + case 8911: + return "manyone-xml", true + case 8912: + return "wcbackup", true + case 8913: + return "dragonfly", true + case 8937: + return "twds", true + case 8953: + return "ub-dns-control", true + case 8954: + return "cumulus-admin", true + case 8980: + return "nod-provider", true + case 8989: + return "sunwebadmins", true + case 8990: + return "http-wmap", true + case 8991: + return "https-wmap", true + case 8997: + return "oracle-ms-ens", true + case 8998: + return "canto-roboflow", true + case 8999: + return "bctp", true + case 9000: + return "cslistener", true + case 9001: + return "etlservicemgr", true + case 9002: + return "dynamid", true + case 9005: + return "golem", true + case 9008: + return "ogs-server", true + case 9009: + return "pichat", true + case 9010: + return "sdr", true + case 9020: + return "tambora", true + case 9021: + return "panagolin-ident", true + case 9022: + return "paragent", true + case 9023: + return "swa-1", true + case 9024: + return "swa-2", true + case 9025: + return "swa-3", true + case 9026: + return "swa-4", true + case 9050: + return "versiera", true + case 9051: + return "fio-cmgmt", true + case 9060: + return "CardWeb-IO", true + case 9080: + return "glrpc", true + case 9083: + return "emc-pp-mgmtsvc", true + case 9084: + return "aurora", true + case 9085: + return "ibm-rsyscon", true + case 9086: + return "net2display", true + case 9087: + return "classic", true + case 9088: + return "sqlexec", true + case 9089: + return "sqlexec-ssl", true + case 9090: + return "websm", true + case 9091: + return "xmltec-xmlmail", true + case 9092: + return "XmlIpcRegSvc", true + case 9093: + return "copycat", true + case 9100: + return "hp-pdl-datastr", true + case 9101: + return "bacula-dir", true + case 9102: + return "bacula-fd", true + case 9103: + return "bacula-sd", true + case 9104: + return "peerwire", true + case 9105: + return "xadmin", true + case 9106: + return "astergate", true + case 9107: + return "astergatefax", true + case 9111: + return "hexxorecore", true + case 9119: + return "mxit", true + case 9122: + return "grcmp", true + case 9123: + return "grcp", true + case 9131: + return "dddp", true + case 9160: + return "apani1", true + case 9161: + return "apani2", true + case 9162: + return "apani3", true + case 9163: + return "apani4", true + case 9164: + return "apani5", true + case 9191: + return "sun-as-jpda", true + case 9200: + return "wap-wsp", true + case 9201: + return "wap-wsp-wtp", true + case 9202: + return "wap-wsp-s", true + case 9203: + return "wap-wsp-wtp-s", true + case 9204: + return "wap-vcard", true + case 9205: + return "wap-vcal", true + case 9206: + return "wap-vcard-s", true + case 9207: + return "wap-vcal-s", true + case 9208: + return "rjcdb-vcards", true + case 9209: + return "almobile-system", true + case 9210: + return "oma-mlp", true + case 9211: + return "oma-mlp-s", true + case 9212: + return "serverviewdbms", true + case 9213: + return "serverstart", true + case 9214: + return "ipdcesgbs", true + case 9215: + return "insis", true + case 9216: + return "acme", true + case 9217: + return "fsc-port", true + case 9222: + return "teamcoherence", true + case 9255: + return "mon", true + case 9278: + return "pegasus", true + case 9279: + return "pegasus-ctl", true + case 9280: + return "pgps", true + case 9281: + return "swtp-port1", true + case 9282: + return "swtp-port2", true + case 9283: + return "callwaveiam", true + case 9284: + return "visd", true + case 9285: + return "n2h2server", true + case 9287: + return "cumulus", true + case 9292: + return "armtechdaemon", true + case 9293: + return "storview", true + case 9294: + return "armcenterhttp", true + case 9295: + return "armcenterhttps", true + case 9300: + return "vrace", true + case 9306: + return "sphinxql", true + case 9310: + return "sapms", true + case 9312: + return "sphinxapi", true + case 9318: + return "secure-ts", true + case 9321: + return "guibase", true + case 9339: + return "gnmi-gnoi", true + case 9340: + return "gribi", true + case 9343: + return "mpidcmgr", true + case 9344: + return "mphlpdmc", true + case 9345: + return "rancher", true + case 9346: + return "ctechlicensing", true + case 9374: + return "fjdmimgr", true + case 9380: + return "boxp", true + case 9387: + return "d2dconfig", true + case 9388: + return "d2ddatatrans", true + case 9389: + return "adws", true + case 9390: + return "otp", true + case 9396: + return "fjinvmgr", true + case 9397: + return "mpidcagt", true + case 9400: + return "sec-t4net-srv", true + case 9401: + return "sec-t4net-clt", true + case 9402: + return "sec-pc2fax-srv", true + case 9418: + return "git", true + case 9443: + return "tungsten-https", true + case 9444: + return "wso2esb-console", true + case 9445: + return "mindarray-ca", true + case 9450: + return "sntlkeyssrvr", true + case 9500: + return "ismserver", true + case 9535: + return "mngsuite", true + case 9536: + return "laes-bf", true + case 9555: + return "trispen-sra", true + case 9559: + return "p4runtime", true + case 9592: + return "ldgateway", true + case 9593: + return "cba8", true + case 9594: + return "msgsys", true + case 9595: + return "pds", true + case 9596: + return "mercury-disc", true + case 9597: + return "pd-admin", true + case 9598: + return "vscp", true + case 9599: + return "robix", true + case 9600: + return "micromuse-ncpw", true + case 9612: + return "streamcomm-ds", true + case 9614: + return "iadt-tls", true + case 9616: + return "erunbook-agent", true + case 9617: + return "erunbook-server", true + case 9618: + return "condor", true + case 9628: + return "odbcpathway", true + case 9629: + return "uniport", true + case 9630: + return "peoctlr", true + case 9631: + return "peocoll", true + case 9640: + return "pqsflows", true + case 9666: + return "zoomcp", true + case 9667: + return "xmms2", true + case 9668: + return "tec5-sdctp", true + case 9694: + return "client-wakeup", true + case 9695: + return "ccnx", true + case 9700: + return "board-roar", true + case 9747: + return "l5nas-parchan", true + case 9750: + return "board-voip", true + case 9753: + return "rasadv", true + case 9762: + return "tungsten-http", true + case 9800: + return "davsrc", true + case 9801: + return "sstp-2", true + case 9802: + return "davsrcs", true + case 9875: + return "sapv1", true + case 9876: + return "sd", true + case 9877: + return "x510", true + case 9888: + return "cyborg-systems", true + case 9889: + return "gt-proxy", true + case 9898: + return "monkeycom", true + case 9900: + return "iua", true + case 9909: + return "domaintime", true + case 9911: + return "sype-transport", true + case 9925: + return "xybrid-cloud", true + case 9950: + return "apc-9950", true + case 9951: + return "apc-9951", true + case 9952: + return "apc-9952", true + case 9953: + return "acis", true + case 9954: + return "hinp", true + case 9955: + return "alljoyn-stm", true + case 9966: + return "odnsp", true + case 9978: + return "xybrid-rt", true + case 9979: + return "visweather", true + case 9981: + return "pumpkindb", true + case 9987: + return "dsm-scm-target", true + case 9988: + return "nsesrvr", true + case 9990: + return "osm-appsrvr", true + case 9991: + return "osm-oev", true + case 9992: + return "palace-1", true + case 9993: + return "palace-2", true + case 9994: + return "palace-3", true + case 9995: + return "palace-4", true + case 9996: + return "palace-5", true + case 9997: + return "palace-6", true + case 9998: + return "distinct32", true + case 9999: + return "distinct", true + case 10000: + return "ndmp", true + case 10001: + return "scp-config", true + case 10002: + return "documentum", true + case 10003: + return "documentum-s", true + case 10004: + return "emcrmirccd", true + case 10005: + return "emcrmird", true + case 10006: + return "netapp-sync", true + case 10007: + return "mvs-capacity", true + case 10008: + return "octopus", true + case 10009: + return "swdtp-sv", true + case 10010: + return "rxapi", true + case 10020: + return "abb-hw", true + case 10050: + return "zabbix-agent", true + case 10051: + return "zabbix-trapper", true + case 10055: + return "qptlmd", true + case 10080: + return "amanda", true + case 10081: + return "famdc", true + case 10100: + return "itap-ddtp", true + case 10101: + return "ezmeeting-2", true + case 10102: + return "ezproxy-2", true + case 10103: + return "ezrelay", true + case 10104: + return "swdtp", true + case 10107: + return "bctp-server", true + case 10110: + return "nmea-0183", true + case 10113: + return "netiq-endpoint", true + case 10114: + return "netiq-qcheck", true + case 10115: + return "netiq-endpt", true + case 10116: + return "netiq-voipa", true + case 10117: + return "iqrm", true + case 10125: + return "cimple", true + case 10128: + return "bmc-perf-sd", true + case 10129: + return "bmc-gms", true + case 10160: + return "qb-db-server", true + case 10161: + return "snmptls", true + case 10162: + return "snmptls-trap", true + case 10200: + return "trisoap", true + case 10201: + return "rsms", true + case 10252: + return "apollo-relay", true + case 10260: + return "axis-wimp-port", true + case 10261: + return "tile-ml", true + case 10288: + return "blocks", true + case 10321: + return "cosir", true + case 10443: + return "cirrossp", true + case 10540: + return "MOS-lower", true + case 10541: + return "MOS-upper", true + case 10542: + return "MOS-aux", true + case 10543: + return "MOS-soap", true + case 10544: + return "MOS-soap-opt", true + case 10548: + return "serverdocs", true + case 10631: + return "printopia", true + case 10800: + return "gap", true + case 10805: + return "lpdg", true + case 10809: + return "nbd", true + case 10860: + return "helix", true + case 10880: + return "bveapi", true + case 10933: + return "octopustentacle", true + case 10990: + return "rmiaux", true + case 11000: + return "irisa", true + case 11001: + return "metasys", true + case 11095: + return "weave", true + case 11103: + return "origo-sync", true + case 11104: + return "netapp-icmgmt", true + case 11105: + return "netapp-icdata", true + case 11106: + return "sgi-lk", true + case 11109: + return "sgi-dmfmgr", true + case 11110: + return "sgi-soap", true + case 11111: + return "vce", true + case 11112: + return "dicom", true + case 11161: + return "suncacao-snmp", true + case 11162: + return "suncacao-jmxmp", true + case 11163: + return "suncacao-rmi", true + case 11164: + return "suncacao-csa", true + case 11165: + return "suncacao-websvc", true + case 11172: + return "oemcacao-jmxmp", true + case 11173: + return "t5-straton", true + case 11174: + return "oemcacao-rmi", true + case 11175: + return "oemcacao-websvc", true + case 11201: + return "smsqp", true + case 11202: + return "dcsl-backup", true + case 11208: + return "wifree", true + case 11211: + return "memcache", true + case 11235: + return "xcompute", true + case 11319: + return "imip", true + case 11320: + return "imip-channels", true + case 11321: + return "arena-server", true + case 11367: + return "atm-uhas", true + case 11371: + return "hkp", true + case 11489: + return "asgcypresstcps", true + case 11600: + return "tempest-port", true + case 11623: + return "emc-xsw-dconfig", true + case 11720: + return "h323callsigalt", true + case 11723: + return "emc-xsw-dcache", true + case 11751: + return "intrepid-ssl", true + case 11796: + return "lanschool", true + case 11876: + return "xoraya", true + case 11967: + return "sysinfo-sp", true + case 11971: + return "tibsd", true + case 12000: + return "entextxid", true + case 12001: + return "entextnetwk", true + case 12002: + return "entexthigh", true + case 12003: + return "entextmed", true + case 12004: + return "entextlow", true + case 12005: + return "dbisamserver1", true + case 12006: + return "dbisamserver2", true + case 12007: + return "accuracer", true + case 12008: + return "accuracer-dbms", true + case 12010: + return "edbsrvr", true + case 12012: + return "vipera", true + case 12013: + return "vipera-ssl", true + case 12109: + return "rets-ssl", true + case 12121: + return "nupaper-ss", true + case 12168: + return "cawas", true + case 12172: + return "hivep", true + case 12300: + return "linogridengine", true + case 12302: + return "rads", true + case 12321: + return "warehouse-sss", true + case 12322: + return "warehouse", true + case 12345: + return "italk", true + case 12546: + return "carb-repl-ctrl", true + case 12753: + return "tsaf", true + case 12865: + return "netperf", true + case 13160: + return "i-zipqd", true + case 13216: + return "bcslogc", true + case 13217: + return "rs-pias", true + case 13218: + return "emc-vcas-tcp", true + case 13223: + return "powwow-client", true + case 13224: + return "powwow-server", true + case 13400: + return "doip-data", true + case 13720: + return "bprd", true + case 13721: + return "bpdbm", true + case 13722: + return "bpjava-msvc", true + case 13724: + return "vnetd", true + case 13782: + return "bpcd", true + case 13783: + return "vopied", true + case 13785: + return "nbdb", true + case 13786: + return "nomdb", true + case 13818: + return "dsmcc-config", true + case 13819: + return "dsmcc-session", true + case 13820: + return "dsmcc-passthru", true + case 13821: + return "dsmcc-download", true + case 13822: + return "dsmcc-ccp", true + case 13823: + return "bmdss", true + case 13832: + return "a-trust-rpc", true + case 13894: + return "ucontrol", true + case 13929: + return "dta-systems", true + case 13930: + return "medevolve", true + case 14000: + return "scotty-ft", true + case 14001: + return "sua", true + case 14033: + return "sage-best-com1", true + case 14034: + return "sage-best-com2", true + case 14141: + return "vcs-app", true + case 14142: + return "icpp", true + case 14143: + return "icpps", true + case 14145: + return "gcm-app", true + case 14149: + return "vrts-tdd", true + case 14150: + return "vcscmd", true + case 14154: + return "vad", true + case 14250: + return "cps", true + case 14414: + return "ca-web-update", true + case 14500: + return "xpra", true + case 14936: + return "hde-lcesrvr-1", true + case 14937: + return "hde-lcesrvr-2", true + case 15000: + return "hydap", true + case 15002: + return "onep-tls", true + case 15345: + return "xpilot", true + case 15363: + return "3link", true + case 15555: + return "cisco-snat", true + case 15660: + return "bex-xr", true + case 15740: + return "ptp", true + case 15999: + return "programmar", true + case 16000: + return "fmsas", true + case 16001: + return "fmsascon", true + case 16002: + return "gsms", true + case 16020: + return "jwpc", true + case 16021: + return "jwpc-bin", true + case 16161: + return "sun-sea-port", true + case 16162: + return "solaris-audit", true + case 16309: + return "etb4j", true + case 16310: + return "pduncs", true + case 16311: + return "pdefmns", true + case 16360: + return "netserialext1", true + case 16361: + return "netserialext2", true + case 16367: + return "netserialext3", true + case 16368: + return "netserialext4", true + case 16384: + return "connected", true + case 16385: + return "rdgs", true + case 16619: + return "xoms", true + case 16665: + return "axon-tunnel", true + case 16789: + return "cadsisvr", true + case 16900: + return "newbay-snc-mc", true + case 16950: + return "sgcip", true + case 16991: + return "intel-rci-mp", true + case 16992: + return "amt-soap-http", true + case 16993: + return "amt-soap-https", true + case 16994: + return "amt-redir-tcp", true + case 16995: + return "amt-redir-tls", true + case 17007: + return "isode-dua", true + case 17010: + return "ncpu", true + case 17184: + return "vestasdlp", true + case 17185: + return "soundsvirtual", true + case 17219: + return "chipper", true + case 17220: + return "avtp", true + case 17221: + return "avdecc", true + case 17223: + return "isa100-gci", true + case 17225: + return "trdp-md", true + case 17234: + return "integrius-stp", true + case 17235: + return "ssh-mgmt", true + case 17500: + return "db-lsp", true + case 17555: + return "ailith", true + case 17729: + return "ea", true + case 17754: + return "zep", true + case 17755: + return "zigbee-ip", true + case 17756: + return "zigbee-ips", true + case 17777: + return "sw-orion", true + case 18000: + return "biimenu", true + case 18104: + return "radpdf", true + case 18136: + return "racf", true + case 18181: + return "opsec-cvp", true + case 18182: + return "opsec-ufp", true + case 18183: + return "opsec-sam", true + case 18184: + return "opsec-lea", true + case 18185: + return "opsec-omi", true + case 18186: + return "ohsc", true + case 18187: + return "opsec-ela", true + case 18241: + return "checkpoint-rtm", true + case 18242: + return "iclid", true + case 18243: + return "clusterxl", true + case 18262: + return "gv-pf", true + case 18463: + return "ac-cluster", true + case 18634: + return "rds-ib", true + case 18635: + return "rds-ip", true + case 18668: + return "vdmmesh", true + case 18769: + return "ique", true + case 18881: + return "infotos", true + case 18888: + return "apc-necmp", true + case 19000: + return "igrid", true + case 19007: + return "scintilla", true + case 19020: + return "j-link", true + case 19191: + return "opsec-uaa", true + case 19194: + return "ua-secureagent", true + case 19220: + return "cora", true + case 19283: + return "keysrvr", true + case 19315: + return "keyshadow", true + case 19398: + return "mtrgtrans", true + case 19410: + return "hp-sco", true + case 19411: + return "hp-sca", true + case 19412: + return "hp-sessmon", true + case 19539: + return "fxuptp", true + case 19540: + return "sxuptp", true + case 19541: + return "jcp", true + case 19790: + return "faircom-db", true + case 19998: + return "iec-104-sec", true + case 19999: + return "dnp-sec", true + case 20000: + return "dnp", true + case 20001: + return "microsan", true + case 20002: + return "commtact-http", true + case 20003: + return "commtact-https", true + case 20005: + return "openwebnet", true + case 20013: + return "ss-idi", true + case 20014: + return "opendeploy", true + case 20034: + return "nburn-id", true + case 20046: + return "tmophl7mts", true + case 20048: + return "mountd", true + case 20049: + return "nfsrdma", true + case 20057: + return "avesterra", true + case 20167: + return "tolfab", true + case 20202: + return "ipdtp-port", true + case 20222: + return "ipulse-ics", true + case 20480: + return "emwavemsg", true + case 20670: + return "track", true + case 20810: + return "crtech-nlm", true + case 20999: + return "athand-mmp", true + case 21000: + return "irtrans", true + case 21010: + return "notezilla-lan", true + case 21212: + return "trinket-agent", true + case 21213: + return "cohesity-agent", true + case 21221: + return "aigairserver", true + case 21553: + return "rdm-tfs", true + case 21554: + return "dfserver", true + case 21590: + return "vofr-gateway", true + case 21800: + return "tvpm", true + case 21801: + return "sal", true + case 21845: + return "webphone", true + case 21846: + return "netspeak-is", true + case 21847: + return "netspeak-cs", true + case 21848: + return "netspeak-acd", true + case 21849: + return "netspeak-cps", true + case 22000: + return "snapenetio", true + case 22001: + return "optocontrol", true + case 22002: + return "optohost002", true + case 22003: + return "optohost003", true + case 22004: + return "optohost004", true + case 22005: + return "optohost004", true + case 22125: + return "dcap", true + case 22128: + return "gsidcap", true + case 22222: + return "easyengine", true + case 22273: + return "wnn6", true + case 22305: + return "cis", true + case 22333: + return "showcockpit-net", true + case 22335: + return "shrewd-control", true + case 22343: + return "cis-secure", true + case 22347: + return "wibukey", true + case 22350: + return "codemeter", true + case 22351: + return "codemeter-cmwan", true + case 22537: + return "caldsoft-backup", true + case 22555: + return "vocaltec-wconf", true + case 22763: + return "talikaserver", true + case 22800: + return "aws-brf", true + case 22951: + return "brf-gw", true + case 23000: + return "inovaport1", true + case 23001: + return "inovaport2", true + case 23002: + return "inovaport3", true + case 23003: + return "inovaport4", true + case 23004: + return "inovaport5", true + case 23005: + return "inovaport6", true + case 23053: + return "gntp", true + case 23294: + return "5afe-dir", true + case 23333: + return "elxmgmt", true + case 23400: + return "novar-dbase", true + case 23401: + return "novar-alarm", true + case 23402: + return "novar-global", true + case 23456: + return "aequus", true + case 23457: + return "aequus-alt", true + case 23546: + return "areaguard-neo", true + case 24000: + return "med-ltp", true + case 24001: + return "med-fsp-rx", true + case 24002: + return "med-fsp-tx", true + case 24003: + return "med-supp", true + case 24004: + return "med-ovw", true + case 24005: + return "med-ci", true + case 24006: + return "med-net-svc", true + case 24242: + return "filesphere", true + case 24249: + return "vista-4gl", true + case 24321: + return "ild", true + case 24323: + return "vrmg-ip", true + case 24386: + return "intel-rci", true + case 24465: + return "tonidods", true + case 24554: + return "binkp", true + case 24577: + return "bilobit", true + case 24666: + return "sdtvwcam", true + case 24676: + return "canditv", true + case 24677: + return "flashfiler", true + case 24678: + return "proactivate", true + case 24680: + return "tcc-http", true + case 24754: + return "cslg", true + case 24922: + return "find", true + case 25000: + return "icl-twobase1", true + case 25001: + return "icl-twobase2", true + case 25002: + return "icl-twobase3", true + case 25003: + return "icl-twobase4", true + case 25004: + return "icl-twobase5", true + case 25005: + return "icl-twobase6", true + case 25006: + return "icl-twobase7", true + case 25007: + return "icl-twobase8", true + case 25008: + return "icl-twobase9", true + case 25009: + return "icl-twobase10", true + case 25576: + return "sauterdongle", true + case 25604: + return "idtp", true + case 25793: + return "vocaltec-hos", true + case 25900: + return "tasp-net", true + case 25901: + return "niobserver", true + case 25902: + return "nilinkanalyst", true + case 25903: + return "niprobe", true + case 26000: + return "quake", true + case 26133: + return "scscp", true + case 26208: + return "wnn6-ds", true + case 26257: + return "cockroach", true + case 26260: + return "ezproxy", true + case 26261: + return "ezmeeting", true + case 26262: + return "k3software-svr", true + case 26263: + return "k3software-cli", true + case 26486: + return "exoline-tcp", true + case 26487: + return "exoconfig", true + case 26489: + return "exonet", true + case 27010: + return "flex-lmadmin", true + case 27017: + return "mongodb", true + case 27345: + return "imagepump", true + case 27442: + return "jesmsjc", true + case 27504: + return "kopek-httphead", true + case 27782: + return "ars-vista", true + case 27876: + return "astrolink", true + case 27999: + return "tw-auth-key", true + case 28000: + return "nxlmd", true + case 28001: + return "pqsp", true + case 28010: + return "gruber-cashreg", true + case 28080: + return "thor-engine", true + case 28200: + return "voxelstorm", true + case 28240: + return "siemensgsm", true + case 28589: + return "bosswave", true + case 29000: + return "saltd-licensing", true + case 29167: + return "otmp", true + case 29999: + return "bingbang", true + case 30000: + return "ndmps", true + case 30001: + return "pago-services1", true + case 30002: + return "pago-services2", true + case 30003: + return "amicon-fpsu-ra", true + case 30100: + return "rwp", true + case 30260: + return "kingdomsonline", true + case 30400: + return "gs-realtime", true + case 30999: + return "ovobs", true + case 31016: + return "ka-sddp", true + case 31020: + return "autotrac-acp", true + case 31337: + return "eldim", true + case 31400: + return "pace-licensed", true + case 31416: + return "xqosd", true + case 31457: + return "tetrinet", true + case 31620: + return "lm-mon", true + case 31685: + return "dsx-monitor", true + case 31765: + return "gamesmith-port", true + case 31948: + return "iceedcp-tx", true + case 31949: + return "iceedcp-rx", true + case 32034: + return "iracinghelper", true + case 32249: + return "t1distproc60", true + case 32400: + return "plex", true + case 32483: + return "apm-link", true + case 32635: + return "sec-ntb-clnt", true + case 32636: + return "DMExpress", true + case 32767: + return "filenet-powsrm", true + case 32768: + return "filenet-tms", true + case 32769: + return "filenet-rpc", true + case 32770: + return "filenet-nch", true + case 32771: + return "filenet-rmi", true + case 32772: + return "filenet-pa", true + case 32773: + return "filenet-cm", true + case 32774: + return "filenet-re", true + case 32775: + return "filenet-pch", true + case 32776: + return "filenet-peior", true + case 32777: + return "filenet-obrok", true + case 32801: + return "mlsn", true + case 32811: + return "retp", true + case 32896: + return "idmgratm", true + case 33000: + return "wg-endpt-comms", true + case 33060: + return "mysqlx", true + case 33123: + return "aurora-balaena", true + case 33331: + return "diamondport", true + case 33333: + return "dgi-serv", true + case 33334: + return "speedtrace", true + case 33434: + return "traceroute", true + case 33656: + return "snip-slave", true + case 33890: + return "digilent-adept", true + case 34249: + return "turbonote-2", true + case 34378: + return "p-net-local", true + case 34379: + return "p-net-remote", true + case 34567: + return "dhanalakshmi", true + case 34962: + return "profinet-rt", true + case 34963: + return "profinet-rtm", true + case 34964: + return "profinet-cm", true + case 34980: + return "ethercat", true + case 35000: + return "heathview", true + case 35001: + return "rt-viewer", true + case 35002: + return "rt-sound", true + case 35003: + return "rt-devicemapper", true + case 35004: + return "rt-classmanager", true + case 35005: + return "rt-labtracker", true + case 35006: + return "rt-helper", true + case 35100: + return "axio-disc", true + case 35354: + return "kitim", true + case 35355: + return "altova-lm", true + case 35356: + return "guttersnex", true + case 35357: + return "openstack-id", true + case 36001: + return "allpeers", true + case 36524: + return "febooti-aw", true + case 36602: + return "observium-agent", true + case 36700: + return "mapx", true + case 36865: + return "kastenxpipe", true + case 37475: + return "neckar", true + case 37483: + return "gdrive-sync", true + case 37601: + return "eftp", true + case 37654: + return "unisys-eportal", true + case 38000: + return "ivs-database", true + case 38001: + return "ivs-insertion", true + case 38002: + return "cresco-control", true + case 38201: + return "galaxy7-data", true + case 38202: + return "fairview", true + case 38203: + return "agpolicy", true + case 38638: + return "psqlmws", true + case 38800: + return "sruth", true + case 38865: + return "secrmmsafecopya", true + case 39063: + return "vroa", true + case 39681: + return "turbonote-1", true + case 40000: + return "safetynetp", true + case 40404: + return "sptx", true + case 40841: + return "cscp", true + case 40842: + return "csccredir", true + case 40843: + return "csccfirewall", true + case 41111: + return "fs-qos", true + case 41121: + return "tentacle", true + case 41230: + return "z-wave-s", true + case 41794: + return "crestron-cip", true + case 41795: + return "crestron-ctp", true + case 41796: + return "crestron-cips", true + case 41797: + return "crestron-ctps", true + case 42508: + return "candp", true + case 42509: + return "candrp", true + case 42510: + return "caerpc", true + case 42999: + return "curiosity", true + case 43000: + return "recvr-rc", true + case 43188: + return "reachout", true + case 43189: + return "ndm-agent-port", true + case 43190: + return "ip-provision", true + case 43191: + return "noit-transport", true + case 43210: + return "shaperai", true + case 43439: + return "eq3-update", true + case 43440: + return "ew-mgmt", true + case 43441: + return "ciscocsdb", true + case 44123: + return "z-wave-tunnel", true + case 44321: + return "pmcd", true + case 44322: + return "pmcdproxy", true + case 44323: + return "pmwebapi", true + case 44444: + return "cognex-dataman", true + case 44445: + return "acronis-backup", true + case 44553: + return "rbr-debug", true + case 44818: + return "EtherNet-IP-2", true + case 44900: + return "m3da", true + case 45000: + return "asmp", true + case 45001: + return "asmps", true + case 45002: + return "rs-status", true + case 45045: + return "synctest", true + case 45054: + return "invision-ag", true + case 45514: + return "cloudcheck", true + case 45678: + return "eba", true + case 45824: + return "dai-shell", true + case 45825: + return "qdb2service", true + case 45966: + return "ssr-servermgr", true + case 46336: + return "inedo", true + case 46998: + return "spremotetablet", true + case 46999: + return "mediabox", true + case 47000: + return "mbus", true + case 47001: + return "winrm", true + case 47557: + return "dbbrowse", true + case 47624: + return "directplaysrvr", true + case 47806: + return "ap", true + case 47808: + return "bacnet", true + case 48000: + return "nimcontroller", true + case 48001: + return "nimspooler", true + case 48002: + return "nimhub", true + case 48003: + return "nimgtw", true + case 48004: + return "nimbusdb", true + case 48005: + return "nimbusdbctrl", true + case 48048: + return "juka", true + case 48049: + return "3gpp-cbsp", true + case 48050: + return "weandsf", true + case 48128: + return "isnetserv", true + case 48129: + return "blp5", true + case 48556: + return "com-bardac-dw", true + case 48619: + return "iqobject", true + case 48653: + return "robotraconteur", true + case 49000: + return "matahari", true + case 49001: + return "nusrp", true + case 49150: + return "inspider", true + + } + + return "", false +} + +// UDPPortNames contains the port names for all UDP ports. +func UDPPortNames(port UDPPort) (string, bool) { + switch port { + case 1: + return "tcpmux", true + case 2: + return "compressnet", true + case 3: + return "compressnet", true + case 5: + return "rje", true + case 7: + return "echo", true + case 9: + return "discard", true + case 11: + return "systat", true + case 13: + return "daytime", true + case 17: + return "qotd", true + case 18: + return "msp", true + case 19: + return "chargen", true + case 20: + return "ftp-data", true + case 21: + return "ftp", true + case 22: + return "ssh", true + case 23: + return "telnet", true + case 25: + return "smtp", true + case 27: + return "nsw-fe", true + case 29: + return "msg-icp", true + case 31: + return "msg-auth", true + case 33: + return "dsp", true + case 37: + return "time", true + case 38: + return "rap", true + case 39: + return "rlp", true + case 41: + return "graphics", true + case 42: + return "name", true + case 43: + return "nicname", true + case 44: + return "mpm-flags", true + case 45: + return "mpm", true + case 46: + return "mpm-snd", true + case 48: + return "auditd", true + case 49: + return "tacacs", true + case 50: + return "re-mail-ck", true + case 52: + return "xns-time", true + case 53: + return "domain", true + case 54: + return "xns-ch", true + case 55: + return "isi-gl", true + case 56: + return "xns-auth", true + case 58: + return "xns-mail", true + case 62: + return "acas", true + case 63: + return "whoispp", true + case 64: + return "covia", true + case 65: + return "tacacs-ds", true + case 66: + return "sql-net", true + case 67: + return "bootps", true + case 68: + return "bootpc", true + case 69: + return "tftp", true + case 70: + return "gopher", true + case 71: + return "netrjs-1", true + case 72: + return "netrjs-2", true + case 73: + return "netrjs-3", true + case 74: + return "netrjs-4", true + case 76: + return "deos", true + case 78: + return "vettcp", true + case 79: + return "finger", true + case 80: + return "http", true + case 82: + return "xfer", true + case 83: + return "mit-ml-dev", true + case 84: + return "ctf", true + case 85: + return "mit-ml-dev", true + case 86: + return "mfcobol", true + case 88: + return "kerberos", true + case 89: + return "su-mit-tg", true + case 90: + return "dnsix", true + case 91: + return "mit-dov", true + case 92: + return "npp", true + case 93: + return "dcp", true + case 94: + return "objcall", true + case 95: + return "supdup", true + case 96: + return "dixie", true + case 97: + return "swift-rvf", true + case 98: + return "tacnews", true + case 99: + return "metagram", true + case 101: + return "hostname", true + case 102: + return "iso-tsap", true + case 103: + return "gppitnp", true + case 104: + return "acr-nema", true + case 105: + return "cso", true + case 106: + return "3com-tsmux", true + case 107: + return "rtelnet", true + case 108: + return "snagas", true + case 109: + return "pop2", true + case 110: + return "pop3", true + case 111: + return "sunrpc", true + case 112: + return "mcidas", true + case 113: + return "auth", true + case 115: + return "sftp", true + case 116: + return "ansanotify", true + case 117: + return "uucp-path", true + case 118: + return "sqlserv", true + case 119: + return "nntp", true + case 120: + return "cfdptkt", true + case 121: + return "erpc", true + case 122: + return "smakynet", true + case 123: + return "ntp", true + case 124: + return "ansatrader", true + case 125: + return "locus-map", true + case 126: + return "nxedit", true + case 127: + return "locus-con", true + case 128: + return "gss-xlicen", true + case 129: + return "pwdgen", true + case 130: + return "cisco-fna", true + case 131: + return "cisco-tna", true + case 132: + return "cisco-sys", true + case 133: + return "statsrv", true + case 134: + return "ingres-net", true + case 135: + return "epmap", true + case 136: + return "profile", true + case 137: + return "netbios-ns", true + case 138: + return "netbios-dgm", true + case 139: + return "netbios-ssn", true + case 140: + return "emfis-data", true + case 141: + return "emfis-cntl", true + case 142: + return "bl-idm", true + case 144: + return "uma", true + case 145: + return "uaac", true + case 146: + return "iso-tp0", true + case 147: + return "iso-ip", true + case 148: + return "jargon", true + case 149: + return "aed-512", true + case 150: + return "sql-net", true + case 151: + return "hems", true + case 152: + return "bftp", true + case 153: + return "sgmp", true + case 154: + return "netsc-prod", true + case 155: + return "netsc-dev", true + case 156: + return "sqlsrv", true + case 157: + return "knet-cmp", true + case 158: + return "pcmail-srv", true + case 159: + return "nss-routing", true + case 160: + return "sgmp-traps", true + case 161: + return "snmp", true + case 162: + return "snmptrap", true + case 163: + return "cmip-man", true + case 164: + return "cmip-agent", true + case 165: + return "xns-courier", true + case 166: + return "s-net", true + case 167: + return "namp", true + case 168: + return "rsvd", true + case 169: + return "send", true + case 170: + return "print-srv", true + case 171: + return "multiplex", true + case 172: + return "cl-1", true + case 173: + return "xyplex-mux", true + case 174: + return "mailq", true + case 175: + return "vmnet", true + case 176: + return "genrad-mux", true + case 177: + return "xdmcp", true + case 178: + return "nextstep", true + case 179: + return "bgp", true + case 180: + return "ris", true + case 181: + return "unify", true + case 182: + return "audit", true + case 183: + return "ocbinder", true + case 184: + return "ocserver", true + case 185: + return "remote-kis", true + case 186: + return "kis", true + case 187: + return "aci", true + case 188: + return "mumps", true + case 189: + return "qft", true + case 190: + return "gacp", true + case 191: + return "prospero", true + case 192: + return "osu-nms", true + case 193: + return "srmp", true + case 194: + return "irc", true + case 195: + return "dn6-nlm-aud", true + case 196: + return "dn6-smm-red", true + case 197: + return "dls", true + case 198: + return "dls-mon", true + case 199: + return "smux", true + case 200: + return "src", true + case 201: + return "at-rtmp", true + case 202: + return "at-nbp", true + case 203: + return "at-3", true + case 204: + return "at-echo", true + case 205: + return "at-5", true + case 206: + return "at-zis", true + case 207: + return "at-7", true + case 208: + return "at-8", true + case 209: + return "qmtp", true + case 210: + return "z39-50", true + case 211: + return "914c-g", true + case 212: + return "anet", true + case 213: + return "ipx", true + case 214: + return "vmpwscs", true + case 215: + return "softpc", true + case 216: + return "CAIlic", true + case 217: + return "dbase", true + case 218: + return "mpp", true + case 219: + return "uarps", true + case 220: + return "imap3", true + case 221: + return "fln-spx", true + case 222: + return "rsh-spx", true + case 223: + return "cdc", true + case 224: + return "masqdialer", true + case 242: + return "direct", true + case 243: + return "sur-meas", true + case 244: + return "inbusiness", true + case 245: + return "link", true + case 246: + return "dsp3270", true + case 247: + return "subntbcst-tftp", true + case 248: + return "bhfhs", true + case 256: + return "rap", true + case 257: + return "set", true + case 259: + return "esro-gen", true + case 260: + return "openport", true + case 261: + return "nsiiops", true + case 262: + return "arcisdms", true + case 263: + return "hdap", true + case 264: + return "bgmp", true + case 265: + return "x-bone-ctl", true + case 266: + return "sst", true + case 267: + return "td-service", true + case 268: + return "td-replica", true + case 269: + return "manet", true + case 270: + return "gist", true + case 280: + return "http-mgmt", true + case 281: + return "personal-link", true + case 282: + return "cableport-ax", true + case 283: + return "rescap", true + case 284: + return "corerjd", true + case 286: + return "fxp", true + case 287: + return "k-block", true + case 308: + return "novastorbakcup", true + case 309: + return "entrusttime", true + case 310: + return "bhmds", true + case 311: + return "asip-webadmin", true + case 312: + return "vslmp", true + case 313: + return "magenta-logic", true + case 314: + return "opalis-robot", true + case 315: + return "dpsi", true + case 316: + return "decauth", true + case 317: + return "zannet", true + case 318: + return "pkix-timestamp", true + case 319: + return "ptp-event", true + case 320: + return "ptp-general", true + case 321: + return "pip", true + case 322: + return "rtsps", true + case 333: + return "texar", true + case 344: + return "pdap", true + case 345: + return "pawserv", true + case 346: + return "zserv", true + case 347: + return "fatserv", true + case 348: + return "csi-sgwp", true + case 349: + return "mftp", true + case 350: + return "matip-type-a", true + case 351: + return "matip-type-b", true + case 352: + return "dtag-ste-sb", true + case 353: + return "ndsauth", true + case 354: + return "bh611", true + case 355: + return "datex-asn", true + case 356: + return "cloanto-net-1", true + case 357: + return "bhevent", true + case 358: + return "shrinkwrap", true + case 359: + return "nsrmp", true + case 360: + return "scoi2odialog", true + case 361: + return "semantix", true + case 362: + return "srssend", true + case 363: + return "rsvp-tunnel", true + case 364: + return "aurora-cmgr", true + case 365: + return "dtk", true + case 366: + return "odmr", true + case 367: + return "mortgageware", true + case 368: + return "qbikgdp", true + case 369: + return "rpc2portmap", true + case 370: + return "codaauth2", true + case 371: + return "clearcase", true + case 372: + return "ulistproc", true + case 373: + return "legent-1", true + case 374: + return "legent-2", true + case 375: + return "hassle", true + case 376: + return "nip", true + case 377: + return "tnETOS", true + case 378: + return "dsETOS", true + case 379: + return "is99c", true + case 380: + return "is99s", true + case 381: + return "hp-collector", true + case 382: + return "hp-managed-node", true + case 383: + return "hp-alarm-mgr", true + case 384: + return "arns", true + case 385: + return "ibm-app", true + case 386: + return "asa", true + case 387: + return "aurp", true + case 388: + return "unidata-ldm", true + case 389: + return "ldap", true + case 390: + return "uis", true + case 391: + return "synotics-relay", true + case 392: + return "synotics-broker", true + case 393: + return "meta5", true + case 394: + return "embl-ndt", true + case 395: + return "netcp", true + case 396: + return "netware-ip", true + case 397: + return "mptn", true + case 398: + return "kryptolan", true + case 399: + return "iso-tsap-c2", true + case 400: + return "osb-sd", true + case 401: + return "ups", true + case 402: + return "genie", true + case 403: + return "decap", true + case 404: + return "nced", true + case 405: + return "ncld", true + case 406: + return "imsp", true + case 407: + return "timbuktu", true + case 408: + return "prm-sm", true + case 409: + return "prm-nm", true + case 410: + return "decladebug", true + case 411: + return "rmt", true + case 412: + return "synoptics-trap", true + case 413: + return "smsp", true + case 414: + return "infoseek", true + case 415: + return "bnet", true + case 416: + return "silverplatter", true + case 417: + return "onmux", true + case 418: + return "hyper-g", true + case 419: + return "ariel1", true + case 420: + return "smpte", true + case 421: + return "ariel2", true + case 422: + return "ariel3", true + case 423: + return "opc-job-start", true + case 424: + return "opc-job-track", true + case 425: + return "icad-el", true + case 426: + return "smartsdp", true + case 427: + return "svrloc", true + case 428: + return "ocs-cmu", true + case 429: + return "ocs-amu", true + case 430: + return "utmpsd", true + case 431: + return "utmpcd", true + case 432: + return "iasd", true + case 433: + return "nnsp", true + case 434: + return "mobileip-agent", true + case 435: + return "mobilip-mn", true + case 436: + return "dna-cml", true + case 437: + return "comscm", true + case 438: + return "dsfgw", true + case 439: + return "dasp", true + case 440: + return "sgcp", true + case 441: + return "decvms-sysmgt", true + case 442: + return "cvc-hostd", true + case 443: + return "https", true + case 444: + return "snpp", true + case 445: + return "microsoft-ds", true + case 446: + return "ddm-rdb", true + case 447: + return "ddm-dfm", true + case 448: + return "ddm-ssl", true + case 449: + return "as-servermap", true + case 450: + return "tserver", true + case 451: + return "sfs-smp-net", true + case 452: + return "sfs-config", true + case 453: + return "creativeserver", true + case 454: + return "contentserver", true + case 455: + return "creativepartnr", true + case 456: + return "macon-udp", true + case 457: + return "scohelp", true + case 458: + return "appleqtc", true + case 459: + return "ampr-rcmd", true + case 460: + return "skronk", true + case 461: + return "datasurfsrv", true + case 462: + return "datasurfsrvsec", true + case 463: + return "alpes", true + case 464: + return "kpasswd", true + case 465: + return "igmpv3lite", true + case 466: + return "digital-vrc", true + case 467: + return "mylex-mapd", true + case 468: + return "photuris", true + case 469: + return "rcp", true + case 470: + return "scx-proxy", true + case 471: + return "mondex", true + case 472: + return "ljk-login", true + case 473: + return "hybrid-pop", true + case 474: + return "tn-tl-w2", true + case 475: + return "tcpnethaspsrv", true + case 476: + return "tn-tl-fd1", true + case 477: + return "ss7ns", true + case 478: + return "spsc", true + case 479: + return "iafserver", true + case 480: + return "iafdbase", true + case 481: + return "ph", true + case 482: + return "bgs-nsi", true + case 483: + return "ulpnet", true + case 484: + return "integra-sme", true + case 485: + return "powerburst", true + case 486: + return "avian", true + case 487: + return "saft", true + case 488: + return "gss-http", true + case 489: + return "nest-protocol", true + case 490: + return "micom-pfs", true + case 491: + return "go-login", true + case 492: + return "ticf-1", true + case 493: + return "ticf-2", true + case 494: + return "pov-ray", true + case 495: + return "intecourier", true + case 496: + return "pim-rp-disc", true + case 497: + return "retrospect", true + case 498: + return "siam", true + case 499: + return "iso-ill", true + case 500: + return "isakmp", true + case 501: + return "stmf", true + case 502: + return "mbap", true + case 503: + return "intrinsa", true + case 504: + return "citadel", true + case 505: + return "mailbox-lm", true + case 506: + return "ohimsrv", true + case 507: + return "crs", true + case 508: + return "xvttp", true + case 509: + return "snare", true + case 510: + return "fcp", true + case 511: + return "passgo", true + case 512: + return "comsat", true + case 513: + return "who", true + case 514: + return "syslog", true + case 515: + return "printer", true + case 516: + return "videotex", true + case 517: + return "talk", true + case 518: + return "ntalk", true + case 519: + return "utime", true + case 520: + return "router", true + case 521: + return "ripng", true + case 522: + return "ulp", true + case 523: + return "ibm-db2", true + case 524: + return "ncp", true + case 525: + return "timed", true + case 526: + return "tempo", true + case 527: + return "stx", true + case 528: + return "custix", true + case 529: + return "irc-serv", true + case 530: + return "courier", true + case 531: + return "conference", true + case 532: + return "netnews", true + case 533: + return "netwall", true + case 534: + return "windream", true + case 535: + return "iiop", true + case 536: + return "opalis-rdv", true + case 537: + return "nmsp", true + case 538: + return "gdomap", true + case 539: + return "apertus-ldp", true + case 540: + return "uucp", true + case 541: + return "uucp-rlogin", true + case 542: + return "commerce", true + case 543: + return "klogin", true + case 544: + return "kshell", true + case 545: + return "appleqtcsrvr", true + case 546: + return "dhcpv6-client", true + case 547: + return "dhcpv6-server", true + case 548: + return "afpovertcp", true + case 549: + return "idfp", true + case 550: + return "new-rwho", true + case 551: + return "cybercash", true + case 552: + return "devshr-nts", true + case 553: + return "pirp", true + case 554: + return "rtsp", true + case 555: + return "dsf", true + case 556: + return "remotefs", true + case 557: + return "openvms-sysipc", true + case 558: + return "sdnskmp", true + case 559: + return "teedtap", true + case 560: + return "rmonitor", true + case 561: + return "monitor", true + case 562: + return "chshell", true + case 563: + return "nntps", true + case 564: + return "9pfs", true + case 565: + return "whoami", true + case 566: + return "streettalk", true + case 567: + return "banyan-rpc", true + case 568: + return "ms-shuttle", true + case 569: + return "ms-rome", true + case 570: + return "meter", true + case 571: + return "meter", true + case 572: + return "sonar", true + case 573: + return "banyan-vip", true + case 574: + return "ftp-agent", true + case 575: + return "vemmi", true + case 576: + return "ipcd", true + case 577: + return "vnas", true + case 578: + return "ipdd", true + case 579: + return "decbsrv", true + case 580: + return "sntp-heartbeat", true + case 581: + return "bdp", true + case 582: + return "scc-security", true + case 583: + return "philips-vc", true + case 584: + return "keyserver", true + case 586: + return "password-chg", true + case 587: + return "submission", true + case 588: + return "cal", true + case 589: + return "eyelink", true + case 590: + return "tns-cml", true + case 591: + return "http-alt", true + case 592: + return "eudora-set", true + case 593: + return "http-rpc-epmap", true + case 594: + return "tpip", true + case 595: + return "cab-protocol", true + case 596: + return "smsd", true + case 597: + return "ptcnameservice", true + case 598: + return "sco-websrvrmg3", true + case 599: + return "acp", true + case 600: + return "ipcserver", true + case 601: + return "syslog-conn", true + case 602: + return "xmlrpc-beep", true + case 603: + return "idxp", true + case 604: + return "tunnel", true + case 605: + return "soap-beep", true + case 606: + return "urm", true + case 607: + return "nqs", true + case 608: + return "sift-uft", true + case 609: + return "npmp-trap", true + case 610: + return "npmp-local", true + case 611: + return "npmp-gui", true + case 612: + return "hmmp-ind", true + case 613: + return "hmmp-op", true + case 614: + return "sshell", true + case 615: + return "sco-inetmgr", true + case 616: + return "sco-sysmgr", true + case 617: + return "sco-dtmgr", true + case 618: + return "dei-icda", true + case 619: + return "compaq-evm", true + case 620: + return "sco-websrvrmgr", true + case 621: + return "escp-ip", true + case 622: + return "collaborator", true + case 623: + return "asf-rmcp", true + case 624: + return "cryptoadmin", true + case 625: + return "dec-dlm", true + case 626: + return "asia", true + case 627: + return "passgo-tivoli", true + case 628: + return "qmqp", true + case 629: + return "3com-amp3", true + case 630: + return "rda", true + case 631: + return "ipp", true + case 632: + return "bmpp", true + case 633: + return "servstat", true + case 634: + return "ginad", true + case 635: + return "rlzdbase", true + case 636: + return "ldaps", true + case 637: + return "lanserver", true + case 638: + return "mcns-sec", true + case 639: + return "msdp", true + case 640: + return "entrust-sps", true + case 641: + return "repcmd", true + case 642: + return "esro-emsdp", true + case 643: + return "sanity", true + case 644: + return "dwr", true + case 645: + return "pssc", true + case 646: + return "ldp", true + case 647: + return "dhcp-failover", true + case 648: + return "rrp", true + case 649: + return "cadview-3d", true + case 650: + return "obex", true + case 651: + return "ieee-mms", true + case 652: + return "hello-port", true + case 653: + return "repscmd", true + case 654: + return "aodv", true + case 655: + return "tinc", true + case 656: + return "spmp", true + case 657: + return "rmc", true + case 658: + return "tenfold", true + case 660: + return "mac-srvr-admin", true + case 661: + return "hap", true + case 662: + return "pftp", true + case 663: + return "purenoise", true + case 664: + return "asf-secure-rmcp", true + case 665: + return "sun-dr", true + case 666: + return "mdqs", true + case 667: + return "disclose", true + case 668: + return "mecomm", true + case 669: + return "meregister", true + case 670: + return "vacdsm-sws", true + case 671: + return "vacdsm-app", true + case 672: + return "vpps-qua", true + case 673: + return "cimplex", true + case 674: + return "acap", true + case 675: + return "dctp", true + case 676: + return "vpps-via", true + case 677: + return "vpp", true + case 678: + return "ggf-ncp", true + case 679: + return "mrm", true + case 680: + return "entrust-aaas", true + case 681: + return "entrust-aams", true + case 682: + return "xfr", true + case 683: + return "corba-iiop", true + case 684: + return "corba-iiop-ssl", true + case 685: + return "mdc-portmapper", true + case 686: + return "hcp-wismar", true + case 687: + return "asipregistry", true + case 688: + return "realm-rusd", true + case 689: + return "nmap", true + case 690: + return "vatp", true + case 691: + return "msexch-routing", true + case 692: + return "hyperwave-isp", true + case 693: + return "connendp", true + case 694: + return "ha-cluster", true + case 695: + return "ieee-mms-ssl", true + case 696: + return "rushd", true + case 697: + return "uuidgen", true + case 698: + return "olsr", true + case 699: + return "accessnetwork", true + case 700: + return "epp", true + case 701: + return "lmp", true + case 702: + return "iris-beep", true + case 704: + return "elcsd", true + case 705: + return "agentx", true + case 706: + return "silc", true + case 707: + return "borland-dsj", true + case 709: + return "entrust-kmsh", true + case 710: + return "entrust-ash", true + case 711: + return "cisco-tdp", true + case 712: + return "tbrpf", true + case 713: + return "iris-xpc", true + case 714: + return "iris-xpcs", true + case 715: + return "iris-lwz", true + case 716: + return "pana", true + case 729: + return "netviewdm1", true + case 730: + return "netviewdm2", true + case 731: + return "netviewdm3", true + case 741: + return "netgw", true + case 742: + return "netrcs", true + case 744: + return "flexlm", true + case 747: + return "fujitsu-dev", true + case 748: + return "ris-cm", true + case 749: + return "kerberos-adm", true + case 750: + return "loadav", true + case 751: + return "pump", true + case 752: + return "qrh", true + case 753: + return "rrh", true + case 754: + return "tell", true + case 758: + return "nlogin", true + case 759: + return "con", true + case 760: + return "ns", true + case 761: + return "rxe", true + case 762: + return "quotad", true + case 763: + return "cycleserv", true + case 764: + return "omserv", true + case 765: + return "webster", true + case 767: + return "phonebook", true + case 769: + return "vid", true + case 770: + return "cadlock", true + case 771: + return "rtip", true + case 772: + return "cycleserv2", true + case 773: + return "notify", true + case 774: + return "acmaint-dbd", true + case 775: + return "acmaint-transd", true + case 776: + return "wpages", true + case 777: + return "multiling-http", true + case 780: + return "wpgs", true + case 800: + return "mdbs-daemon", true + case 801: + return "device", true + case 802: + return "mbap-s", true + case 810: + return "fcp-udp", true + case 828: + return "itm-mcell-s", true + case 829: + return "pkix-3-ca-ra", true + case 830: + return "netconf-ssh", true + case 831: + return "netconf-beep", true + case 832: + return "netconfsoaphttp", true + case 833: + return "netconfsoapbeep", true + case 847: + return "dhcp-failover2", true + case 848: + return "gdoi", true + case 853: + return "domain-s", true + case 854: + return "dlep", true + case 860: + return "iscsi", true + case 861: + return "owamp-test", true + case 862: + return "twamp-test", true + case 873: + return "rsync", true + case 886: + return "iclcnet-locate", true + case 887: + return "iclcnet-svinfo", true + case 888: + return "accessbuilder", true + case 900: + return "omginitialrefs", true + case 901: + return "smpnameres", true + case 902: + return "ideafarm-door", true + case 903: + return "ideafarm-panic", true + case 910: + return "kink", true + case 911: + return "xact-backup", true + case 912: + return "apex-mesh", true + case 913: + return "apex-edge", true + case 914: + return "rift-lies", true + case 915: + return "rift-ties", true + case 989: + return "ftps-data", true + case 990: + return "ftps", true + case 991: + return "nas", true + case 992: + return "telnets", true + case 995: + return "pop3s", true + case 996: + return "vsinet", true + case 997: + return "maitrd", true + case 998: + return "puparp", true + case 999: + return "applix", true + case 1000: + return "cadlock2", true + case 1010: + return "surf", true + case 1021: + return "exp1", true + case 1022: + return "exp2", true + case 1025: + return "blackjack", true + case 1026: + return "cap", true + case 1027: + return "6a44", true + case 1029: + return "solid-mux", true + case 1033: + return "netinfo-local", true + case 1034: + return "activesync", true + case 1035: + return "mxxrlogin", true + case 1036: + return "nsstp", true + case 1037: + return "ams", true + case 1038: + return "mtqp", true + case 1039: + return "sbl", true + case 1040: + return "netarx", true + case 1041: + return "danf-ak2", true + case 1042: + return "afrog", true + case 1043: + return "boinc-client", true + case 1044: + return "dcutility", true + case 1045: + return "fpitp", true + case 1046: + return "wfremotertm", true + case 1047: + return "neod1", true + case 1048: + return "neod2", true + case 1049: + return "td-postman", true + case 1050: + return "cma", true + case 1051: + return "optima-vnet", true + case 1052: + return "ddt", true + case 1053: + return "remote-as", true + case 1054: + return "brvread", true + case 1055: + return "ansyslmd", true + case 1056: + return "vfo", true + case 1057: + return "startron", true + case 1058: + return "nim", true + case 1059: + return "nimreg", true + case 1060: + return "polestar", true + case 1061: + return "kiosk", true + case 1062: + return "veracity", true + case 1063: + return "kyoceranetdev", true + case 1064: + return "jstel", true + case 1065: + return "syscomlan", true + case 1066: + return "fpo-fns", true + case 1067: + return "instl-boots", true + case 1068: + return "instl-bootc", true + case 1069: + return "cognex-insight", true + case 1070: + return "gmrupdateserv", true + case 1071: + return "bsquare-voip", true + case 1072: + return "cardax", true + case 1073: + return "bridgecontrol", true + case 1074: + return "warmspotMgmt", true + case 1075: + return "rdrmshc", true + case 1076: + return "dab-sti-c", true + case 1077: + return "imgames", true + case 1078: + return "avocent-proxy", true + case 1079: + return "asprovatalk", true + case 1080: + return "socks", true + case 1081: + return "pvuniwien", true + case 1082: + return "amt-esd-prot", true + case 1083: + return "ansoft-lm-1", true + case 1084: + return "ansoft-lm-2", true + case 1085: + return "webobjects", true + case 1086: + return "cplscrambler-lg", true + case 1087: + return "cplscrambler-in", true + case 1088: + return "cplscrambler-al", true + case 1089: + return "ff-annunc", true + case 1090: + return "ff-fms", true + case 1091: + return "ff-sm", true + case 1092: + return "obrpd", true + case 1093: + return "proofd", true + case 1094: + return "rootd", true + case 1095: + return "nicelink", true + case 1096: + return "cnrprotocol", true + case 1097: + return "sunclustermgr", true + case 1098: + return "rmiactivation", true + case 1099: + return "rmiregistry", true + case 1100: + return "mctp", true + case 1101: + return "pt2-discover", true + case 1102: + return "adobeserver-1", true + case 1103: + return "adobeserver-2", true + case 1104: + return "xrl", true + case 1105: + return "ftranhc", true + case 1106: + return "isoipsigport-1", true + case 1107: + return "isoipsigport-2", true + case 1108: + return "ratio-adp", true + case 1110: + return "nfsd-keepalive", true + case 1111: + return "lmsocialserver", true + case 1112: + return "icp", true + case 1113: + return "ltp-deepspace", true + case 1114: + return "mini-sql", true + case 1115: + return "ardus-trns", true + case 1116: + return "ardus-cntl", true + case 1117: + return "ardus-mtrns", true + case 1118: + return "sacred", true + case 1119: + return "bnetgame", true + case 1120: + return "bnetfile", true + case 1121: + return "rmpp", true + case 1122: + return "availant-mgr", true + case 1123: + return "murray", true + case 1124: + return "hpvmmcontrol", true + case 1125: + return "hpvmmagent", true + case 1126: + return "hpvmmdata", true + case 1127: + return "kwdb-commn", true + case 1128: + return "saphostctrl", true + case 1129: + return "saphostctrls", true + case 1130: + return "casp", true + case 1131: + return "caspssl", true + case 1132: + return "kvm-via-ip", true + case 1133: + return "dfn", true + case 1134: + return "aplx", true + case 1135: + return "omnivision", true + case 1136: + return "hhb-gateway", true + case 1137: + return "trim", true + case 1138: + return "encrypted-admin", true + case 1139: + return "evm", true + case 1140: + return "autonoc", true + case 1141: + return "mxomss", true + case 1142: + return "edtools", true + case 1143: + return "imyx", true + case 1144: + return "fuscript", true + case 1145: + return "x9-icue", true + case 1146: + return "audit-transfer", true + case 1147: + return "capioverlan", true + case 1148: + return "elfiq-repl", true + case 1149: + return "bvtsonar", true + case 1150: + return "blaze", true + case 1151: + return "unizensus", true + case 1152: + return "winpoplanmess", true + case 1153: + return "c1222-acse", true + case 1154: + return "resacommunity", true + case 1155: + return "nfa", true + case 1156: + return "iascontrol-oms", true + case 1157: + return "iascontrol", true + case 1158: + return "dbcontrol-oms", true + case 1159: + return "oracle-oms", true + case 1160: + return "olsv", true + case 1161: + return "health-polling", true + case 1162: + return "health-trap", true + case 1163: + return "sddp", true + case 1164: + return "qsm-proxy", true + case 1165: + return "qsm-gui", true + case 1166: + return "qsm-remote", true + case 1167: + return "cisco-ipsla", true + case 1168: + return "vchat", true + case 1169: + return "tripwire", true + case 1170: + return "atc-lm", true + case 1171: + return "atc-appserver", true + case 1172: + return "dnap", true + case 1173: + return "d-cinema-rrp", true + case 1174: + return "fnet-remote-ui", true + case 1175: + return "dossier", true + case 1176: + return "indigo-server", true + case 1177: + return "dkmessenger", true + case 1178: + return "sgi-storman", true + case 1179: + return "b2n", true + case 1180: + return "mc-client", true + case 1181: + return "3comnetman", true + case 1182: + return "accelenet-data", true + case 1183: + return "llsurfup-http", true + case 1184: + return "llsurfup-https", true + case 1185: + return "catchpole", true + case 1186: + return "mysql-cluster", true + case 1187: + return "alias", true + case 1188: + return "hp-webadmin", true + case 1189: + return "unet", true + case 1190: + return "commlinx-avl", true + case 1191: + return "gpfs", true + case 1192: + return "caids-sensor", true + case 1193: + return "fiveacross", true + case 1194: + return "openvpn", true + case 1195: + return "rsf-1", true + case 1196: + return "netmagic", true + case 1197: + return "carrius-rshell", true + case 1198: + return "cajo-discovery", true + case 1199: + return "dmidi", true + case 1200: + return "scol", true + case 1201: + return "nucleus-sand", true + case 1202: + return "caiccipc", true + case 1203: + return "ssslic-mgr", true + case 1204: + return "ssslog-mgr", true + case 1205: + return "accord-mgc", true + case 1206: + return "anthony-data", true + case 1207: + return "metasage", true + case 1208: + return "seagull-ais", true + case 1209: + return "ipcd3", true + case 1210: + return "eoss", true + case 1211: + return "groove-dpp", true + case 1212: + return "lupa", true + case 1213: + return "mpc-lifenet", true + case 1214: + return "kazaa", true + case 1215: + return "scanstat-1", true + case 1216: + return "etebac5", true + case 1217: + return "hpss-ndapi", true + case 1218: + return "aeroflight-ads", true + case 1219: + return "aeroflight-ret", true + case 1220: + return "qt-serveradmin", true + case 1221: + return "sweetware-apps", true + case 1222: + return "nerv", true + case 1223: + return "tgp", true + case 1224: + return "vpnz", true + case 1225: + return "slinkysearch", true + case 1226: + return "stgxfws", true + case 1227: + return "dns2go", true + case 1228: + return "florence", true + case 1229: + return "zented", true + case 1230: + return "periscope", true + case 1231: + return "menandmice-lpm", true + case 1232: + return "first-defense", true + case 1233: + return "univ-appserver", true + case 1234: + return "search-agent", true + case 1235: + return "mosaicsyssvc1", true + case 1236: + return "bvcontrol", true + case 1237: + return "tsdos390", true + case 1238: + return "hacl-qs", true + case 1239: + return "nmsd", true + case 1240: + return "instantia", true + case 1241: + return "nessus", true + case 1242: + return "nmasoverip", true + case 1243: + return "serialgateway", true + case 1244: + return "isbconference1", true + case 1245: + return "isbconference2", true + case 1246: + return "payrouter", true + case 1247: + return "visionpyramid", true + case 1248: + return "hermes", true + case 1249: + return "mesavistaco", true + case 1250: + return "swldy-sias", true + case 1251: + return "servergraph", true + case 1252: + return "bspne-pcc", true + case 1253: + return "q55-pcc", true + case 1254: + return "de-noc", true + case 1255: + return "de-cache-query", true + case 1256: + return "de-server", true + case 1257: + return "shockwave2", true + case 1258: + return "opennl", true + case 1259: + return "opennl-voice", true + case 1260: + return "ibm-ssd", true + case 1261: + return "mpshrsv", true + case 1262: + return "qnts-orb", true + case 1263: + return "dka", true + case 1264: + return "prat", true + case 1265: + return "dssiapi", true + case 1266: + return "dellpwrappks", true + case 1267: + return "epc", true + case 1268: + return "propel-msgsys", true + case 1269: + return "watilapp", true + case 1270: + return "opsmgr", true + case 1271: + return "excw", true + case 1272: + return "cspmlockmgr", true + case 1273: + return "emc-gateway", true + case 1274: + return "t1distproc", true + case 1275: + return "ivcollector", true + case 1277: + return "miva-mqs", true + case 1278: + return "dellwebadmin-1", true + case 1279: + return "dellwebadmin-2", true + case 1280: + return "pictrography", true + case 1281: + return "healthd", true + case 1282: + return "emperion", true + case 1283: + return "productinfo", true + case 1284: + return "iee-qfx", true + case 1285: + return "neoiface", true + case 1286: + return "netuitive", true + case 1287: + return "routematch", true + case 1288: + return "navbuddy", true + case 1289: + return "jwalkserver", true + case 1290: + return "winjaserver", true + case 1291: + return "seagulllms", true + case 1292: + return "dsdn", true + case 1293: + return "pkt-krb-ipsec", true + case 1294: + return "cmmdriver", true + case 1295: + return "ehtp", true + case 1296: + return "dproxy", true + case 1297: + return "sdproxy", true + case 1298: + return "lpcp", true + case 1299: + return "hp-sci", true + case 1300: + return "h323hostcallsc", true + case 1303: + return "sftsrv", true + case 1304: + return "boomerang", true + case 1305: + return "pe-mike", true + case 1306: + return "re-conn-proto", true + case 1307: + return "pacmand", true + case 1308: + return "odsi", true + case 1309: + return "jtag-server", true + case 1310: + return "husky", true + case 1311: + return "rxmon", true + case 1312: + return "sti-envision", true + case 1313: + return "bmc-patroldb", true + case 1314: + return "pdps", true + case 1315: + return "els", true + case 1316: + return "exbit-escp", true + case 1317: + return "vrts-ipcserver", true + case 1318: + return "krb5gatekeeper", true + case 1319: + return "amx-icsp", true + case 1320: + return "amx-axbnet", true + case 1321: + return "pip", true + case 1322: + return "novation", true + case 1323: + return "brcd", true + case 1324: + return "delta-mcp", true + case 1325: + return "dx-instrument", true + case 1326: + return "wimsic", true + case 1327: + return "ultrex", true + case 1328: + return "ewall", true + case 1329: + return "netdb-export", true + case 1330: + return "streetperfect", true + case 1331: + return "intersan", true + case 1332: + return "pcia-rxp-b", true + case 1333: + return "passwrd-policy", true + case 1334: + return "writesrv", true + case 1335: + return "digital-notary", true + case 1336: + return "ischat", true + case 1337: + return "menandmice-dns", true + case 1338: + return "wmc-log-svc", true + case 1339: + return "kjtsiteserver", true + case 1340: + return "naap", true + case 1341: + return "qubes", true + case 1342: + return "esbroker", true + case 1343: + return "re101", true + case 1344: + return "icap", true + case 1345: + return "vpjp", true + case 1346: + return "alta-ana-lm", true + case 1347: + return "bbn-mmc", true + case 1348: + return "bbn-mmx", true + case 1349: + return "sbook", true + case 1350: + return "editbench", true + case 1351: + return "equationbuilder", true + case 1352: + return "lotusnote", true + case 1353: + return "relief", true + case 1354: + return "XSIP-network", true + case 1355: + return "intuitive-edge", true + case 1356: + return "cuillamartin", true + case 1357: + return "pegboard", true + case 1358: + return "connlcli", true + case 1359: + return "ftsrv", true + case 1360: + return "mimer", true + case 1361: + return "linx", true + case 1362: + return "timeflies", true + case 1363: + return "ndm-requester", true + case 1364: + return "ndm-server", true + case 1365: + return "adapt-sna", true + case 1366: + return "netware-csp", true + case 1367: + return "dcs", true + case 1368: + return "screencast", true + case 1369: + return "gv-us", true + case 1370: + return "us-gv", true + case 1371: + return "fc-cli", true + case 1372: + return "fc-ser", true + case 1373: + return "chromagrafx", true + case 1374: + return "molly", true + case 1375: + return "bytex", true + case 1376: + return "ibm-pps", true + case 1377: + return "cichlid", true + case 1378: + return "elan", true + case 1379: + return "dbreporter", true + case 1380: + return "telesis-licman", true + case 1381: + return "apple-licman", true + case 1382: + return "udt-os", true + case 1383: + return "gwha", true + case 1384: + return "os-licman", true + case 1385: + return "atex-elmd", true + case 1386: + return "checksum", true + case 1387: + return "cadsi-lm", true + case 1388: + return "objective-dbc", true + case 1389: + return "iclpv-dm", true + case 1390: + return "iclpv-sc", true + case 1391: + return "iclpv-sas", true + case 1392: + return "iclpv-pm", true + case 1393: + return "iclpv-nls", true + case 1394: + return "iclpv-nlc", true + case 1395: + return "iclpv-wsm", true + case 1396: + return "dvl-activemail", true + case 1397: + return "audio-activmail", true + case 1398: + return "video-activmail", true + case 1399: + return "cadkey-licman", true + case 1400: + return "cadkey-tablet", true + case 1401: + return "goldleaf-licman", true + case 1402: + return "prm-sm-np", true + case 1403: + return "prm-nm-np", true + case 1404: + return "igi-lm", true + case 1405: + return "ibm-res", true + case 1406: + return "netlabs-lm", true + case 1408: + return "sophia-lm", true + case 1409: + return "here-lm", true + case 1410: + return "hiq", true + case 1411: + return "af", true + case 1412: + return "innosys", true + case 1413: + return "innosys-acl", true + case 1414: + return "ibm-mqseries", true + case 1415: + return "dbstar", true + case 1416: + return "novell-lu6-2", true + case 1417: + return "timbuktu-srv1", true + case 1418: + return "timbuktu-srv2", true + case 1419: + return "timbuktu-srv3", true + case 1420: + return "timbuktu-srv4", true + case 1421: + return "gandalf-lm", true + case 1422: + return "autodesk-lm", true + case 1423: + return "essbase", true + case 1424: + return "hybrid", true + case 1425: + return "zion-lm", true + case 1426: + return "sais", true + case 1427: + return "mloadd", true + case 1428: + return "informatik-lm", true + case 1429: + return "nms", true + case 1430: + return "tpdu", true + case 1431: + return "rgtp", true + case 1432: + return "blueberry-lm", true + case 1433: + return "ms-sql-s", true + case 1434: + return "ms-sql-m", true + case 1435: + return "ibm-cics", true + case 1436: + return "saism", true + case 1437: + return "tabula", true + case 1438: + return "eicon-server", true + case 1439: + return "eicon-x25", true + case 1440: + return "eicon-slp", true + case 1441: + return "cadis-1", true + case 1442: + return "cadis-2", true + case 1443: + return "ies-lm", true + case 1444: + return "marcam-lm", true + case 1445: + return "proxima-lm", true + case 1446: + return "ora-lm", true + case 1447: + return "apri-lm", true + case 1448: + return "oc-lm", true + case 1449: + return "peport", true + case 1450: + return "dwf", true + case 1451: + return "infoman", true + case 1452: + return "gtegsc-lm", true + case 1453: + return "genie-lm", true + case 1454: + return "interhdl-elmd", true + case 1455: + return "esl-lm", true + case 1456: + return "dca", true + case 1457: + return "valisys-lm", true + case 1458: + return "nrcabq-lm", true + case 1459: + return "proshare1", true + case 1460: + return "proshare2", true + case 1461: + return "ibm-wrless-lan", true + case 1462: + return "world-lm", true + case 1463: + return "nucleus", true + case 1464: + return "msl-lmd", true + case 1465: + return "pipes", true + case 1466: + return "oceansoft-lm", true + case 1467: + return "csdmbase", true + case 1468: + return "csdm", true + case 1469: + return "aal-lm", true + case 1470: + return "uaiact", true + case 1471: + return "csdmbase", true + case 1472: + return "csdm", true + case 1473: + return "openmath", true + case 1474: + return "telefinder", true + case 1475: + return "taligent-lm", true + case 1476: + return "clvm-cfg", true + case 1477: + return "ms-sna-server", true + case 1478: + return "ms-sna-base", true + case 1479: + return "dberegister", true + case 1480: + return "pacerforum", true + case 1481: + return "airs", true + case 1482: + return "miteksys-lm", true + case 1483: + return "afs", true + case 1484: + return "confluent", true + case 1485: + return "lansource", true + case 1486: + return "nms-topo-serv", true + case 1487: + return "localinfosrvr", true + case 1488: + return "docstor", true + case 1489: + return "dmdocbroker", true + case 1490: + return "insitu-conf", true + case 1492: + return "stone-design-1", true + case 1493: + return "netmap-lm", true + case 1494: + return "ica", true + case 1495: + return "cvc", true + case 1496: + return "liberty-lm", true + case 1497: + return "rfx-lm", true + case 1498: + return "sybase-sqlany", true + case 1499: + return "fhc", true + case 1500: + return "vlsi-lm", true + case 1501: + return "saiscm", true + case 1502: + return "shivadiscovery", true + case 1503: + return "imtc-mcs", true + case 1504: + return "evb-elm", true + case 1505: + return "funkproxy", true + case 1506: + return "utcd", true + case 1507: + return "symplex", true + case 1508: + return "diagmond", true + case 1509: + return "robcad-lm", true + case 1510: + return "mvx-lm", true + case 1511: + return "3l-l1", true + case 1512: + return "wins", true + case 1513: + return "fujitsu-dtc", true + case 1514: + return "fujitsu-dtcns", true + case 1515: + return "ifor-protocol", true + case 1516: + return "vpad", true + case 1517: + return "vpac", true + case 1518: + return "vpvd", true + case 1519: + return "vpvc", true + case 1520: + return "atm-zip-office", true + case 1521: + return "ncube-lm", true + case 1522: + return "ricardo-lm", true + case 1523: + return "cichild-lm", true + case 1524: + return "ingreslock", true + case 1525: + return "orasrv", true + case 1526: + return "pdap-np", true + case 1527: + return "tlisrv", true + case 1528: + return "norp", true + case 1529: + return "coauthor", true + case 1530: + return "rap-service", true + case 1531: + return "rap-listen", true + case 1532: + return "miroconnect", true + case 1533: + return "virtual-places", true + case 1534: + return "micromuse-lm", true + case 1535: + return "ampr-info", true + case 1536: + return "ampr-inter", true + case 1537: + return "sdsc-lm", true + case 1538: + return "3ds-lm", true + case 1539: + return "intellistor-lm", true + case 1540: + return "rds", true + case 1541: + return "rds2", true + case 1542: + return "gridgen-elmd", true + case 1543: + return "simba-cs", true + case 1544: + return "aspeclmd", true + case 1545: + return "vistium-share", true + case 1546: + return "abbaccuray", true + case 1547: + return "laplink", true + case 1548: + return "axon-lm", true + case 1549: + return "shivasound", true + case 1550: + return "3m-image-lm", true + case 1551: + return "hecmtl-db", true + case 1552: + return "pciarray", true + case 1553: + return "sna-cs", true + case 1554: + return "caci-lm", true + case 1555: + return "livelan", true + case 1556: + return "veritas-pbx", true + case 1557: + return "arbortext-lm", true + case 1558: + return "xingmpeg", true + case 1559: + return "web2host", true + case 1560: + return "asci-val", true + case 1561: + return "facilityview", true + case 1562: + return "pconnectmgr", true + case 1563: + return "cadabra-lm", true + case 1564: + return "pay-per-view", true + case 1565: + return "winddlb", true + case 1566: + return "corelvideo", true + case 1567: + return "jlicelmd", true + case 1568: + return "tsspmap", true + case 1569: + return "ets", true + case 1570: + return "orbixd", true + case 1571: + return "rdb-dbs-disp", true + case 1572: + return "chip-lm", true + case 1573: + return "itscomm-ns", true + case 1574: + return "mvel-lm", true + case 1575: + return "oraclenames", true + case 1576: + return "moldflow-lm", true + case 1577: + return "hypercube-lm", true + case 1578: + return "jacobus-lm", true + case 1579: + return "ioc-sea-lm", true + case 1580: + return "tn-tl-r2", true + case 1581: + return "mil-2045-47001", true + case 1582: + return "msims", true + case 1583: + return "simbaexpress", true + case 1584: + return "tn-tl-fd2", true + case 1585: + return "intv", true + case 1586: + return "ibm-abtact", true + case 1587: + return "pra-elmd", true + case 1588: + return "triquest-lm", true + case 1589: + return "vqp", true + case 1590: + return "gemini-lm", true + case 1591: + return "ncpm-pm", true + case 1592: + return "commonspace", true + case 1593: + return "mainsoft-lm", true + case 1594: + return "sixtrak", true + case 1595: + return "radio", true + case 1596: + return "radio-bc", true + case 1597: + return "orbplus-iiop", true + case 1598: + return "picknfs", true + case 1599: + return "simbaservices", true + case 1600: + return "issd", true + case 1601: + return "aas", true + case 1602: + return "inspect", true + case 1603: + return "picodbc", true + case 1604: + return "icabrowser", true + case 1605: + return "slp", true + case 1606: + return "slm-api", true + case 1607: + return "stt", true + case 1608: + return "smart-lm", true + case 1609: + return "isysg-lm", true + case 1610: + return "taurus-wh", true + case 1611: + return "ill", true + case 1612: + return "netbill-trans", true + case 1613: + return "netbill-keyrep", true + case 1614: + return "netbill-cred", true + case 1615: + return "netbill-auth", true + case 1616: + return "netbill-prod", true + case 1617: + return "nimrod-agent", true + case 1618: + return "skytelnet", true + case 1619: + return "xs-openstorage", true + case 1620: + return "faxportwinport", true + case 1621: + return "softdataphone", true + case 1622: + return "ontime", true + case 1623: + return "jaleosnd", true + case 1624: + return "udp-sr-port", true + case 1625: + return "svs-omagent", true + case 1626: + return "shockwave", true + case 1627: + return "t128-gateway", true + case 1628: + return "lontalk-norm", true + case 1629: + return "lontalk-urgnt", true + case 1630: + return "oraclenet8cman", true + case 1631: + return "visitview", true + case 1632: + return "pammratc", true + case 1633: + return "pammrpc", true + case 1634: + return "loaprobe", true + case 1635: + return "edb-server1", true + case 1636: + return "isdc", true + case 1637: + return "islc", true + case 1638: + return "ismc", true + case 1639: + return "cert-initiator", true + case 1640: + return "cert-responder", true + case 1641: + return "invision", true + case 1642: + return "isis-am", true + case 1643: + return "isis-ambc", true + case 1644: + return "saiseh", true + case 1645: + return "sightline", true + case 1646: + return "sa-msg-port", true + case 1647: + return "rsap", true + case 1648: + return "concurrent-lm", true + case 1649: + return "kermit", true + case 1650: + return "nkd", true + case 1651: + return "shiva-confsrvr", true + case 1652: + return "xnmp", true + case 1653: + return "alphatech-lm", true + case 1654: + return "stargatealerts", true + case 1655: + return "dec-mbadmin", true + case 1656: + return "dec-mbadmin-h", true + case 1657: + return "fujitsu-mmpdc", true + case 1658: + return "sixnetudr", true + case 1659: + return "sg-lm", true + case 1660: + return "skip-mc-gikreq", true + case 1661: + return "netview-aix-1", true + case 1662: + return "netview-aix-2", true + case 1663: + return "netview-aix-3", true + case 1664: + return "netview-aix-4", true + case 1665: + return "netview-aix-5", true + case 1666: + return "netview-aix-6", true + case 1667: + return "netview-aix-7", true + case 1668: + return "netview-aix-8", true + case 1669: + return "netview-aix-9", true + case 1670: + return "netview-aix-10", true + case 1671: + return "netview-aix-11", true + case 1672: + return "netview-aix-12", true + case 1673: + return "proshare-mc-1", true + case 1674: + return "proshare-mc-2", true + case 1675: + return "pdp", true + case 1676: + return "netcomm2", true + case 1677: + return "groupwise", true + case 1678: + return "prolink", true + case 1679: + return "darcorp-lm", true + case 1680: + return "microcom-sbp", true + case 1681: + return "sd-elmd", true + case 1682: + return "lanyon-lantern", true + case 1683: + return "ncpm-hip", true + case 1684: + return "snaresecure", true + case 1685: + return "n2nremote", true + case 1686: + return "cvmon", true + case 1687: + return "nsjtp-ctrl", true + case 1688: + return "nsjtp-data", true + case 1689: + return "firefox", true + case 1690: + return "ng-umds", true + case 1691: + return "empire-empuma", true + case 1692: + return "sstsys-lm", true + case 1693: + return "rrirtr", true + case 1694: + return "rrimwm", true + case 1695: + return "rrilwm", true + case 1696: + return "rrifmm", true + case 1697: + return "rrisat", true + case 1698: + return "rsvp-encap-1", true + case 1699: + return "rsvp-encap-2", true + case 1700: + return "mps-raft", true + case 1701: + return "l2f", true + case 1702: + return "deskshare", true + case 1703: + return "hb-engine", true + case 1704: + return "bcs-broker", true + case 1705: + return "slingshot", true + case 1706: + return "jetform", true + case 1707: + return "vdmplay", true + case 1708: + return "gat-lmd", true + case 1709: + return "centra", true + case 1710: + return "impera", true + case 1711: + return "pptconference", true + case 1712: + return "registrar", true + case 1713: + return "conferencetalk", true + case 1714: + return "sesi-lm", true + case 1715: + return "houdini-lm", true + case 1716: + return "xmsg", true + case 1717: + return "fj-hdnet", true + case 1718: + return "h323gatedisc", true + case 1719: + return "h323gatestat", true + case 1720: + return "h323hostcall", true + case 1721: + return "caicci", true + case 1722: + return "hks-lm", true + case 1723: + return "pptp", true + case 1724: + return "csbphonemaster", true + case 1725: + return "iden-ralp", true + case 1726: + return "iberiagames", true + case 1727: + return "winddx", true + case 1728: + return "telindus", true + case 1729: + return "citynl", true + case 1730: + return "roketz", true + case 1731: + return "msiccp", true + case 1732: + return "proxim", true + case 1733: + return "siipat", true + case 1734: + return "cambertx-lm", true + case 1735: + return "privatechat", true + case 1736: + return "street-stream", true + case 1737: + return "ultimad", true + case 1738: + return "gamegen1", true + case 1739: + return "webaccess", true + case 1740: + return "encore", true + case 1741: + return "cisco-net-mgmt", true + case 1742: + return "3Com-nsd", true + case 1743: + return "cinegrfx-lm", true + case 1744: + return "ncpm-ft", true + case 1745: + return "remote-winsock", true + case 1746: + return "ftrapid-1", true + case 1747: + return "ftrapid-2", true + case 1748: + return "oracle-em1", true + case 1749: + return "aspen-services", true + case 1750: + return "sslp", true + case 1751: + return "swiftnet", true + case 1752: + return "lofr-lm", true + case 1754: + return "oracle-em2", true + case 1755: + return "ms-streaming", true + case 1756: + return "capfast-lmd", true + case 1757: + return "cnhrp", true + case 1758: + return "tftp-mcast", true + case 1759: + return "spss-lm", true + case 1760: + return "www-ldap-gw", true + case 1761: + return "cft-0", true + case 1762: + return "cft-1", true + case 1763: + return "cft-2", true + case 1764: + return "cft-3", true + case 1765: + return "cft-4", true + case 1766: + return "cft-5", true + case 1767: + return "cft-6", true + case 1768: + return "cft-7", true + case 1769: + return "bmc-net-adm", true + case 1770: + return "bmc-net-svc", true + case 1771: + return "vaultbase", true + case 1772: + return "essweb-gw", true + case 1773: + return "kmscontrol", true + case 1774: + return "global-dtserv", true + case 1776: + return "femis", true + case 1777: + return "powerguardian", true + case 1778: + return "prodigy-intrnet", true + case 1779: + return "pharmasoft", true + case 1780: + return "dpkeyserv", true + case 1781: + return "answersoft-lm", true + case 1782: + return "hp-hcip", true + case 1784: + return "finle-lm", true + case 1785: + return "windlm", true + case 1786: + return "funk-logger", true + case 1787: + return "funk-license", true + case 1788: + return "psmond", true + case 1789: + return "hello", true + case 1790: + return "nmsp", true + case 1791: + return "ea1", true + case 1792: + return "ibm-dt-2", true + case 1793: + return "rsc-robot", true + case 1794: + return "cera-bcm", true + case 1795: + return "dpi-proxy", true + case 1796: + return "vocaltec-admin", true + case 1797: + return "uma", true + case 1798: + return "etp", true + case 1799: + return "netrisk", true + case 1800: + return "ansys-lm", true + case 1801: + return "msmq", true + case 1802: + return "concomp1", true + case 1803: + return "hp-hcip-gwy", true + case 1804: + return "enl", true + case 1805: + return "enl-name", true + case 1806: + return "musiconline", true + case 1807: + return "fhsp", true + case 1808: + return "oracle-vp2", true + case 1809: + return "oracle-vp1", true + case 1810: + return "jerand-lm", true + case 1811: + return "scientia-sdb", true + case 1812: + return "radius", true + case 1813: + return "radius-acct", true + case 1814: + return "tdp-suite", true + case 1815: + return "mmpft", true + case 1816: + return "harp", true + case 1817: + return "rkb-oscs", true + case 1818: + return "etftp", true + case 1819: + return "plato-lm", true + case 1820: + return "mcagent", true + case 1821: + return "donnyworld", true + case 1822: + return "es-elmd", true + case 1823: + return "unisys-lm", true + case 1824: + return "metrics-pas", true + case 1825: + return "direcpc-video", true + case 1826: + return "ardt", true + case 1827: + return "asi", true + case 1828: + return "itm-mcell-u", true + case 1829: + return "optika-emedia", true + case 1830: + return "net8-cman", true + case 1831: + return "myrtle", true + case 1832: + return "tht-treasure", true + case 1833: + return "udpradio", true + case 1834: + return "ardusuni", true + case 1835: + return "ardusmul", true + case 1836: + return "ste-smsc", true + case 1837: + return "csoft1", true + case 1838: + return "talnet", true + case 1839: + return "netopia-vo1", true + case 1840: + return "netopia-vo2", true + case 1841: + return "netopia-vo3", true + case 1842: + return "netopia-vo4", true + case 1843: + return "netopia-vo5", true + case 1844: + return "direcpc-dll", true + case 1845: + return "altalink", true + case 1846: + return "tunstall-pnc", true + case 1847: + return "slp-notify", true + case 1848: + return "fjdocdist", true + case 1849: + return "alpha-sms", true + case 1850: + return "gsi", true + case 1851: + return "ctcd", true + case 1852: + return "virtual-time", true + case 1853: + return "vids-avtp", true + case 1854: + return "buddy-draw", true + case 1855: + return "fiorano-rtrsvc", true + case 1856: + return "fiorano-msgsvc", true + case 1857: + return "datacaptor", true + case 1858: + return "privateark", true + case 1859: + return "gammafetchsvr", true + case 1860: + return "sunscalar-svc", true + case 1861: + return "lecroy-vicp", true + case 1862: + return "mysql-cm-agent", true + case 1863: + return "msnp", true + case 1864: + return "paradym-31port", true + case 1865: + return "entp", true + case 1866: + return "swrmi", true + case 1867: + return "udrive", true + case 1868: + return "viziblebrowser", true + case 1869: + return "transact", true + case 1870: + return "sunscalar-dns", true + case 1871: + return "canocentral0", true + case 1872: + return "canocentral1", true + case 1873: + return "fjmpjps", true + case 1874: + return "fjswapsnp", true + case 1875: + return "westell-stats", true + case 1876: + return "ewcappsrv", true + case 1877: + return "hp-webqosdb", true + case 1878: + return "drmsmc", true + case 1879: + return "nettgain-nms", true + case 1880: + return "vsat-control", true + case 1881: + return "ibm-mqseries2", true + case 1882: + return "ecsqdmn", true + case 1883: + return "mqtt", true + case 1884: + return "idmaps", true + case 1885: + return "vrtstrapserver", true + case 1886: + return "leoip", true + case 1887: + return "filex-lport", true + case 1888: + return "ncconfig", true + case 1889: + return "unify-adapter", true + case 1890: + return "wilkenlistener", true + case 1891: + return "childkey-notif", true + case 1892: + return "childkey-ctrl", true + case 1893: + return "elad", true + case 1894: + return "o2server-port", true + case 1896: + return "b-novative-ls", true + case 1897: + return "metaagent", true + case 1898: + return "cymtec-port", true + case 1899: + return "mc2studios", true + case 1900: + return "ssdp", true + case 1901: + return "fjicl-tep-a", true + case 1902: + return "fjicl-tep-b", true + case 1903: + return "linkname", true + case 1904: + return "fjicl-tep-c", true + case 1905: + return "sugp", true + case 1906: + return "tpmd", true + case 1907: + return "intrastar", true + case 1908: + return "dawn", true + case 1909: + return "global-wlink", true + case 1910: + return "ultrabac", true + case 1911: + return "mtp", true + case 1912: + return "rhp-iibp", true + case 1913: + return "armadp", true + case 1914: + return "elm-momentum", true + case 1915: + return "facelink", true + case 1916: + return "persona", true + case 1917: + return "noagent", true + case 1918: + return "can-nds", true + case 1919: + return "can-dch", true + case 1920: + return "can-ferret", true + case 1921: + return "noadmin", true + case 1922: + return "tapestry", true + case 1923: + return "spice", true + case 1924: + return "xiip", true + case 1925: + return "discovery-port", true + case 1926: + return "egs", true + case 1927: + return "videte-cipc", true + case 1928: + return "emsd-port", true + case 1929: + return "bandwiz-system", true + case 1930: + return "driveappserver", true + case 1931: + return "amdsched", true + case 1932: + return "ctt-broker", true + case 1933: + return "xmapi", true + case 1934: + return "xaapi", true + case 1935: + return "macromedia-fcs", true + case 1936: + return "jetcmeserver", true + case 1937: + return "jwserver", true + case 1938: + return "jwclient", true + case 1939: + return "jvserver", true + case 1940: + return "jvclient", true + case 1941: + return "dic-aida", true + case 1942: + return "res", true + case 1943: + return "beeyond-media", true + case 1944: + return "close-combat", true + case 1945: + return "dialogic-elmd", true + case 1946: + return "tekpls", true + case 1947: + return "sentinelsrm", true + case 1948: + return "eye2eye", true + case 1949: + return "ismaeasdaqlive", true + case 1950: + return "ismaeasdaqtest", true + case 1951: + return "bcs-lmserver", true + case 1952: + return "mpnjsc", true + case 1953: + return "rapidbase", true + case 1954: + return "abr-api", true + case 1955: + return "abr-secure", true + case 1956: + return "vrtl-vmf-ds", true + case 1957: + return "unix-status", true + case 1958: + return "dxadmind", true + case 1959: + return "simp-all", true + case 1960: + return "nasmanager", true + case 1961: + return "bts-appserver", true + case 1962: + return "biap-mp", true + case 1963: + return "webmachine", true + case 1964: + return "solid-e-engine", true + case 1965: + return "tivoli-npm", true + case 1966: + return "slush", true + case 1967: + return "sns-quote", true + case 1968: + return "lipsinc", true + case 1969: + return "lipsinc1", true + case 1970: + return "netop-rc", true + case 1971: + return "netop-school", true + case 1972: + return "intersys-cache", true + case 1973: + return "dlsrap", true + case 1974: + return "drp", true + case 1975: + return "tcoflashagent", true + case 1976: + return "tcoregagent", true + case 1977: + return "tcoaddressbook", true + case 1978: + return "unisql", true + case 1979: + return "unisql-java", true + case 1980: + return "pearldoc-xact", true + case 1981: + return "p2pq", true + case 1982: + return "estamp", true + case 1983: + return "lhtp", true + case 1984: + return "bb", true + case 1985: + return "hsrp", true + case 1986: + return "licensedaemon", true + case 1987: + return "tr-rsrb-p1", true + case 1988: + return "tr-rsrb-p2", true + case 1989: + return "tr-rsrb-p3", true + case 1990: + return "stun-p1", true + case 1991: + return "stun-p2", true + case 1992: + return "stun-p3", true + case 1993: + return "snmp-tcp-port", true + case 1994: + return "stun-port", true + case 1995: + return "perf-port", true + case 1996: + return "tr-rsrb-port", true + case 1997: + return "gdp-port", true + case 1998: + return "x25-svc-port", true + case 1999: + return "tcp-id-port", true + case 2000: + return "cisco-sccp", true + case 2001: + return "wizard", true + case 2002: + return "globe", true + case 2003: + return "brutus", true + case 2004: + return "emce", true + case 2005: + return "oracle", true + case 2006: + return "raid-cd", true + case 2007: + return "raid-am", true + case 2008: + return "terminaldb", true + case 2009: + return "whosockami", true + case 2010: + return "pipe-server", true + case 2011: + return "servserv", true + case 2012: + return "raid-ac", true + case 2013: + return "raid-cd", true + case 2014: + return "raid-sf", true + case 2015: + return "raid-cs", true + case 2016: + return "bootserver", true + case 2017: + return "bootclient", true + case 2018: + return "rellpack", true + case 2019: + return "about", true + case 2020: + return "xinupageserver", true + case 2021: + return "xinuexpansion1", true + case 2022: + return "xinuexpansion2", true + case 2023: + return "xinuexpansion3", true + case 2024: + return "xinuexpansion4", true + case 2025: + return "xribs", true + case 2026: + return "scrabble", true + case 2027: + return "shadowserver", true + case 2028: + return "submitserver", true + case 2029: + return "hsrpv6", true + case 2030: + return "device2", true + case 2031: + return "mobrien-chat", true + case 2032: + return "blackboard", true + case 2033: + return "glogger", true + case 2034: + return "scoremgr", true + case 2035: + return "imsldoc", true + case 2036: + return "e-dpnet", true + case 2037: + return "applus", true + case 2038: + return "objectmanager", true + case 2039: + return "prizma", true + case 2040: + return "lam", true + case 2041: + return "interbase", true + case 2042: + return "isis", true + case 2043: + return "isis-bcast", true + case 2044: + return "rimsl", true + case 2045: + return "cdfunc", true + case 2046: + return "sdfunc", true + case 2047: + return "dls", true + case 2048: + return "dls-monitor", true + case 2049: + return "shilp", true + case 2050: + return "av-emb-config", true + case 2051: + return "epnsdp", true + case 2052: + return "clearvisn", true + case 2053: + return "lot105-ds-upd", true + case 2054: + return "weblogin", true + case 2055: + return "iop", true + case 2056: + return "omnisky", true + case 2057: + return "rich-cp", true + case 2058: + return "newwavesearch", true + case 2059: + return "bmc-messaging", true + case 2060: + return "teleniumdaemon", true + case 2061: + return "netmount", true + case 2062: + return "icg-swp", true + case 2063: + return "icg-bridge", true + case 2064: + return "icg-iprelay", true + case 2065: + return "dlsrpn", true + case 2066: + return "aura", true + case 2067: + return "dlswpn", true + case 2068: + return "avauthsrvprtcl", true + case 2069: + return "event-port", true + case 2070: + return "ah-esp-encap", true + case 2071: + return "acp-port", true + case 2072: + return "msync", true + case 2073: + return "gxs-data-port", true + case 2074: + return "vrtl-vmf-sa", true + case 2075: + return "newlixengine", true + case 2076: + return "newlixconfig", true + case 2077: + return "tsrmagt", true + case 2078: + return "tpcsrvr", true + case 2079: + return "idware-router", true + case 2080: + return "autodesk-nlm", true + case 2081: + return "kme-trap-port", true + case 2082: + return "infowave", true + case 2083: + return "radsec", true + case 2084: + return "sunclustergeo", true + case 2085: + return "ada-cip", true + case 2086: + return "gnunet", true + case 2087: + return "eli", true + case 2088: + return "ip-blf", true + case 2089: + return "sep", true + case 2090: + return "lrp", true + case 2091: + return "prp", true + case 2092: + return "descent3", true + case 2093: + return "nbx-cc", true + case 2094: + return "nbx-au", true + case 2095: + return "nbx-ser", true + case 2096: + return "nbx-dir", true + case 2097: + return "jetformpreview", true + case 2098: + return "dialog-port", true + case 2099: + return "h2250-annex-g", true + case 2100: + return "amiganetfs", true + case 2101: + return "rtcm-sc104", true + case 2102: + return "zephyr-srv", true + case 2103: + return "zephyr-clt", true + case 2104: + return "zephyr-hm", true + case 2105: + return "minipay", true + case 2106: + return "mzap", true + case 2107: + return "bintec-admin", true + case 2108: + return "comcam", true + case 2109: + return "ergolight", true + case 2110: + return "umsp", true + case 2111: + return "dsatp", true + case 2112: + return "idonix-metanet", true + case 2113: + return "hsl-storm", true + case 2114: + return "ariascribe", true + case 2115: + return "kdm", true + case 2116: + return "ccowcmr", true + case 2117: + return "mentaclient", true + case 2118: + return "mentaserver", true + case 2119: + return "gsigatekeeper", true + case 2120: + return "qencp", true + case 2121: + return "scientia-ssdb", true + case 2122: + return "caupc-remote", true + case 2123: + return "gtp-control", true + case 2124: + return "elatelink", true + case 2125: + return "lockstep", true + case 2126: + return "pktcable-cops", true + case 2127: + return "index-pc-wb", true + case 2128: + return "net-steward", true + case 2129: + return "cs-live", true + case 2130: + return "xds", true + case 2131: + return "avantageb2b", true + case 2132: + return "solera-epmap", true + case 2133: + return "zymed-zpp", true + case 2134: + return "avenue", true + case 2135: + return "gris", true + case 2136: + return "appworxsrv", true + case 2137: + return "connect", true + case 2138: + return "unbind-cluster", true + case 2139: + return "ias-auth", true + case 2140: + return "ias-reg", true + case 2141: + return "ias-admind", true + case 2142: + return "tdmoip", true + case 2143: + return "lv-jc", true + case 2144: + return "lv-ffx", true + case 2145: + return "lv-pici", true + case 2146: + return "lv-not", true + case 2147: + return "lv-auth", true + case 2148: + return "veritas-ucl", true + case 2149: + return "acptsys", true + case 2150: + return "dynamic3d", true + case 2151: + return "docent", true + case 2152: + return "gtp-user", true + case 2153: + return "ctlptc", true + case 2154: + return "stdptc", true + case 2155: + return "brdptc", true + case 2156: + return "trp", true + case 2157: + return "xnds", true + case 2158: + return "touchnetplus", true + case 2159: + return "gdbremote", true + case 2160: + return "apc-2160", true + case 2161: + return "apc-2161", true + case 2162: + return "navisphere", true + case 2163: + return "navisphere-sec", true + case 2164: + return "ddns-v3", true + case 2165: + return "x-bone-api", true + case 2166: + return "iwserver", true + case 2167: + return "raw-serial", true + case 2168: + return "easy-soft-mux", true + case 2169: + return "brain", true + case 2170: + return "eyetv", true + case 2171: + return "msfw-storage", true + case 2172: + return "msfw-s-storage", true + case 2173: + return "msfw-replica", true + case 2174: + return "msfw-array", true + case 2175: + return "airsync", true + case 2176: + return "rapi", true + case 2177: + return "qwave", true + case 2178: + return "bitspeer", true + case 2179: + return "vmrdp", true + case 2180: + return "mc-gt-srv", true + case 2181: + return "eforward", true + case 2182: + return "cgn-stat", true + case 2183: + return "cgn-config", true + case 2184: + return "nvd", true + case 2185: + return "onbase-dds", true + case 2186: + return "gtaua", true + case 2187: + return "ssmd", true + case 2190: + return "tivoconnect", true + case 2191: + return "tvbus", true + case 2192: + return "asdis", true + case 2193: + return "drwcs", true + case 2197: + return "mnp-exchange", true + case 2198: + return "onehome-remote", true + case 2199: + return "onehome-help", true + case 2201: + return "ats", true + case 2202: + return "imtc-map", true + case 2203: + return "b2-runtime", true + case 2204: + return "b2-license", true + case 2205: + return "jps", true + case 2206: + return "hpocbus", true + case 2207: + return "hpssd", true + case 2208: + return "hpiod", true + case 2209: + return "rimf-ps", true + case 2210: + return "noaaport", true + case 2211: + return "emwin", true + case 2212: + return "leecoposserver", true + case 2213: + return "kali", true + case 2214: + return "rpi", true + case 2215: + return "ipcore", true + case 2216: + return "vtu-comms", true + case 2217: + return "gotodevice", true + case 2218: + return "bounzza", true + case 2219: + return "netiq-ncap", true + case 2220: + return "netiq", true + case 2221: + return "ethernet-ip-s", true + case 2222: + return "EtherNet-IP-1", true + case 2223: + return "rockwell-csp2", true + case 2224: + return "efi-mg", true + case 2226: + return "di-drm", true + case 2227: + return "di-msg", true + case 2228: + return "ehome-ms", true + case 2229: + return "datalens", true + case 2230: + return "queueadm", true + case 2231: + return "wimaxasncp", true + case 2232: + return "ivs-video", true + case 2233: + return "infocrypt", true + case 2234: + return "directplay", true + case 2235: + return "sercomm-wlink", true + case 2236: + return "nani", true + case 2237: + return "optech-port1-lm", true + case 2238: + return "aviva-sna", true + case 2239: + return "imagequery", true + case 2240: + return "recipe", true + case 2241: + return "ivsd", true + case 2242: + return "foliocorp", true + case 2243: + return "magicom", true + case 2244: + return "nmsserver", true + case 2245: + return "hao", true + case 2246: + return "pc-mta-addrmap", true + case 2247: + return "antidotemgrsvr", true + case 2248: + return "ums", true + case 2249: + return "rfmp", true + case 2250: + return "remote-collab", true + case 2251: + return "dif-port", true + case 2252: + return "njenet-ssl", true + case 2253: + return "dtv-chan-req", true + case 2254: + return "seispoc", true + case 2255: + return "vrtp", true + case 2256: + return "pcc-mfp", true + case 2257: + return "simple-tx-rx", true + case 2258: + return "rcts", true + case 2259: + return "bid-serv", true + case 2260: + return "apc-2260", true + case 2261: + return "comotionmaster", true + case 2262: + return "comotionback", true + case 2263: + return "ecwcfg", true + case 2264: + return "apx500api-1", true + case 2265: + return "apx500api-2", true + case 2266: + return "mfserver", true + case 2267: + return "ontobroker", true + case 2268: + return "amt", true + case 2269: + return "mikey", true + case 2270: + return "starschool", true + case 2271: + return "mmcals", true + case 2272: + return "mmcal", true + case 2273: + return "mysql-im", true + case 2274: + return "pcttunnell", true + case 2275: + return "ibridge-data", true + case 2276: + return "ibridge-mgmt", true + case 2277: + return "bluectrlproxy", true + case 2278: + return "s3db", true + case 2279: + return "xmquery", true + case 2280: + return "lnvpoller", true + case 2281: + return "lnvconsole", true + case 2282: + return "lnvalarm", true + case 2283: + return "lnvstatus", true + case 2284: + return "lnvmaps", true + case 2285: + return "lnvmailmon", true + case 2286: + return "nas-metering", true + case 2287: + return "dna", true + case 2288: + return "netml", true + case 2289: + return "dict-lookup", true + case 2290: + return "sonus-logging", true + case 2291: + return "eapsp", true + case 2292: + return "mib-streaming", true + case 2293: + return "npdbgmngr", true + case 2294: + return "konshus-lm", true + case 2295: + return "advant-lm", true + case 2296: + return "theta-lm", true + case 2297: + return "d2k-datamover1", true + case 2298: + return "d2k-datamover2", true + case 2299: + return "pc-telecommute", true + case 2300: + return "cvmmon", true + case 2301: + return "cpq-wbem", true + case 2302: + return "binderysupport", true + case 2303: + return "proxy-gateway", true + case 2304: + return "attachmate-uts", true + case 2305: + return "mt-scaleserver", true + case 2306: + return "tappi-boxnet", true + case 2307: + return "pehelp", true + case 2308: + return "sdhelp", true + case 2309: + return "sdserver", true + case 2310: + return "sdclient", true + case 2311: + return "messageservice", true + case 2312: + return "wanscaler", true + case 2313: + return "iapp", true + case 2314: + return "cr-websystems", true + case 2315: + return "precise-sft", true + case 2316: + return "sent-lm", true + case 2317: + return "attachmate-g32", true + case 2318: + return "cadencecontrol", true + case 2319: + return "infolibria", true + case 2320: + return "siebel-ns", true + case 2321: + return "rdlap", true + case 2322: + return "ofsd", true + case 2323: + return "3d-nfsd", true + case 2324: + return "cosmocall", true + case 2325: + return "ansysli", true + case 2326: + return "idcp", true + case 2327: + return "xingcsm", true + case 2328: + return "netrix-sftm", true + case 2329: + return "nvd", true + case 2330: + return "tscchat", true + case 2331: + return "agentview", true + case 2332: + return "rcc-host", true + case 2333: + return "snapp", true + case 2334: + return "ace-client", true + case 2335: + return "ace-proxy", true + case 2336: + return "appleugcontrol", true + case 2337: + return "ideesrv", true + case 2338: + return "norton-lambert", true + case 2339: + return "3com-webview", true + case 2340: + return "wrs-registry", true + case 2341: + return "xiostatus", true + case 2342: + return "manage-exec", true + case 2343: + return "nati-logos", true + case 2344: + return "fcmsys", true + case 2345: + return "dbm", true + case 2346: + return "redstorm-join", true + case 2347: + return "redstorm-find", true + case 2348: + return "redstorm-info", true + case 2349: + return "redstorm-diag", true + case 2350: + return "psbserver", true + case 2351: + return "psrserver", true + case 2352: + return "pslserver", true + case 2353: + return "pspserver", true + case 2354: + return "psprserver", true + case 2355: + return "psdbserver", true + case 2356: + return "gxtelmd", true + case 2357: + return "unihub-server", true + case 2358: + return "futrix", true + case 2359: + return "flukeserver", true + case 2360: + return "nexstorindltd", true + case 2361: + return "tl1", true + case 2362: + return "digiman", true + case 2363: + return "mediacntrlnfsd", true + case 2364: + return "oi-2000", true + case 2365: + return "dbref", true + case 2366: + return "qip-login", true + case 2367: + return "service-ctrl", true + case 2368: + return "opentable", true + case 2369: + return "bif-p2p", true + case 2370: + return "l3-hbmon", true + case 2372: + return "lanmessenger", true + case 2378: + return "dali", true + case 2381: + return "compaq-https", true + case 2382: + return "ms-olap3", true + case 2383: + return "ms-olap4", true + case 2384: + return "sd-capacity", true + case 2385: + return "sd-data", true + case 2386: + return "virtualtape", true + case 2387: + return "vsamredirector", true + case 2388: + return "mynahautostart", true + case 2389: + return "ovsessionmgr", true + case 2390: + return "rsmtp", true + case 2391: + return "3com-net-mgmt", true + case 2392: + return "tacticalauth", true + case 2393: + return "ms-olap1", true + case 2394: + return "ms-olap2", true + case 2395: + return "lan900-remote", true + case 2396: + return "wusage", true + case 2397: + return "ncl", true + case 2398: + return "orbiter", true + case 2399: + return "fmpro-fdal", true + case 2400: + return "opequus-server", true + case 2401: + return "cvspserver", true + case 2402: + return "taskmaster2000", true + case 2403: + return "taskmaster2000", true + case 2404: + return "iec-104", true + case 2405: + return "trc-netpoll", true + case 2406: + return "jediserver", true + case 2407: + return "orion", true + case 2409: + return "sns-protocol", true + case 2410: + return "vrts-registry", true + case 2411: + return "netwave-ap-mgmt", true + case 2412: + return "cdn", true + case 2413: + return "orion-rmi-reg", true + case 2414: + return "beeyond", true + case 2415: + return "codima-rtp", true + case 2416: + return "rmtserver", true + case 2417: + return "composit-server", true + case 2418: + return "cas", true + case 2419: + return "attachmate-s2s", true + case 2420: + return "dslremote-mgmt", true + case 2421: + return "g-talk", true + case 2422: + return "crmsbits", true + case 2423: + return "rnrp", true + case 2424: + return "kofax-svr", true + case 2425: + return "fjitsuappmgr", true + case 2426: + return "vcmp", true + case 2427: + return "mgcp-gateway", true + case 2428: + return "ott", true + case 2429: + return "ft-role", true + case 2430: + return "venus", true + case 2431: + return "venus-se", true + case 2432: + return "codasrv", true + case 2433: + return "codasrv-se", true + case 2434: + return "pxc-epmap", true + case 2435: + return "optilogic", true + case 2436: + return "topx", true + case 2437: + return "unicontrol", true + case 2438: + return "msp", true + case 2439: + return "sybasedbsynch", true + case 2440: + return "spearway", true + case 2441: + return "pvsw-inet", true + case 2442: + return "netangel", true + case 2443: + return "powerclientcsf", true + case 2444: + return "btpp2sectrans", true + case 2445: + return "dtn1", true + case 2446: + return "bues-service", true + case 2447: + return "ovwdb", true + case 2448: + return "hpppssvr", true + case 2449: + return "ratl", true + case 2450: + return "netadmin", true + case 2451: + return "netchat", true + case 2452: + return "snifferclient", true + case 2453: + return "madge-ltd", true + case 2454: + return "indx-dds", true + case 2455: + return "wago-io-system", true + case 2456: + return "altav-remmgt", true + case 2457: + return "rapido-ip", true + case 2458: + return "griffin", true + case 2459: + return "xrpl", true + case 2460: + return "ms-theater", true + case 2461: + return "qadmifoper", true + case 2462: + return "qadmifevent", true + case 2463: + return "lsi-raid-mgmt", true + case 2464: + return "direcpc-si", true + case 2465: + return "lbm", true + case 2466: + return "lbf", true + case 2467: + return "high-criteria", true + case 2468: + return "qip-msgd", true + case 2469: + return "mti-tcs-comm", true + case 2470: + return "taskman-port", true + case 2471: + return "seaodbc", true + case 2472: + return "c3", true + case 2473: + return "aker-cdp", true + case 2474: + return "vitalanalysis", true + case 2475: + return "ace-server", true + case 2476: + return "ace-svr-prop", true + case 2477: + return "ssm-cvs", true + case 2478: + return "ssm-cssps", true + case 2479: + return "ssm-els", true + case 2480: + return "powerexchange", true + case 2481: + return "giop", true + case 2482: + return "giop-ssl", true + case 2483: + return "ttc", true + case 2484: + return "ttc-ssl", true + case 2485: + return "netobjects1", true + case 2486: + return "netobjects2", true + case 2487: + return "pns", true + case 2488: + return "moy-corp", true + case 2489: + return "tsilb", true + case 2490: + return "qip-qdhcp", true + case 2491: + return "conclave-cpp", true + case 2492: + return "groove", true + case 2493: + return "talarian-mqs", true + case 2494: + return "bmc-ar", true + case 2495: + return "fast-rem-serv", true + case 2496: + return "dirgis", true + case 2497: + return "quaddb", true + case 2498: + return "odn-castraq", true + case 2499: + return "unicontrol", true + case 2500: + return "rtsserv", true + case 2501: + return "rtsclient", true + case 2502: + return "kentrox-prot", true + case 2503: + return "nms-dpnss", true + case 2504: + return "wlbs", true + case 2505: + return "ppcontrol", true + case 2506: + return "jbroker", true + case 2507: + return "spock", true + case 2508: + return "jdatastore", true + case 2509: + return "fjmpss", true + case 2510: + return "fjappmgrbulk", true + case 2511: + return "metastorm", true + case 2512: + return "citrixima", true + case 2513: + return "citrixadmin", true + case 2514: + return "facsys-ntp", true + case 2515: + return "facsys-router", true + case 2516: + return "maincontrol", true + case 2517: + return "call-sig-trans", true + case 2518: + return "willy", true + case 2519: + return "globmsgsvc", true + case 2520: + return "pvsw", true + case 2521: + return "adaptecmgr", true + case 2522: + return "windb", true + case 2523: + return "qke-llc-v3", true + case 2524: + return "optiwave-lm", true + case 2525: + return "ms-v-worlds", true + case 2526: + return "ema-sent-lm", true + case 2527: + return "iqserver", true + case 2528: + return "ncr-ccl", true + case 2529: + return "utsftp", true + case 2530: + return "vrcommerce", true + case 2531: + return "ito-e-gui", true + case 2532: + return "ovtopmd", true + case 2533: + return "snifferserver", true + case 2534: + return "combox-web-acc", true + case 2535: + return "madcap", true + case 2536: + return "btpp2audctr1", true + case 2537: + return "upgrade", true + case 2538: + return "vnwk-prapi", true + case 2539: + return "vsiadmin", true + case 2540: + return "lonworks", true + case 2541: + return "lonworks2", true + case 2542: + return "udrawgraph", true + case 2543: + return "reftek", true + case 2544: + return "novell-zen", true + case 2545: + return "sis-emt", true + case 2546: + return "vytalvaultbrtp", true + case 2547: + return "vytalvaultvsmp", true + case 2548: + return "vytalvaultpipe", true + case 2549: + return "ipass", true + case 2550: + return "ads", true + case 2551: + return "isg-uda-server", true + case 2552: + return "call-logging", true + case 2553: + return "efidiningport", true + case 2554: + return "vcnet-link-v10", true + case 2555: + return "compaq-wcp", true + case 2556: + return "nicetec-nmsvc", true + case 2557: + return "nicetec-mgmt", true + case 2558: + return "pclemultimedia", true + case 2559: + return "lstp", true + case 2560: + return "labrat", true + case 2561: + return "mosaixcc", true + case 2562: + return "delibo", true + case 2563: + return "cti-redwood", true + case 2564: + return "hp-3000-telnet", true + case 2565: + return "coord-svr", true + case 2566: + return "pcs-pcw", true + case 2567: + return "clp", true + case 2568: + return "spamtrap", true + case 2569: + return "sonuscallsig", true + case 2570: + return "hs-port", true + case 2571: + return "cecsvc", true + case 2572: + return "ibp", true + case 2573: + return "trustestablish", true + case 2574: + return "blockade-bpsp", true + case 2575: + return "hl7", true + case 2576: + return "tclprodebugger", true + case 2577: + return "scipticslsrvr", true + case 2578: + return "rvs-isdn-dcp", true + case 2579: + return "mpfoncl", true + case 2580: + return "tributary", true + case 2581: + return "argis-te", true + case 2582: + return "argis-ds", true + case 2583: + return "mon", true + case 2584: + return "cyaserv", true + case 2585: + return "netx-server", true + case 2586: + return "netx-agent", true + case 2587: + return "masc", true + case 2588: + return "privilege", true + case 2589: + return "quartus-tcl", true + case 2590: + return "idotdist", true + case 2591: + return "maytagshuffle", true + case 2592: + return "netrek", true + case 2593: + return "mns-mail", true + case 2594: + return "dts", true + case 2595: + return "worldfusion1", true + case 2596: + return "worldfusion2", true + case 2597: + return "homesteadglory", true + case 2598: + return "citriximaclient", true + case 2599: + return "snapd", true + case 2600: + return "hpstgmgr", true + case 2601: + return "discp-client", true + case 2602: + return "discp-server", true + case 2603: + return "servicemeter", true + case 2604: + return "nsc-ccs", true + case 2605: + return "nsc-posa", true + case 2606: + return "netmon", true + case 2607: + return "connection", true + case 2608: + return "wag-service", true + case 2609: + return "system-monitor", true + case 2610: + return "versa-tek", true + case 2611: + return "lionhead", true + case 2612: + return "qpasa-agent", true + case 2613: + return "smntubootstrap", true + case 2614: + return "neveroffline", true + case 2615: + return "firepower", true + case 2616: + return "appswitch-emp", true + case 2617: + return "cmadmin", true + case 2618: + return "priority-e-com", true + case 2619: + return "bruce", true + case 2620: + return "lpsrecommender", true + case 2621: + return "miles-apart", true + case 2622: + return "metricadbc", true + case 2623: + return "lmdp", true + case 2624: + return "aria", true + case 2625: + return "blwnkl-port", true + case 2626: + return "gbjd816", true + case 2627: + return "moshebeeri", true + case 2628: + return "dict", true + case 2629: + return "sitaraserver", true + case 2630: + return "sitaramgmt", true + case 2631: + return "sitaradir", true + case 2632: + return "irdg-post", true + case 2633: + return "interintelli", true + case 2634: + return "pk-electronics", true + case 2635: + return "backburner", true + case 2636: + return "solve", true + case 2637: + return "imdocsvc", true + case 2638: + return "sybaseanywhere", true + case 2639: + return "aminet", true + case 2640: + return "ami-control", true + case 2641: + return "hdl-srv", true + case 2642: + return "tragic", true + case 2643: + return "gte-samp", true + case 2644: + return "travsoft-ipx-t", true + case 2645: + return "novell-ipx-cmd", true + case 2646: + return "and-lm", true + case 2647: + return "syncserver", true + case 2648: + return "upsnotifyprot", true + case 2649: + return "vpsipport", true + case 2650: + return "eristwoguns", true + case 2651: + return "ebinsite", true + case 2652: + return "interpathpanel", true + case 2653: + return "sonus", true + case 2654: + return "corel-vncadmin", true + case 2655: + return "unglue", true + case 2656: + return "kana", true + case 2657: + return "sns-dispatcher", true + case 2658: + return "sns-admin", true + case 2659: + return "sns-query", true + case 2660: + return "gcmonitor", true + case 2661: + return "olhost", true + case 2662: + return "bintec-capi", true + case 2663: + return "bintec-tapi", true + case 2664: + return "patrol-mq-gm", true + case 2665: + return "patrol-mq-nm", true + case 2666: + return "extensis", true + case 2667: + return "alarm-clock-s", true + case 2668: + return "alarm-clock-c", true + case 2669: + return "toad", true + case 2670: + return "tve-announce", true + case 2671: + return "newlixreg", true + case 2672: + return "nhserver", true + case 2673: + return "firstcall42", true + case 2674: + return "ewnn", true + case 2675: + return "ttc-etap", true + case 2676: + return "simslink", true + case 2677: + return "gadgetgate1way", true + case 2678: + return "gadgetgate2way", true + case 2679: + return "syncserverssl", true + case 2680: + return "pxc-sapxom", true + case 2681: + return "mpnjsomb", true + case 2683: + return "ncdloadbalance", true + case 2684: + return "mpnjsosv", true + case 2685: + return "mpnjsocl", true + case 2686: + return "mpnjsomg", true + case 2687: + return "pq-lic-mgmt", true + case 2688: + return "md-cg-http", true + case 2689: + return "fastlynx", true + case 2690: + return "hp-nnm-data", true + case 2691: + return "itinternet", true + case 2692: + return "admins-lms", true + case 2694: + return "pwrsevent", true + case 2695: + return "vspread", true + case 2696: + return "unifyadmin", true + case 2697: + return "oce-snmp-trap", true + case 2698: + return "mck-ivpip", true + case 2699: + return "csoft-plusclnt", true + case 2700: + return "tqdata", true + case 2701: + return "sms-rcinfo", true + case 2702: + return "sms-xfer", true + case 2703: + return "sms-chat", true + case 2704: + return "sms-remctrl", true + case 2705: + return "sds-admin", true + case 2706: + return "ncdmirroring", true + case 2707: + return "emcsymapiport", true + case 2708: + return "banyan-net", true + case 2709: + return "supermon", true + case 2710: + return "sso-service", true + case 2711: + return "sso-control", true + case 2712: + return "aocp", true + case 2713: + return "raventbs", true + case 2714: + return "raventdm", true + case 2715: + return "hpstgmgr2", true + case 2716: + return "inova-ip-disco", true + case 2717: + return "pn-requester", true + case 2718: + return "pn-requester2", true + case 2719: + return "scan-change", true + case 2720: + return "wkars", true + case 2721: + return "smart-diagnose", true + case 2722: + return "proactivesrvr", true + case 2723: + return "watchdog-nt", true + case 2724: + return "qotps", true + case 2725: + return "msolap-ptp2", true + case 2726: + return "tams", true + case 2727: + return "mgcp-callagent", true + case 2728: + return "sqdr", true + case 2729: + return "tcim-control", true + case 2730: + return "nec-raidplus", true + case 2731: + return "fyre-messanger", true + case 2732: + return "g5m", true + case 2733: + return "signet-ctf", true + case 2734: + return "ccs-software", true + case 2735: + return "netiq-mc", true + case 2736: + return "radwiz-nms-srv", true + case 2737: + return "srp-feedback", true + case 2738: + return "ndl-tcp-ois-gw", true + case 2739: + return "tn-timing", true + case 2740: + return "alarm", true + case 2741: + return "tsb", true + case 2742: + return "tsb2", true + case 2743: + return "murx", true + case 2744: + return "honyaku", true + case 2745: + return "urbisnet", true + case 2746: + return "cpudpencap", true + case 2747: + return "fjippol-swrly", true + case 2748: + return "fjippol-polsvr", true + case 2749: + return "fjippol-cnsl", true + case 2750: + return "fjippol-port1", true + case 2751: + return "fjippol-port2", true + case 2752: + return "rsisysaccess", true + case 2753: + return "de-spot", true + case 2754: + return "apollo-cc", true + case 2755: + return "expresspay", true + case 2756: + return "simplement-tie", true + case 2757: + return "cnrp", true + case 2758: + return "apollo-status", true + case 2759: + return "apollo-gms", true + case 2760: + return "sabams", true + case 2761: + return "dicom-iscl", true + case 2762: + return "dicom-tls", true + case 2763: + return "desktop-dna", true + case 2764: + return "data-insurance", true + case 2765: + return "qip-audup", true + case 2766: + return "compaq-scp", true + case 2767: + return "uadtc", true + case 2768: + return "uacs", true + case 2769: + return "exce", true + case 2770: + return "veronica", true + case 2771: + return "vergencecm", true + case 2772: + return "auris", true + case 2773: + return "rbakcup1", true + case 2774: + return "rbakcup2", true + case 2775: + return "smpp", true + case 2776: + return "ridgeway1", true + case 2777: + return "ridgeway2", true + case 2778: + return "gwen-sonya", true + case 2779: + return "lbc-sync", true + case 2780: + return "lbc-control", true + case 2781: + return "whosells", true + case 2782: + return "everydayrc", true + case 2783: + return "aises", true + case 2784: + return "www-dev", true + case 2785: + return "aic-np", true + case 2786: + return "aic-oncrpc", true + case 2787: + return "piccolo", true + case 2788: + return "fryeserv", true + case 2789: + return "media-agent", true + case 2790: + return "plgproxy", true + case 2791: + return "mtport-regist", true + case 2792: + return "f5-globalsite", true + case 2793: + return "initlsmsad", true + case 2795: + return "livestats", true + case 2796: + return "ac-tech", true + case 2797: + return "esp-encap", true + case 2798: + return "tmesis-upshot", true + case 2799: + return "icon-discover", true + case 2800: + return "acc-raid", true + case 2801: + return "igcp", true + case 2802: + return "veritas-udp1", true + case 2803: + return "btprjctrl", true + case 2804: + return "dvr-esm", true + case 2805: + return "wta-wsp-s", true + case 2806: + return "cspuni", true + case 2807: + return "cspmulti", true + case 2808: + return "j-lan-p", true + case 2809: + return "corbaloc", true + case 2810: + return "netsteward", true + case 2811: + return "gsiftp", true + case 2812: + return "atmtcp", true + case 2813: + return "llm-pass", true + case 2814: + return "llm-csv", true + case 2815: + return "lbc-measure", true + case 2816: + return "lbc-watchdog", true + case 2817: + return "nmsigport", true + case 2818: + return "rmlnk", true + case 2819: + return "fc-faultnotify", true + case 2820: + return "univision", true + case 2821: + return "vrts-at-port", true + case 2822: + return "ka0wuc", true + case 2823: + return "cqg-netlan", true + case 2824: + return "cqg-netlan-1", true + case 2826: + return "slc-systemlog", true + case 2827: + return "slc-ctrlrloops", true + case 2828: + return "itm-lm", true + case 2829: + return "silkp1", true + case 2830: + return "silkp2", true + case 2831: + return "silkp3", true + case 2832: + return "silkp4", true + case 2833: + return "glishd", true + case 2834: + return "evtp", true + case 2835: + return "evtp-data", true + case 2836: + return "catalyst", true + case 2837: + return "repliweb", true + case 2838: + return "starbot", true + case 2839: + return "nmsigport", true + case 2840: + return "l3-exprt", true + case 2841: + return "l3-ranger", true + case 2842: + return "l3-hawk", true + case 2843: + return "pdnet", true + case 2844: + return "bpcp-poll", true + case 2845: + return "bpcp-trap", true + case 2846: + return "aimpp-hello", true + case 2847: + return "aimpp-port-req", true + case 2848: + return "amt-blc-port", true + case 2849: + return "fxp", true + case 2850: + return "metaconsole", true + case 2851: + return "webemshttp", true + case 2852: + return "bears-01", true + case 2853: + return "ispipes", true + case 2854: + return "infomover", true + case 2856: + return "cesdinv", true + case 2857: + return "simctlp", true + case 2858: + return "ecnp", true + case 2859: + return "activememory", true + case 2860: + return "dialpad-voice1", true + case 2861: + return "dialpad-voice2", true + case 2862: + return "ttg-protocol", true + case 2863: + return "sonardata", true + case 2864: + return "astronova-main", true + case 2865: + return "pit-vpn", true + case 2866: + return "iwlistener", true + case 2867: + return "esps-portal", true + case 2868: + return "npep-messaging", true + case 2869: + return "icslap", true + case 2870: + return "daishi", true + case 2871: + return "msi-selectplay", true + case 2872: + return "radix", true + case 2873: + return "psrt", true + case 2874: + return "dxmessagebase1", true + case 2875: + return "dxmessagebase2", true + case 2876: + return "sps-tunnel", true + case 2877: + return "bluelance", true + case 2878: + return "aap", true + case 2879: + return "ucentric-ds", true + case 2880: + return "synapse", true + case 2881: + return "ndsp", true + case 2882: + return "ndtp", true + case 2883: + return "ndnp", true + case 2884: + return "flashmsg", true + case 2885: + return "topflow", true + case 2886: + return "responselogic", true + case 2887: + return "aironetddp", true + case 2888: + return "spcsdlobby", true + case 2889: + return "rsom", true + case 2890: + return "cspclmulti", true + case 2891: + return "cinegrfx-elmd", true + case 2892: + return "snifferdata", true + case 2893: + return "vseconnector", true + case 2894: + return "abacus-remote", true + case 2895: + return "natuslink", true + case 2896: + return "ecovisiong6-1", true + case 2897: + return "citrix-rtmp", true + case 2898: + return "appliance-cfg", true + case 2899: + return "powergemplus", true + case 2900: + return "quicksuite", true + case 2901: + return "allstorcns", true + case 2902: + return "netaspi", true + case 2903: + return "suitcase", true + case 2904: + return "m2ua", true + case 2906: + return "caller9", true + case 2907: + return "webmethods-b2b", true + case 2908: + return "mao", true + case 2909: + return "funk-dialout", true + case 2910: + return "tdaccess", true + case 2911: + return "blockade", true + case 2912: + return "epicon", true + case 2913: + return "boosterware", true + case 2914: + return "gamelobby", true + case 2915: + return "tksocket", true + case 2916: + return "elvin-server", true + case 2917: + return "elvin-client", true + case 2918: + return "kastenchasepad", true + case 2919: + return "roboer", true + case 2920: + return "roboeda", true + case 2921: + return "cesdcdman", true + case 2922: + return "cesdcdtrn", true + case 2923: + return "wta-wsp-wtp-s", true + case 2924: + return "precise-vip", true + case 2926: + return "mobile-file-dl", true + case 2927: + return "unimobilectrl", true + case 2928: + return "redstone-cpss", true + case 2929: + return "amx-webadmin", true + case 2930: + return "amx-weblinx", true + case 2931: + return "circle-x", true + case 2932: + return "incp", true + case 2933: + return "4-tieropmgw", true + case 2934: + return "4-tieropmcli", true + case 2935: + return "qtp", true + case 2936: + return "otpatch", true + case 2937: + return "pnaconsult-lm", true + case 2938: + return "sm-pas-1", true + case 2939: + return "sm-pas-2", true + case 2940: + return "sm-pas-3", true + case 2941: + return "sm-pas-4", true + case 2942: + return "sm-pas-5", true + case 2943: + return "ttnrepository", true + case 2944: + return "megaco-h248", true + case 2945: + return "h248-binary", true + case 2946: + return "fjsvmpor", true + case 2947: + return "gpsd", true + case 2948: + return "wap-push", true + case 2949: + return "wap-pushsecure", true + case 2950: + return "esip", true + case 2951: + return "ottp", true + case 2952: + return "mpfwsas", true + case 2953: + return "ovalarmsrv", true + case 2954: + return "ovalarmsrv-cmd", true + case 2955: + return "csnotify", true + case 2956: + return "ovrimosdbman", true + case 2957: + return "jmact5", true + case 2958: + return "jmact6", true + case 2959: + return "rmopagt", true + case 2960: + return "dfoxserver", true + case 2961: + return "boldsoft-lm", true + case 2962: + return "iph-policy-cli", true + case 2963: + return "iph-policy-adm", true + case 2964: + return "bullant-srap", true + case 2965: + return "bullant-rap", true + case 2966: + return "idp-infotrieve", true + case 2967: + return "ssc-agent", true + case 2968: + return "enpp", true + case 2969: + return "essp", true + case 2970: + return "index-net", true + case 2971: + return "netclip", true + case 2972: + return "pmsm-webrctl", true + case 2973: + return "svnetworks", true + case 2974: + return "signal", true + case 2975: + return "fjmpcm", true + case 2976: + return "cns-srv-port", true + case 2977: + return "ttc-etap-ns", true + case 2978: + return "ttc-etap-ds", true + case 2979: + return "h263-video", true + case 2980: + return "wimd", true + case 2981: + return "mylxamport", true + case 2982: + return "iwb-whiteboard", true + case 2983: + return "netplan", true + case 2984: + return "hpidsadmin", true + case 2985: + return "hpidsagent", true + case 2986: + return "stonefalls", true + case 2987: + return "identify", true + case 2988: + return "hippad", true + case 2989: + return "zarkov", true + case 2990: + return "boscap", true + case 2991: + return "wkstn-mon", true + case 2992: + return "avenyo", true + case 2993: + return "veritas-vis1", true + case 2994: + return "veritas-vis2", true + case 2995: + return "idrs", true + case 2996: + return "vsixml", true + case 2997: + return "rebol", true + case 2998: + return "realsecure", true + case 2999: + return "remoteware-un", true + case 3000: + return "hbci", true + case 3002: + return "exlm-agent", true + case 3003: + return "cgms", true + case 3004: + return "csoftragent", true + case 3005: + return "geniuslm", true + case 3006: + return "ii-admin", true + case 3007: + return "lotusmtap", true + case 3008: + return "midnight-tech", true + case 3009: + return "pxc-ntfy", true + case 3010: + return "ping-pong", true + case 3011: + return "trusted-web", true + case 3012: + return "twsdss", true + case 3013: + return "gilatskysurfer", true + case 3014: + return "broker-service", true + case 3015: + return "nati-dstp", true + case 3016: + return "notify-srvr", true + case 3017: + return "event-listener", true + case 3018: + return "srvc-registry", true + case 3019: + return "resource-mgr", true + case 3020: + return "cifs", true + case 3021: + return "agriserver", true + case 3022: + return "csregagent", true + case 3023: + return "magicnotes", true + case 3024: + return "nds-sso", true + case 3025: + return "arepa-raft", true + case 3026: + return "agri-gateway", true + case 3027: + return "LiebDevMgmt-C", true + case 3028: + return "LiebDevMgmt-DM", true + case 3029: + return "LiebDevMgmt-A", true + case 3030: + return "arepa-cas", true + case 3031: + return "eppc", true + case 3032: + return "redwood-chat", true + case 3033: + return "pdb", true + case 3034: + return "osmosis-aeea", true + case 3035: + return "fjsv-gssagt", true + case 3036: + return "hagel-dump", true + case 3037: + return "hp-san-mgmt", true + case 3038: + return "santak-ups", true + case 3039: + return "cogitate", true + case 3040: + return "tomato-springs", true + case 3041: + return "di-traceware", true + case 3042: + return "journee", true + case 3043: + return "brp", true + case 3044: + return "epp", true + case 3045: + return "responsenet", true + case 3046: + return "di-ase", true + case 3047: + return "hlserver", true + case 3048: + return "pctrader", true + case 3049: + return "nsws", true + case 3050: + return "gds-db", true + case 3051: + return "galaxy-server", true + case 3052: + return "apc-3052", true + case 3053: + return "dsom-server", true + case 3054: + return "amt-cnf-prot", true + case 3055: + return "policyserver", true + case 3056: + return "cdl-server", true + case 3057: + return "goahead-fldup", true + case 3058: + return "videobeans", true + case 3059: + return "qsoft", true + case 3060: + return "interserver", true + case 3061: + return "cautcpd", true + case 3062: + return "ncacn-ip-tcp", true + case 3063: + return "ncadg-ip-udp", true + case 3064: + return "rprt", true + case 3065: + return "slinterbase", true + case 3066: + return "netattachsdmp", true + case 3067: + return "fjhpjp", true + case 3068: + return "ls3bcast", true + case 3069: + return "ls3", true + case 3070: + return "mgxswitch", true + case 3072: + return "csd-monitor", true + case 3073: + return "vcrp", true + case 3074: + return "xbox", true + case 3075: + return "orbix-locator", true + case 3076: + return "orbix-config", true + case 3077: + return "orbix-loc-ssl", true + case 3078: + return "orbix-cfg-ssl", true + case 3079: + return "lv-frontpanel", true + case 3080: + return "stm-pproc", true + case 3081: + return "tl1-lv", true + case 3082: + return "tl1-raw", true + case 3083: + return "tl1-telnet", true + case 3084: + return "itm-mccs", true + case 3085: + return "pcihreq", true + case 3086: + return "jdl-dbkitchen", true + case 3087: + return "asoki-sma", true + case 3088: + return "xdtp", true + case 3089: + return "ptk-alink", true + case 3090: + return "stss", true + case 3091: + return "1ci-smcs", true + case 3093: + return "rapidmq-center", true + case 3094: + return "rapidmq-reg", true + case 3095: + return "panasas", true + case 3096: + return "ndl-aps", true + case 3098: + return "umm-port", true + case 3099: + return "chmd", true + case 3100: + return "opcon-xps", true + case 3101: + return "hp-pxpib", true + case 3102: + return "slslavemon", true + case 3103: + return "autocuesmi", true + case 3104: + return "autocuetime", true + case 3105: + return "cardbox", true + case 3106: + return "cardbox-http", true + case 3107: + return "business", true + case 3108: + return "geolocate", true + case 3109: + return "personnel", true + case 3110: + return "sim-control", true + case 3111: + return "wsynch", true + case 3112: + return "ksysguard", true + case 3113: + return "cs-auth-svr", true + case 3114: + return "ccmad", true + case 3115: + return "mctet-master", true + case 3116: + return "mctet-gateway", true + case 3117: + return "mctet-jserv", true + case 3118: + return "pkagent", true + case 3119: + return "d2000kernel", true + case 3120: + return "d2000webserver", true + case 3122: + return "vtr-emulator", true + case 3123: + return "edix", true + case 3124: + return "beacon-port", true + case 3125: + return "a13-an", true + case 3127: + return "ctx-bridge", true + case 3128: + return "ndl-aas", true + case 3129: + return "netport-id", true + case 3130: + return "icpv2", true + case 3131: + return "netbookmark", true + case 3132: + return "ms-rule-engine", true + case 3133: + return "prism-deploy", true + case 3134: + return "ecp", true + case 3135: + return "peerbook-port", true + case 3136: + return "grubd", true + case 3137: + return "rtnt-1", true + case 3138: + return "rtnt-2", true + case 3139: + return "incognitorv", true + case 3140: + return "ariliamulti", true + case 3141: + return "vmodem", true + case 3142: + return "rdc-wh-eos", true + case 3143: + return "seaview", true + case 3144: + return "tarantella", true + case 3145: + return "csi-lfap", true + case 3146: + return "bears-02", true + case 3147: + return "rfio", true + case 3148: + return "nm-game-admin", true + case 3149: + return "nm-game-server", true + case 3150: + return "nm-asses-admin", true + case 3151: + return "nm-assessor", true + case 3152: + return "feitianrockey", true + case 3153: + return "s8-client-port", true + case 3154: + return "ccmrmi", true + case 3155: + return "jpegmpeg", true + case 3156: + return "indura", true + case 3157: + return "e3consultants", true + case 3158: + return "stvp", true + case 3159: + return "navegaweb-port", true + case 3160: + return "tip-app-server", true + case 3161: + return "doc1lm", true + case 3162: + return "sflm", true + case 3163: + return "res-sap", true + case 3164: + return "imprs", true + case 3165: + return "newgenpay", true + case 3166: + return "sossecollector", true + case 3167: + return "nowcontact", true + case 3168: + return "poweronnud", true + case 3169: + return "serverview-as", true + case 3170: + return "serverview-asn", true + case 3171: + return "serverview-gf", true + case 3172: + return "serverview-rm", true + case 3173: + return "serverview-icc", true + case 3174: + return "armi-server", true + case 3175: + return "t1-e1-over-ip", true + case 3176: + return "ars-master", true + case 3177: + return "phonex-port", true + case 3178: + return "radclientport", true + case 3179: + return "h2gf-w-2m", true + case 3180: + return "mc-brk-srv", true + case 3181: + return "bmcpatrolagent", true + case 3182: + return "bmcpatrolrnvu", true + case 3183: + return "cops-tls", true + case 3184: + return "apogeex-port", true + case 3185: + return "smpppd", true + case 3186: + return "iiw-port", true + case 3187: + return "odi-port", true + case 3188: + return "brcm-comm-port", true + case 3189: + return "pcle-infex", true + case 3190: + return "csvr-proxy", true + case 3191: + return "csvr-sslproxy", true + case 3192: + return "firemonrcc", true + case 3193: + return "spandataport", true + case 3194: + return "magbind", true + case 3195: + return "ncu-1", true + case 3196: + return "ncu-2", true + case 3197: + return "embrace-dp-s", true + case 3198: + return "embrace-dp-c", true + case 3199: + return "dmod-workspace", true + case 3200: + return "tick-port", true + case 3201: + return "cpq-tasksmart", true + case 3202: + return "intraintra", true + case 3203: + return "netwatcher-mon", true + case 3204: + return "netwatcher-db", true + case 3205: + return "isns", true + case 3206: + return "ironmail", true + case 3207: + return "vx-auth-port", true + case 3208: + return "pfu-prcallback", true + case 3209: + return "netwkpathengine", true + case 3210: + return "flamenco-proxy", true + case 3211: + return "avsecuremgmt", true + case 3212: + return "surveyinst", true + case 3213: + return "neon24x7", true + case 3214: + return "jmq-daemon-1", true + case 3215: + return "jmq-daemon-2", true + case 3216: + return "ferrari-foam", true + case 3217: + return "unite", true + case 3218: + return "smartpackets", true + case 3219: + return "wms-messenger", true + case 3220: + return "xnm-ssl", true + case 3221: + return "xnm-clear-text", true + case 3222: + return "glbp", true + case 3223: + return "digivote", true + case 3224: + return "aes-discovery", true + case 3225: + return "fcip-port", true + case 3226: + return "isi-irp", true + case 3227: + return "dwnmshttp", true + case 3228: + return "dwmsgserver", true + case 3229: + return "global-cd-port", true + case 3230: + return "sftdst-port", true + case 3231: + return "vidigo", true + case 3232: + return "mdtp", true + case 3233: + return "whisker", true + case 3234: + return "alchemy", true + case 3235: + return "mdap-port", true + case 3236: + return "apparenet-ts", true + case 3237: + return "apparenet-tps", true + case 3238: + return "apparenet-as", true + case 3239: + return "apparenet-ui", true + case 3240: + return "triomotion", true + case 3241: + return "sysorb", true + case 3242: + return "sdp-id-port", true + case 3243: + return "timelot", true + case 3244: + return "onesaf", true + case 3245: + return "vieo-fe", true + case 3246: + return "dvt-system", true + case 3247: + return "dvt-data", true + case 3248: + return "procos-lm", true + case 3249: + return "ssp", true + case 3250: + return "hicp", true + case 3251: + return "sysscanner", true + case 3252: + return "dhe", true + case 3253: + return "pda-data", true + case 3254: + return "pda-sys", true + case 3255: + return "semaphore", true + case 3256: + return "cpqrpm-agent", true + case 3257: + return "cpqrpm-server", true + case 3258: + return "ivecon-port", true + case 3259: + return "epncdp2", true + case 3260: + return "iscsi-target", true + case 3261: + return "winshadow", true + case 3262: + return "necp", true + case 3263: + return "ecolor-imager", true + case 3264: + return "ccmail", true + case 3265: + return "altav-tunnel", true + case 3266: + return "ns-cfg-server", true + case 3267: + return "ibm-dial-out", true + case 3268: + return "msft-gc", true + case 3269: + return "msft-gc-ssl", true + case 3270: + return "verismart", true + case 3271: + return "csoft-prev", true + case 3272: + return "user-manager", true + case 3273: + return "sxmp", true + case 3274: + return "ordinox-server", true + case 3275: + return "samd", true + case 3276: + return "maxim-asics", true + case 3277: + return "awg-proxy", true + case 3278: + return "lkcmserver", true + case 3279: + return "admind", true + case 3280: + return "vs-server", true + case 3281: + return "sysopt", true + case 3282: + return "datusorb", true + case 3283: + return "Apple Remote Desktop (Net Assistant)", true + case 3284: + return "4talk", true + case 3285: + return "plato", true + case 3286: + return "e-net", true + case 3287: + return "directvdata", true + case 3288: + return "cops", true + case 3289: + return "enpc", true + case 3290: + return "caps-lm", true + case 3291: + return "sah-lm", true + case 3292: + return "cart-o-rama", true + case 3293: + return "fg-fps", true + case 3294: + return "fg-gip", true + case 3295: + return "dyniplookup", true + case 3296: + return "rib-slm", true + case 3297: + return "cytel-lm", true + case 3298: + return "deskview", true + case 3299: + return "pdrncs", true + case 3301: + return "tarantool", true + case 3302: + return "mcs-fastmail", true + case 3303: + return "opsession-clnt", true + case 3304: + return "opsession-srvr", true + case 3305: + return "odette-ftp", true + case 3306: + return "mysql", true + case 3307: + return "opsession-prxy", true + case 3308: + return "tns-server", true + case 3309: + return "tns-adv", true + case 3310: + return "dyna-access", true + case 3311: + return "mcns-tel-ret", true + case 3312: + return "appman-server", true + case 3313: + return "uorb", true + case 3314: + return "uohost", true + case 3315: + return "cdid", true + case 3316: + return "aicc-cmi", true + case 3317: + return "vsaiport", true + case 3318: + return "ssrip", true + case 3319: + return "sdt-lmd", true + case 3320: + return "officelink2000", true + case 3321: + return "vnsstr", true + case 3326: + return "sftu", true + case 3327: + return "bbars", true + case 3328: + return "egptlm", true + case 3329: + return "hp-device-disc", true + case 3330: + return "mcs-calypsoicf", true + case 3331: + return "mcs-messaging", true + case 3332: + return "mcs-mailsvr", true + case 3333: + return "dec-notes", true + case 3334: + return "directv-web", true + case 3335: + return "directv-soft", true + case 3336: + return "directv-tick", true + case 3337: + return "directv-catlg", true + case 3338: + return "anet-b", true + case 3339: + return "anet-l", true + case 3340: + return "anet-m", true + case 3341: + return "anet-h", true + case 3342: + return "webtie", true + case 3343: + return "ms-cluster-net", true + case 3344: + return "bnt-manager", true + case 3345: + return "influence", true + case 3346: + return "trnsprntproxy", true + case 3347: + return "phoenix-rpc", true + case 3348: + return "pangolin-laser", true + case 3349: + return "chevinservices", true + case 3350: + return "findviatv", true + case 3351: + return "btrieve", true + case 3352: + return "ssql", true + case 3353: + return "fatpipe", true + case 3354: + return "suitjd", true + case 3355: + return "ordinox-dbase", true + case 3356: + return "upnotifyps", true + case 3357: + return "adtech-test", true + case 3358: + return "mpsysrmsvr", true + case 3359: + return "wg-netforce", true + case 3360: + return "kv-server", true + case 3361: + return "kv-agent", true + case 3362: + return "dj-ilm", true + case 3363: + return "nati-vi-server", true + case 3364: + return "creativeserver", true + case 3365: + return "contentserver", true + case 3366: + return "creativepartnr", true + case 3372: + return "tip2", true + case 3373: + return "lavenir-lm", true + case 3374: + return "cluster-disc", true + case 3375: + return "vsnm-agent", true + case 3376: + return "cdbroker", true + case 3377: + return "cogsys-lm", true + case 3378: + return "wsicopy", true + case 3379: + return "socorfs", true + case 3380: + return "sns-channels", true + case 3381: + return "geneous", true + case 3382: + return "fujitsu-neat", true + case 3383: + return "esp-lm", true + case 3384: + return "hp-clic", true + case 3385: + return "qnxnetman", true + case 3386: + return "gprs-sig", true + case 3387: + return "backroomnet", true + case 3388: + return "cbserver", true + case 3389: + return "ms-wbt-server", true + case 3390: + return "dsc", true + case 3391: + return "savant", true + case 3392: + return "efi-lm", true + case 3393: + return "d2k-tapestry1", true + case 3394: + return "d2k-tapestry2", true + case 3395: + return "dyna-lm", true + case 3396: + return "printer-agent", true + case 3397: + return "cloanto-lm", true + case 3398: + return "mercantile", true + case 3399: + return "csms", true + case 3400: + return "csms2", true + case 3401: + return "filecast", true + case 3402: + return "fxaengine-net", true + case 3405: + return "nokia-ann-ch1", true + case 3406: + return "nokia-ann-ch2", true + case 3407: + return "ldap-admin", true + case 3408: + return "BESApi", true + case 3409: + return "networklens", true + case 3410: + return "networklenss", true + case 3411: + return "biolink-auth", true + case 3412: + return "xmlblaster", true + case 3413: + return "svnet", true + case 3414: + return "wip-port", true + case 3415: + return "bcinameservice", true + case 3416: + return "commandport", true + case 3417: + return "csvr", true + case 3418: + return "rnmap", true + case 3419: + return "softaudit", true + case 3420: + return "ifcp-port", true + case 3421: + return "bmap", true + case 3422: + return "rusb-sys-port", true + case 3423: + return "xtrm", true + case 3424: + return "xtrms", true + case 3425: + return "agps-port", true + case 3426: + return "arkivio", true + case 3427: + return "websphere-snmp", true + case 3428: + return "twcss", true + case 3429: + return "gcsp", true + case 3430: + return "ssdispatch", true + case 3431: + return "ndl-als", true + case 3432: + return "osdcp", true + case 3433: + return "opnet-smp", true + case 3434: + return "opencm", true + case 3435: + return "pacom", true + case 3436: + return "gc-config", true + case 3437: + return "autocueds", true + case 3438: + return "spiral-admin", true + case 3439: + return "hri-port", true + case 3440: + return "ans-console", true + case 3441: + return "connect-client", true + case 3442: + return "connect-server", true + case 3443: + return "ov-nnm-websrv", true + case 3444: + return "denali-server", true + case 3445: + return "monp", true + case 3446: + return "3comfaxrpc", true + case 3447: + return "directnet", true + case 3448: + return "dnc-port", true + case 3449: + return "hotu-chat", true + case 3450: + return "castorproxy", true + case 3451: + return "asam", true + case 3452: + return "sabp-signal", true + case 3453: + return "pscupd", true + case 3454: + return "mira", true + case 3455: + return "prsvp", true + case 3456: + return "vat", true + case 3457: + return "vat-control", true + case 3458: + return "d3winosfi", true + case 3459: + return "integral", true + case 3460: + return "edm-manager", true + case 3461: + return "edm-stager", true + case 3462: + return "edm-std-notify", true + case 3463: + return "edm-adm-notify", true + case 3464: + return "edm-mgr-sync", true + case 3465: + return "edm-mgr-cntrl", true + case 3466: + return "workflow", true + case 3467: + return "rcst", true + case 3468: + return "ttcmremotectrl", true + case 3469: + return "pluribus", true + case 3470: + return "jt400", true + case 3471: + return "jt400-ssl", true + case 3472: + return "jaugsremotec-1", true + case 3473: + return "jaugsremotec-2", true + case 3474: + return "ttntspauto", true + case 3475: + return "genisar-port", true + case 3476: + return "nppmp", true + case 3477: + return "ecomm", true + case 3478: + return "stun", true + case 3479: + return "twrpc", true + case 3480: + return "plethora", true + case 3481: + return "cleanerliverc", true + case 3482: + return "vulture", true + case 3483: + return "slim-devices", true + case 3484: + return "gbs-stp", true + case 3485: + return "celatalk", true + case 3486: + return "ifsf-hb-port", true + case 3487: + return "ltcudp", true + case 3488: + return "fs-rh-srv", true + case 3489: + return "dtp-dia", true + case 3490: + return "colubris", true + case 3491: + return "swr-port", true + case 3492: + return "tvdumtray-port", true + case 3493: + return "nut", true + case 3494: + return "ibm3494", true + case 3495: + return "seclayer-tcp", true + case 3496: + return "seclayer-tls", true + case 3497: + return "ipether232port", true + case 3498: + return "dashpas-port", true + case 3499: + return "sccip-media", true + case 3500: + return "rtmp-port", true + case 3501: + return "isoft-p2p", true + case 3502: + return "avinstalldisc", true + case 3503: + return "lsp-ping", true + case 3504: + return "ironstorm", true + case 3505: + return "ccmcomm", true + case 3506: + return "apc-3506", true + case 3507: + return "nesh-broker", true + case 3508: + return "interactionweb", true + case 3509: + return "vt-ssl", true + case 3510: + return "xss-port", true + case 3511: + return "webmail-2", true + case 3512: + return "aztec", true + case 3513: + return "arcpd", true + case 3514: + return "must-p2p", true + case 3515: + return "must-backplane", true + case 3516: + return "smartcard-port", true + case 3517: + return "802-11-iapp", true + case 3518: + return "artifact-msg", true + case 3519: + return "galileo", true + case 3520: + return "galileolog", true + case 3521: + return "mc3ss", true + case 3522: + return "nssocketport", true + case 3523: + return "odeumservlink", true + case 3524: + return "ecmport", true + case 3525: + return "eisport", true + case 3526: + return "starquiz-port", true + case 3527: + return "beserver-msg-q", true + case 3528: + return "jboss-iiop", true + case 3529: + return "jboss-iiop-ssl", true + case 3530: + return "gf", true + case 3531: + return "joltid", true + case 3532: + return "raven-rmp", true + case 3533: + return "raven-rdp", true + case 3534: + return "urld-port", true + case 3535: + return "ms-la", true + case 3536: + return "snac", true + case 3537: + return "ni-visa-remote", true + case 3538: + return "ibm-diradm", true + case 3539: + return "ibm-diradm-ssl", true + case 3540: + return "pnrp-port", true + case 3541: + return "voispeed-port", true + case 3542: + return "hacl-monitor", true + case 3543: + return "qftest-lookup", true + case 3544: + return "teredo", true + case 3545: + return "camac", true + case 3547: + return "symantec-sim", true + case 3548: + return "interworld", true + case 3549: + return "tellumat-nms", true + case 3550: + return "ssmpp", true + case 3551: + return "apcupsd", true + case 3552: + return "taserver", true + case 3553: + return "rbr-discovery", true + case 3554: + return "questnotify", true + case 3555: + return "razor", true + case 3556: + return "sky-transport", true + case 3557: + return "personalos-001", true + case 3558: + return "mcp-port", true + case 3559: + return "cctv-port", true + case 3560: + return "iniserve-port", true + case 3561: + return "bmc-onekey", true + case 3562: + return "sdbproxy", true + case 3563: + return "watcomdebug", true + case 3564: + return "esimport", true + case 3567: + return "dof-eps", true + case 3568: + return "dof-tunnel-sec", true + case 3569: + return "mbg-ctrl", true + case 3570: + return "mccwebsvr-port", true + case 3571: + return "megardsvr-port", true + case 3572: + return "megaregsvrport", true + case 3573: + return "tag-ups-1", true + case 3574: + return "dmaf-caster", true + case 3575: + return "ccm-port", true + case 3576: + return "cmc-port", true + case 3577: + return "config-port", true + case 3578: + return "data-port", true + case 3579: + return "ttat3lb", true + case 3580: + return "nati-svrloc", true + case 3581: + return "kfxaclicensing", true + case 3582: + return "press", true + case 3583: + return "canex-watch", true + case 3584: + return "u-dbap", true + case 3585: + return "emprise-lls", true + case 3586: + return "emprise-lsc", true + case 3587: + return "p2pgroup", true + case 3588: + return "sentinel", true + case 3589: + return "isomair", true + case 3590: + return "wv-csp-sms", true + case 3591: + return "gtrack-server", true + case 3592: + return "gtrack-ne", true + case 3593: + return "bpmd", true + case 3594: + return "mediaspace", true + case 3595: + return "shareapp", true + case 3596: + return "iw-mmogame", true + case 3597: + return "a14", true + case 3598: + return "a15", true + case 3599: + return "quasar-server", true + case 3600: + return "trap-daemon", true + case 3601: + return "visinet-gui", true + case 3602: + return "infiniswitchcl", true + case 3603: + return "int-rcv-cntrl", true + case 3604: + return "bmc-jmx-port", true + case 3605: + return "comcam-io", true + case 3606: + return "splitlock", true + case 3607: + return "precise-i3", true + case 3608: + return "trendchip-dcp", true + case 3609: + return "cpdi-pidas-cm", true + case 3610: + return "echonet", true + case 3611: + return "six-degrees", true + case 3612: + return "dataprotector", true + case 3613: + return "alaris-disc", true + case 3614: + return "sigma-port", true + case 3615: + return "start-network", true + case 3616: + return "cd3o-protocol", true + case 3617: + return "sharp-server", true + case 3618: + return "aairnet-1", true + case 3619: + return "aairnet-2", true + case 3620: + return "ep-pcp", true + case 3621: + return "ep-nsp", true + case 3622: + return "ff-lr-port", true + case 3623: + return "haipe-discover", true + case 3624: + return "dist-upgrade", true + case 3625: + return "volley", true + case 3626: + return "bvcdaemon-port", true + case 3627: + return "jamserverport", true + case 3628: + return "ept-machine", true + case 3629: + return "escvpnet", true + case 3630: + return "cs-remote-db", true + case 3631: + return "cs-services", true + case 3632: + return "distcc", true + case 3633: + return "wacp", true + case 3634: + return "hlibmgr", true + case 3635: + return "sdo", true + case 3636: + return "servistaitsm", true + case 3637: + return "scservp", true + case 3638: + return "ehp-backup", true + case 3639: + return "xap-ha", true + case 3640: + return "netplay-port1", true + case 3641: + return "netplay-port2", true + case 3642: + return "juxml-port", true + case 3643: + return "audiojuggler", true + case 3644: + return "ssowatch", true + case 3645: + return "cyc", true + case 3646: + return "xss-srv-port", true + case 3647: + return "splitlock-gw", true + case 3648: + return "fjcp", true + case 3649: + return "nmmp", true + case 3650: + return "prismiq-plugin", true + case 3651: + return "xrpc-registry", true + case 3652: + return "vxcrnbuport", true + case 3653: + return "tsp", true + case 3654: + return "vaprtm", true + case 3655: + return "abatemgr", true + case 3656: + return "abatjss", true + case 3657: + return "immedianet-bcn", true + case 3658: + return "ps-ams", true + case 3659: + return "apple-sasl", true + case 3660: + return "can-nds-ssl", true + case 3661: + return "can-ferret-ssl", true + case 3662: + return "pserver", true + case 3663: + return "dtp", true + case 3664: + return "ups-engine", true + case 3665: + return "ent-engine", true + case 3666: + return "eserver-pap", true + case 3667: + return "infoexch", true + case 3668: + return "dell-rm-port", true + case 3669: + return "casanswmgmt", true + case 3670: + return "smile", true + case 3671: + return "efcp", true + case 3672: + return "lispworks-orb", true + case 3673: + return "mediavault-gui", true + case 3674: + return "wininstall-ipc", true + case 3675: + return "calltrax", true + case 3676: + return "va-pacbase", true + case 3677: + return "roverlog", true + case 3678: + return "ipr-dglt", true + case 3679: + return "Escale (Newton Dock)", true + case 3680: + return "npds-tracker", true + case 3681: + return "bts-x73", true + case 3682: + return "cas-mapi", true + case 3683: + return "bmc-ea", true + case 3684: + return "faxstfx-port", true + case 3685: + return "dsx-agent", true + case 3686: + return "tnmpv2", true + case 3687: + return "simple-push", true + case 3688: + return "simple-push-s", true + case 3689: + return "daap", true + case 3690: + return "svn", true + case 3691: + return "magaya-network", true + case 3692: + return "intelsync", true + case 3695: + return "bmc-data-coll", true + case 3696: + return "telnetcpcd", true + case 3697: + return "nw-license", true + case 3698: + return "sagectlpanel", true + case 3699: + return "kpn-icw", true + case 3700: + return "lrs-paging", true + case 3701: + return "netcelera", true + case 3702: + return "ws-discovery", true + case 3703: + return "adobeserver-3", true + case 3704: + return "adobeserver-4", true + case 3705: + return "adobeserver-5", true + case 3706: + return "rt-event", true + case 3707: + return "rt-event-s", true + case 3708: + return "sun-as-iiops", true + case 3709: + return "ca-idms", true + case 3710: + return "portgate-auth", true + case 3711: + return "edb-server2", true + case 3712: + return "sentinel-ent", true + case 3713: + return "tftps", true + case 3714: + return "delos-dms", true + case 3715: + return "anoto-rendezv", true + case 3716: + return "wv-csp-sms-cir", true + case 3717: + return "wv-csp-udp-cir", true + case 3718: + return "opus-services", true + case 3719: + return "itelserverport", true + case 3720: + return "ufastro-instr", true + case 3721: + return "xsync", true + case 3722: + return "xserveraid", true + case 3723: + return "sychrond", true + case 3724: + return "blizwow", true + case 3725: + return "na-er-tip", true + case 3726: + return "array-manager", true + case 3727: + return "e-mdu", true + case 3728: + return "e-woa", true + case 3729: + return "fksp-audit", true + case 3730: + return "client-ctrl", true + case 3731: + return "smap", true + case 3732: + return "m-wnn", true + case 3733: + return "multip-msg", true + case 3734: + return "synel-data", true + case 3735: + return "pwdis", true + case 3736: + return "rs-rmi", true + case 3738: + return "versatalk", true + case 3739: + return "launchbird-lm", true + case 3740: + return "heartbeat", true + case 3741: + return "wysdma", true + case 3742: + return "cst-port", true + case 3743: + return "ipcs-command", true + case 3744: + return "sasg", true + case 3745: + return "gw-call-port", true + case 3746: + return "linktest", true + case 3747: + return "linktest-s", true + case 3748: + return "webdata", true + case 3749: + return "cimtrak", true + case 3750: + return "cbos-ip-port", true + case 3751: + return "gprs-cube", true + case 3752: + return "vipremoteagent", true + case 3753: + return "nattyserver", true + case 3754: + return "timestenbroker", true + case 3755: + return "sas-remote-hlp", true + case 3756: + return "canon-capt", true + case 3757: + return "grf-port", true + case 3758: + return "apw-registry", true + case 3759: + return "exapt-lmgr", true + case 3760: + return "adtempusclient", true + case 3761: + return "gsakmp", true + case 3762: + return "gbs-smp", true + case 3763: + return "xo-wave", true + case 3764: + return "mni-prot-rout", true + case 3765: + return "rtraceroute", true + case 3767: + return "listmgr-port", true + case 3768: + return "rblcheckd", true + case 3769: + return "haipe-otnk", true + case 3770: + return "cindycollab", true + case 3771: + return "paging-port", true + case 3772: + return "ctp", true + case 3773: + return "ctdhercules", true + case 3774: + return "zicom", true + case 3775: + return "ispmmgr", true + case 3776: + return "dvcprov-port", true + case 3777: + return "jibe-eb", true + case 3778: + return "c-h-it-port", true + case 3779: + return "cognima", true + case 3780: + return "nnp", true + case 3781: + return "abcvoice-port", true + case 3782: + return "iso-tp0s", true + case 3783: + return "bim-pem", true + case 3784: + return "bfd-control", true + case 3785: + return "bfd-echo", true + case 3786: + return "upstriggervsw", true + case 3787: + return "fintrx", true + case 3788: + return "isrp-port", true + case 3789: + return "remotedeploy", true + case 3790: + return "quickbooksrds", true + case 3791: + return "tvnetworkvideo", true + case 3792: + return "sitewatch", true + case 3793: + return "dcsoftware", true + case 3794: + return "jaus", true + case 3795: + return "myblast", true + case 3796: + return "spw-dialer", true + case 3797: + return "idps", true + case 3798: + return "minilock", true + case 3799: + return "radius-dynauth", true + case 3800: + return "pwgpsi", true + case 3801: + return "ibm-mgr", true + case 3802: + return "vhd", true + case 3803: + return "soniqsync", true + case 3804: + return "iqnet-port", true + case 3805: + return "tcpdataserver", true + case 3806: + return "wsmlb", true + case 3807: + return "spugna", true + case 3808: + return "sun-as-iiops-ca", true + case 3809: + return "apocd", true + case 3810: + return "wlanauth", true + case 3811: + return "amp", true + case 3812: + return "neto-wol-server", true + case 3813: + return "rap-ip", true + case 3814: + return "neto-dcs", true + case 3815: + return "lansurveyorxml", true + case 3816: + return "sunlps-http", true + case 3817: + return "tapeware", true + case 3818: + return "crinis-hb", true + case 3819: + return "epl-slp", true + case 3820: + return "scp", true + case 3821: + return "pmcp", true + case 3822: + return "acp-discovery", true + case 3823: + return "acp-conduit", true + case 3824: + return "acp-policy", true + case 3825: + return "ffserver", true + case 3826: + return "warmux", true + case 3827: + return "netmpi", true + case 3828: + return "neteh", true + case 3829: + return "neteh-ext", true + case 3830: + return "cernsysmgmtagt", true + case 3831: + return "dvapps", true + case 3832: + return "xxnetserver", true + case 3833: + return "aipn-auth", true + case 3834: + return "spectardata", true + case 3835: + return "spectardb", true + case 3836: + return "markem-dcp", true + case 3837: + return "mkm-discovery", true + case 3838: + return "sos", true + case 3839: + return "amx-rms", true + case 3840: + return "flirtmitmir", true + case 3842: + return "nhci", true + case 3843: + return "quest-agent", true + case 3844: + return "rnm", true + case 3845: + return "v-one-spp", true + case 3846: + return "an-pcp", true + case 3847: + return "msfw-control", true + case 3848: + return "item", true + case 3849: + return "spw-dnspreload", true + case 3850: + return "qtms-bootstrap", true + case 3851: + return "spectraport", true + case 3852: + return "sse-app-config", true + case 3853: + return "sscan", true + case 3854: + return "stryker-com", true + case 3855: + return "opentrac", true + case 3856: + return "informer", true + case 3857: + return "trap-port", true + case 3858: + return "trap-port-mom", true + case 3859: + return "nav-port", true + case 3860: + return "sasp", true + case 3861: + return "winshadow-hd", true + case 3862: + return "giga-pocket", true + case 3863: + return "asap-udp", true + case 3865: + return "xpl", true + case 3866: + return "dzdaemon", true + case 3867: + return "dzoglserver", true + case 3869: + return "ovsam-mgmt", true + case 3870: + return "ovsam-d-agent", true + case 3871: + return "avocent-adsap", true + case 3872: + return "oem-agent", true + case 3873: + return "fagordnc", true + case 3874: + return "sixxsconfig", true + case 3875: + return "pnbscada", true + case 3876: + return "dl-agent", true + case 3877: + return "xmpcr-interface", true + case 3878: + return "fotogcad", true + case 3879: + return "appss-lm", true + case 3880: + return "igrs", true + case 3881: + return "idac", true + case 3882: + return "msdts1", true + case 3883: + return "vrpn", true + case 3884: + return "softrack-meter", true + case 3885: + return "topflow-ssl", true + case 3886: + return "nei-management", true + case 3887: + return "ciphire-data", true + case 3888: + return "ciphire-serv", true + case 3889: + return "dandv-tester", true + case 3890: + return "ndsconnect", true + case 3891: + return "rtc-pm-port", true + case 3892: + return "pcc-image-port", true + case 3893: + return "cgi-starapi", true + case 3894: + return "syam-agent", true + case 3895: + return "syam-smc", true + case 3896: + return "sdo-tls", true + case 3897: + return "sdo-ssh", true + case 3898: + return "senip", true + case 3899: + return "itv-control", true + case 3900: + return "udt-os", true + case 3901: + return "nimsh", true + case 3902: + return "nimaux", true + case 3903: + return "charsetmgr", true + case 3904: + return "omnilink-port", true + case 3905: + return "mupdate", true + case 3906: + return "topovista-data", true + case 3907: + return "imoguia-port", true + case 3908: + return "hppronetman", true + case 3909: + return "surfcontrolcpa", true + case 3910: + return "prnrequest", true + case 3911: + return "prnstatus", true + case 3912: + return "gbmt-stars", true + case 3913: + return "listcrt-port", true + case 3914: + return "listcrt-port-2", true + case 3915: + return "agcat", true + case 3916: + return "wysdmc", true + case 3917: + return "aftmux", true + case 3918: + return "pktcablemmcops", true + case 3919: + return "hyperip", true + case 3920: + return "exasoftport1", true + case 3921: + return "herodotus-net", true + case 3922: + return "sor-update", true + case 3923: + return "symb-sb-port", true + case 3924: + return "mpl-gprs-port", true + case 3925: + return "zmp", true + case 3926: + return "winport", true + case 3927: + return "natdataservice", true + case 3928: + return "netboot-pxe", true + case 3929: + return "smauth-port", true + case 3930: + return "syam-webserver", true + case 3931: + return "msr-plugin-port", true + case 3932: + return "dyn-site", true + case 3933: + return "plbserve-port", true + case 3934: + return "sunfm-port", true + case 3935: + return "sdp-portmapper", true + case 3936: + return "mailprox", true + case 3937: + return "dvbservdsc", true + case 3938: + return "dbcontrol-agent", true + case 3939: + return "aamp", true + case 3940: + return "xecp-node", true + case 3941: + return "homeportal-web", true + case 3942: + return "srdp", true + case 3943: + return "tig", true + case 3944: + return "sops", true + case 3945: + return "emcads", true + case 3946: + return "backupedge", true + case 3947: + return "ccp", true + case 3948: + return "apdap", true + case 3949: + return "drip", true + case 3950: + return "namemunge", true + case 3951: + return "pwgippfax", true + case 3952: + return "i3-sessionmgr", true + case 3953: + return "xmlink-connect", true + case 3954: + return "adrep", true + case 3955: + return "p2pcommunity", true + case 3956: + return "gvcp", true + case 3957: + return "mqe-broker", true + case 3958: + return "mqe-agent", true + case 3959: + return "treehopper", true + case 3960: + return "bess", true + case 3961: + return "proaxess", true + case 3962: + return "sbi-agent", true + case 3963: + return "thrp", true + case 3964: + return "sasggprs", true + case 3965: + return "ati-ip-to-ncpe", true + case 3966: + return "bflckmgr", true + case 3967: + return "ppsms", true + case 3968: + return "ianywhere-dbns", true + case 3969: + return "landmarks", true + case 3970: + return "lanrevagent", true + case 3971: + return "lanrevserver", true + case 3972: + return "iconp", true + case 3973: + return "progistics", true + case 3974: + return "xk22", true + case 3975: + return "airshot", true + case 3976: + return "opswagent", true + case 3977: + return "opswmanager", true + case 3978: + return "secure-cfg-svr", true + case 3979: + return "smwan", true + case 3981: + return "starfish", true + case 3982: + return "eis", true + case 3983: + return "eisp", true + case 3984: + return "mapper-nodemgr", true + case 3985: + return "mapper-mapethd", true + case 3986: + return "mapper-ws-ethd", true + case 3987: + return "centerline", true + case 3988: + return "dcs-config", true + case 3989: + return "bv-queryengine", true + case 3990: + return "bv-is", true + case 3991: + return "bv-smcsrv", true + case 3992: + return "bv-ds", true + case 3993: + return "bv-agent", true + case 3995: + return "iss-mgmt-ssl", true + case 3996: + return "abcsoftware", true + case 3997: + return "agentsease-db", true + case 3998: + return "dnx", true + case 3999: + return "nvcnet", true + case 4000: + return "terabase", true + case 4001: + return "newoak", true + case 4002: + return "pxc-spvr-ft", true + case 4003: + return "pxc-splr-ft", true + case 4004: + return "pxc-roid", true + case 4005: + return "pxc-pin", true + case 4006: + return "pxc-spvr", true + case 4007: + return "pxc-splr", true + case 4008: + return "netcheque", true + case 4009: + return "chimera-hwm", true + case 4010: + return "samsung-unidex", true + case 4011: + return "altserviceboot", true + case 4012: + return "pda-gate", true + case 4013: + return "acl-manager", true + case 4014: + return "taiclock", true + case 4015: + return "talarian-mcast1", true + case 4016: + return "talarian-mcast2", true + case 4017: + return "talarian-mcast3", true + case 4018: + return "talarian-mcast4", true + case 4019: + return "talarian-mcast5", true + case 4020: + return "trap", true + case 4021: + return "nexus-portal", true + case 4022: + return "dnox", true + case 4023: + return "esnm-zoning", true + case 4024: + return "tnp1-port", true + case 4025: + return "partimage", true + case 4026: + return "as-debug", true + case 4027: + return "bxp", true + case 4028: + return "dtserver-port", true + case 4029: + return "ip-qsig", true + case 4030: + return "jdmn-port", true + case 4031: + return "suucp", true + case 4032: + return "vrts-auth-port", true + case 4033: + return "sanavigator", true + case 4034: + return "ubxd", true + case 4035: + return "wap-push-http", true + case 4036: + return "wap-push-https", true + case 4037: + return "ravehd", true + case 4038: + return "fazzt-ptp", true + case 4039: + return "fazzt-admin", true + case 4040: + return "yo-main", true + case 4041: + return "houston", true + case 4042: + return "ldxp", true + case 4043: + return "nirp", true + case 4044: + return "ltp", true + case 4045: + return "npp", true + case 4046: + return "acp-proto", true + case 4047: + return "ctp-state", true + case 4049: + return "wafs", true + case 4050: + return "cisco-wafs", true + case 4051: + return "cppdp", true + case 4052: + return "interact", true + case 4053: + return "ccu-comm-1", true + case 4054: + return "ccu-comm-2", true + case 4055: + return "ccu-comm-3", true + case 4056: + return "lms", true + case 4057: + return "wfm", true + case 4058: + return "kingfisher", true + case 4059: + return "dlms-cosem", true + case 4060: + return "dsmeter-iatc", true + case 4061: + return "ice-location", true + case 4062: + return "ice-slocation", true + case 4063: + return "ice-router", true + case 4064: + return "ice-srouter", true + case 4065: + return "avanti-cdp", true + case 4066: + return "pmas", true + case 4067: + return "idp", true + case 4068: + return "ipfltbcst", true + case 4069: + return "minger", true + case 4070: + return "tripe", true + case 4071: + return "aibkup", true + case 4072: + return "zieto-sock", true + case 4073: + return "iRAPP", true + case 4074: + return "cequint-cityid", true + case 4075: + return "perimlan", true + case 4076: + return "seraph", true + case 4077: + return "ascomalarm", true + case 4079: + return "santools", true + case 4080: + return "lorica-in", true + case 4081: + return "lorica-in-sec", true + case 4082: + return "lorica-out", true + case 4083: + return "lorica-out-sec", true + case 4084: + return "fortisphere-vm", true + case 4086: + return "ftsync", true + case 4089: + return "opencore", true + case 4090: + return "omasgport", true + case 4091: + return "ewinstaller", true + case 4092: + return "ewdgs", true + case 4093: + return "pvxpluscs", true + case 4094: + return "sysrqd", true + case 4095: + return "xtgui", true + case 4096: + return "bre", true + case 4097: + return "patrolview", true + case 4098: + return "drmsfsd", true + case 4099: + return "dpcp", true + case 4100: + return "igo-incognito", true + case 4101: + return "brlp-0", true + case 4102: + return "brlp-1", true + case 4103: + return "brlp-2", true + case 4104: + return "brlp-3", true + case 4105: + return "shofar", true + case 4106: + return "synchronite", true + case 4107: + return "j-ac", true + case 4108: + return "accel", true + case 4109: + return "izm", true + case 4110: + return "g2tag", true + case 4111: + return "xgrid", true + case 4112: + return "apple-vpns-rp", true + case 4113: + return "aipn-reg", true + case 4114: + return "jomamqmonitor", true + case 4115: + return "cds", true + case 4116: + return "smartcard-tls", true + case 4117: + return "hillrserv", true + case 4118: + return "netscript", true + case 4119: + return "assuria-slm", true + case 4121: + return "e-builder", true + case 4122: + return "fprams", true + case 4123: + return "z-wave", true + case 4124: + return "tigv2", true + case 4125: + return "opsview-envoy", true + case 4126: + return "ddrepl", true + case 4127: + return "unikeypro", true + case 4128: + return "nufw", true + case 4129: + return "nuauth", true + case 4130: + return "fronet", true + case 4131: + return "stars", true + case 4132: + return "nuts-dem", true + case 4133: + return "nuts-bootp", true + case 4134: + return "nifty-hmi", true + case 4135: + return "cl-db-attach", true + case 4136: + return "cl-db-request", true + case 4137: + return "cl-db-remote", true + case 4138: + return "nettest", true + case 4139: + return "thrtx", true + case 4140: + return "cedros-fds", true + case 4141: + return "oirtgsvc", true + case 4142: + return "oidocsvc", true + case 4143: + return "oidsr", true + case 4145: + return "vvr-control", true + case 4146: + return "tgcconnect", true + case 4147: + return "vrxpservman", true + case 4148: + return "hhb-handheld", true + case 4149: + return "agslb", true + case 4150: + return "PowerAlert-nsa", true + case 4151: + return "menandmice-noh", true + case 4152: + return "idig-mux", true + case 4153: + return "mbl-battd", true + case 4154: + return "atlinks", true + case 4155: + return "bzr", true + case 4156: + return "stat-results", true + case 4157: + return "stat-scanner", true + case 4158: + return "stat-cc", true + case 4159: + return "nss", true + case 4160: + return "jini-discovery", true + case 4161: + return "omscontact", true + case 4162: + return "omstopology", true + case 4163: + return "silverpeakpeer", true + case 4164: + return "silverpeakcomm", true + case 4165: + return "altcp", true + case 4166: + return "joost", true + case 4167: + return "ddgn", true + case 4168: + return "pslicser", true + case 4169: + return "iadt-disc", true + case 4172: + return "pcoip", true + case 4173: + return "mma-discovery", true + case 4174: + return "sm-disc", true + case 4177: + return "wello", true + case 4178: + return "storman", true + case 4179: + return "MaxumSP", true + case 4180: + return "httpx", true + case 4181: + return "macbak", true + case 4182: + return "pcptcpservice", true + case 4183: + return "cyborgnet", true + case 4184: + return "universe-suite", true + case 4185: + return "wcpp", true + case 4188: + return "vatata", true + case 4191: + return "dsmipv6", true + case 4192: + return "azeti-bd", true + case 4195: + return "aws-wsp", true + case 4197: + return "hctl", true + case 4199: + return "eims-admin", true + case 4300: + return "corelccam", true + case 4301: + return "d-data", true + case 4302: + return "d-data-control", true + case 4303: + return "srcp", true + case 4304: + return "owserver", true + case 4305: + return "batman", true + case 4306: + return "pinghgl", true + case 4307: + return "trueconf", true + case 4308: + return "compx-lockview", true + case 4309: + return "dserver", true + case 4310: + return "mirrtex", true + case 4319: + return "fox-skytale", true + case 4320: + return "fdt-rcatp", true + case 4321: + return "rwhois", true + case 4322: + return "trim-event", true + case 4323: + return "trim-ice", true + case 4325: + return "geognosisman", true + case 4326: + return "geognosis", true + case 4327: + return "jaxer-web", true + case 4328: + return "jaxer-manager", true + case 4333: + return "ahsp", true + case 4340: + return "gaia", true + case 4341: + return "lisp-data", true + case 4342: + return "lisp-control", true + case 4343: + return "unicall", true + case 4344: + return "vinainstall", true + case 4345: + return "m4-network-as", true + case 4346: + return "elanlm", true + case 4347: + return "lansurveyor", true + case 4348: + return "itose", true + case 4349: + return "fsportmap", true + case 4350: + return "net-device", true + case 4351: + return "plcy-net-svcs", true + case 4352: + return "pjlink", true + case 4353: + return "f5-iquery", true + case 4354: + return "qsnet-trans", true + case 4355: + return "qsnet-workst", true + case 4356: + return "qsnet-assist", true + case 4357: + return "qsnet-cond", true + case 4358: + return "qsnet-nucl", true + case 4359: + return "omabcastltkm", true + case 4361: + return "nacnl", true + case 4362: + return "afore-vdp-disc", true + case 4366: + return "shadowstream", true + case 4368: + return "wxbrief", true + case 4369: + return "epmd", true + case 4370: + return "elpro-tunnel", true + case 4371: + return "l2c-disc", true + case 4372: + return "l2c-data", true + case 4373: + return "remctl", true + case 4375: + return "tolteces", true + case 4376: + return "bip", true + case 4377: + return "cp-spxsvr", true + case 4378: + return "cp-spxdpy", true + case 4379: + return "ctdb", true + case 4389: + return "xandros-cms", true + case 4390: + return "wiegand", true + case 4394: + return "apwi-disc", true + case 4395: + return "omnivisionesx", true + case 4400: + return "ds-srv", true + case 4401: + return "ds-srvr", true + case 4402: + return "ds-clnt", true + case 4403: + return "ds-user", true + case 4404: + return "ds-admin", true + case 4405: + return "ds-mail", true + case 4406: + return "ds-slp", true + case 4412: + return "smallchat", true + case 4413: + return "avi-nms-disc", true + case 4416: + return "pjj-player-disc", true + case 4418: + return "axysbridge", true + case 4420: + return "nvme", true + case 4425: + return "netrockey6", true + case 4426: + return "beacon-port-2", true + case 4430: + return "rsqlserver", true + case 4432: + return "l-acoustics", true + case 4441: + return "netblox", true + case 4442: + return "saris", true + case 4443: + return "pharos", true + case 4444: + return "krb524", true + case 4445: + return "upnotifyp", true + case 4446: + return "n1-fwp", true + case 4447: + return "n1-rmgmt", true + case 4448: + return "asc-slmd", true + case 4449: + return "privatewire", true + case 4450: + return "camp", true + case 4451: + return "ctisystemmsg", true + case 4452: + return "ctiprogramload", true + case 4453: + return "nssalertmgr", true + case 4454: + return "nssagentmgr", true + case 4455: + return "prchat-user", true + case 4456: + return "prchat-server", true + case 4457: + return "prRegister", true + case 4458: + return "mcp", true + case 4484: + return "hpssmgmt", true + case 4486: + return "icms", true + case 4488: + return "awacs-ice", true + case 4500: + return "ipsec-nat-t", true + case 4534: + return "armagetronad", true + case 4535: + return "ehs", true + case 4536: + return "ehs-ssl", true + case 4537: + return "wssauthsvc", true + case 4538: + return "swx-gate", true + case 4545: + return "worldscores", true + case 4546: + return "sf-lm", true + case 4547: + return "lanner-lm", true + case 4548: + return "synchromesh", true + case 4549: + return "aegate", true + case 4550: + return "gds-adppiw-db", true + case 4551: + return "ieee-mih", true + case 4552: + return "menandmice-mon", true + case 4554: + return "msfrs", true + case 4555: + return "rsip", true + case 4556: + return "dtn-bundle", true + case 4557: + return "mtcevrunqss", true + case 4558: + return "mtcevrunqman", true + case 4559: + return "hylafax", true + case 4566: + return "kwtc", true + case 4567: + return "tram", true + case 4568: + return "bmc-reporting", true + case 4569: + return "iax", true + case 4591: + return "l3t-at-an", true + case 4592: + return "hrpd-ith-at-an", true + case 4593: + return "ipt-anri-anri", true + case 4594: + return "ias-session", true + case 4595: + return "ias-paging", true + case 4596: + return "ias-neighbor", true + case 4597: + return "a21-an-1xbs", true + case 4598: + return "a16-an-an", true + case 4599: + return "a17-an-an", true + case 4600: + return "piranha1", true + case 4601: + return "piranha2", true + case 4621: + return "ventoso", true + case 4646: + return "dots-signal", true + case 4658: + return "playsta2-app", true + case 4659: + return "playsta2-lob", true + case 4660: + return "smaclmgr", true + case 4661: + return "kar2ouche", true + case 4662: + return "oms", true + case 4663: + return "noteit", true + case 4664: + return "ems", true + case 4665: + return "contclientms", true + case 4666: + return "eportcomm", true + case 4667: + return "mmacomm", true + case 4668: + return "mmaeds", true + case 4669: + return "eportcommdata", true + case 4670: + return "light", true + case 4671: + return "acter", true + case 4672: + return "rfa", true + case 4673: + return "cxws", true + case 4674: + return "appiq-mgmt", true + case 4675: + return "dhct-status", true + case 4676: + return "dhct-alerts", true + case 4677: + return "bcs", true + case 4678: + return "traversal", true + case 4679: + return "mgesupervision", true + case 4680: + return "mgemanagement", true + case 4681: + return "parliant", true + case 4682: + return "finisar", true + case 4683: + return "spike", true + case 4684: + return "rfid-rp1", true + case 4685: + return "autopac", true + case 4686: + return "msp-os", true + case 4687: + return "nst", true + case 4688: + return "mobile-p2p", true + case 4689: + return "altovacentral", true + case 4690: + return "prelude", true + case 4691: + return "mtn", true + case 4692: + return "conspiracy", true + case 4700: + return "netxms-agent", true + case 4701: + return "netxms-mgmt", true + case 4702: + return "netxms-sync", true + case 4711: + return "trinity-dist", true + case 4725: + return "truckstar", true + case 4726: + return "a26-fap-fgw", true + case 4727: + return "fcis-disc", true + case 4728: + return "capmux", true + case 4729: + return "gsmtap", true + case 4730: + return "gearman", true + case 4732: + return "ohmtrigger", true + case 4737: + return "ipdr-sp", true + case 4738: + return "solera-lpn", true + case 4739: + return "ipfix", true + case 4740: + return "ipfixs", true + case 4741: + return "lumimgrd", true + case 4742: + return "sicct-sdp", true + case 4743: + return "openhpid", true + case 4744: + return "ifsp", true + case 4745: + return "fmp", true + case 4746: + return "intelliadm-disc", true + case 4747: + return "buschtrommel", true + case 4749: + return "profilemac", true + case 4750: + return "ssad", true + case 4751: + return "spocp", true + case 4752: + return "snap", true + case 4753: + return "simon-disc", true + case 4754: + return "gre-in-udp", true + case 4755: + return "gre-udp-dtls", true + case 4784: + return "bfd-multi-ctl", true + case 4785: + return "cncp", true + case 4789: + return "vxlan", true + case 4790: + return "vxlan-gpe", true + case 4791: + return "roce", true + case 4792: + return "unified-bus", true + case 4800: + return "iims", true + case 4801: + return "iwec", true + case 4802: + return "ilss", true + case 4803: + return "notateit-disc", true + case 4804: + return "aja-ntv4-disc", true + case 4827: + return "htcp", true + case 4837: + return "varadero-0", true + case 4838: + return "varadero-1", true + case 4839: + return "varadero-2", true + case 4840: + return "opcua-udp", true + case 4841: + return "quosa", true + case 4842: + return "gw-asv", true + case 4843: + return "opcua-tls", true + case 4844: + return "gw-log", true + case 4845: + return "wcr-remlib", true + case 4846: + return "contamac-icm", true + case 4847: + return "wfc", true + case 4848: + return "appserv-http", true + case 4849: + return "appserv-https", true + case 4850: + return "sun-as-nodeagt", true + case 4851: + return "derby-repli", true + case 4867: + return "unify-debug", true + case 4868: + return "phrelay", true + case 4869: + return "phrelaydbg", true + case 4870: + return "cc-tracking", true + case 4871: + return "wired", true + case 4876: + return "tritium-can", true + case 4877: + return "lmcs", true + case 4878: + return "inst-discovery", true + case 4881: + return "socp-t", true + case 4882: + return "socp-c", true + case 4884: + return "hivestor", true + case 4885: + return "abbs", true + case 4894: + return "lyskom", true + case 4899: + return "radmin-port", true + case 4900: + return "hfcs", true + case 4914: + return "bones", true + case 4936: + return "an-signaling", true + case 4937: + return "atsc-mh-ssc", true + case 4940: + return "eq-office-4940", true + case 4941: + return "eq-office-4941", true + case 4942: + return "eq-office-4942", true + case 4949: + return "munin", true + case 4950: + return "sybasesrvmon", true + case 4951: + return "pwgwims", true + case 4952: + return "sagxtsds", true + case 4969: + return "ccss-qmm", true + case 4970: + return "ccss-qsm", true + case 4980: + return "ctxs-vpp", true + case 4986: + return "mrip", true + case 4987: + return "smar-se-port1", true + case 4988: + return "smar-se-port2", true + case 4989: + return "parallel", true + case 4990: + return "busycal", true + case 4991: + return "vrt", true + case 4999: + return "hfcs-manager", true + case 5000: + return "commplex-main", true + case 5001: + return "commplex-link", true + case 5002: + return "rfe", true + case 5003: + return "fmpro-internal", true + case 5004: + return "avt-profile-1", true + case 5005: + return "avt-profile-2", true + case 5006: + return "wsm-server", true + case 5007: + return "wsm-server-ssl", true + case 5008: + return "synapsis-edge", true + case 5009: + return "winfs", true + case 5010: + return "telelpathstart", true + case 5011: + return "telelpathattack", true + case 5012: + return "nsp", true + case 5013: + return "fmpro-v6", true + case 5014: + return "onpsocket", true + case 5020: + return "zenginkyo-1", true + case 5021: + return "zenginkyo-2", true + case 5022: + return "mice", true + case 5023: + return "htuilsrv", true + case 5024: + return "scpi-telnet", true + case 5025: + return "scpi-raw", true + case 5026: + return "strexec-d", true + case 5027: + return "strexec-s", true + case 5029: + return "infobright", true + case 5031: + return "dmp", true + case 5042: + return "asnaacceler8db", true + case 5043: + return "swxadmin", true + case 5044: + return "lxi-evntsvc", true + case 5046: + return "vpm-udp", true + case 5047: + return "iscape", true + case 5049: + return "ivocalize", true + case 5050: + return "mmcc", true + case 5051: + return "ita-agent", true + case 5052: + return "ita-manager", true + case 5053: + return "rlm-disc", true + case 5055: + return "unot", true + case 5056: + return "intecom-ps1", true + case 5057: + return "intecom-ps2", true + case 5058: + return "locus-disc", true + case 5059: + return "sds", true + case 5060: + return "sip", true + case 5061: + return "sips", true + case 5062: + return "na-localise", true + case 5064: + return "ca-1", true + case 5065: + return "ca-2", true + case 5066: + return "stanag-5066", true + case 5067: + return "authentx", true + case 5069: + return "i-net-2000-npr", true + case 5070: + return "vtsas", true + case 5071: + return "powerschool", true + case 5072: + return "ayiya", true + case 5073: + return "tag-pm", true + case 5074: + return "alesquery", true + case 5078: + return "pixelpusher", true + case 5079: + return "cp-spxrpts", true + case 5080: + return "onscreen", true + case 5081: + return "sdl-ets", true + case 5082: + return "qcp", true + case 5083: + return "qfp", true + case 5084: + return "llrp", true + case 5085: + return "encrypted-llrp", true + case 5092: + return "magpie", true + case 5093: + return "sentinel-lm", true + case 5094: + return "hart-ip", true + case 5099: + return "sentlm-srv2srv", true + case 5100: + return "socalia", true + case 5101: + return "talarian-udp", true + case 5102: + return "oms-nonsecure", true + case 5104: + return "tinymessage", true + case 5105: + return "hughes-ap", true + case 5111: + return "taep-as-svc", true + case 5112: + return "pm-cmdsvr", true + case 5116: + return "emb-proj-cmd", true + case 5120: + return "barracuda-bbs", true + case 5133: + return "nbt-pc", true + case 5136: + return "minotaur-sa", true + case 5137: + return "ctsd", true + case 5145: + return "rmonitor-secure", true + case 5150: + return "atmp", true + case 5151: + return "esri-sde", true + case 5152: + return "sde-discovery", true + case 5154: + return "bzflag", true + case 5155: + return "asctrl-agent", true + case 5164: + return "vpa-disc", true + case 5165: + return "ife-icorp", true + case 5166: + return "winpcs", true + case 5167: + return "scte104", true + case 5168: + return "scte30", true + case 5190: + return "aol", true + case 5191: + return "aol-1", true + case 5192: + return "aol-2", true + case 5193: + return "aol-3", true + case 5200: + return "targus-getdata", true + case 5201: + return "targus-getdata1", true + case 5202: + return "targus-getdata2", true + case 5203: + return "targus-getdata3", true + case 5223: + return "hpvirtgrp", true + case 5224: + return "hpvirtctrl", true + case 5225: + return "hp-server", true + case 5226: + return "hp-status", true + case 5227: + return "perfd", true + case 5234: + return "eenet", true + case 5235: + return "galaxy-network", true + case 5236: + return "padl2sim", true + case 5237: + return "mnet-discovery", true + case 5245: + return "downtools-disc", true + case 5246: + return "capwap-control", true + case 5247: + return "capwap-data", true + case 5248: + return "caacws", true + case 5249: + return "caaclang2", true + case 5250: + return "soagateway", true + case 5251: + return "caevms", true + case 5252: + return "movaz-ssc", true + case 5264: + return "3com-njack-1", true + case 5265: + return "3com-njack-2", true + case 5270: + return "cartographerxmp", true + case 5271: + return "cuelink-disc", true + case 5272: + return "pk", true + case 5282: + return "transmit-port", true + case 5298: + return "presence", true + case 5299: + return "nlg-data", true + case 5300: + return "hacl-hb", true + case 5301: + return "hacl-gs", true + case 5302: + return "hacl-cfg", true + case 5303: + return "hacl-probe", true + case 5304: + return "hacl-local", true + case 5305: + return "hacl-test", true + case 5306: + return "sun-mc-grp", true + case 5307: + return "sco-aip", true + case 5308: + return "cfengine", true + case 5309: + return "jprinter", true + case 5310: + return "outlaws", true + case 5312: + return "permabit-cs", true + case 5313: + return "rrdp", true + case 5314: + return "opalis-rbt-ipc", true + case 5315: + return "hacl-poll", true + case 5343: + return "kfserver", true + case 5344: + return "xkotodrcp", true + case 5349: + return "stuns", true + case 5350: + return "pcp-multicast", true + case 5351: + return "pcp", true + case 5352: + return "dns-llq", true + case 5353: + return "mdns", true + case 5354: + return "mdnsresponder", true + case 5355: + return "llmnr", true + case 5356: + return "ms-smlbiz", true + case 5357: + return "wsdapi", true + case 5358: + return "wsdapi-s", true + case 5359: + return "ms-alerter", true + case 5360: + return "ms-sideshow", true + case 5361: + return "ms-s-sideshow", true + case 5362: + return "serverwsd2", true + case 5363: + return "net-projection", true + case 5364: + return "kdnet", true + case 5397: + return "stresstester", true + case 5398: + return "elektron-admin", true + case 5399: + return "securitychase", true + case 5400: + return "excerpt", true + case 5401: + return "excerpts", true + case 5402: + return "mftp", true + case 5403: + return "hpoms-ci-lstn", true + case 5404: + return "hpoms-dps-lstn", true + case 5405: + return "netsupport", true + case 5406: + return "systemics-sox", true + case 5407: + return "foresyte-clear", true + case 5408: + return "foresyte-sec", true + case 5409: + return "salient-dtasrv", true + case 5410: + return "salient-usrmgr", true + case 5411: + return "actnet", true + case 5412: + return "continuus", true + case 5413: + return "wwiotalk", true + case 5414: + return "statusd", true + case 5415: + return "ns-server", true + case 5416: + return "sns-gateway", true + case 5417: + return "sns-agent", true + case 5418: + return "mcntp", true + case 5419: + return "dj-ice", true + case 5420: + return "cylink-c", true + case 5421: + return "netsupport2", true + case 5422: + return "salient-mux", true + case 5423: + return "virtualuser", true + case 5424: + return "beyond-remote", true + case 5425: + return "br-channel", true + case 5426: + return "devbasic", true + case 5427: + return "sco-peer-tta", true + case 5428: + return "telaconsole", true + case 5429: + return "base", true + case 5430: + return "radec-corp", true + case 5431: + return "park-agent", true + case 5432: + return "postgresql", true + case 5433: + return "pyrrho", true + case 5434: + return "sgi-arrayd", true + case 5435: + return "sceanics", true + case 5436: + return "pmip6-cntl", true + case 5437: + return "pmip6-data", true + case 5443: + return "spss", true + case 5450: + return "tiepie-disc", true + case 5453: + return "surebox", true + case 5454: + return "apc-5454", true + case 5455: + return "apc-5455", true + case 5456: + return "apc-5456", true + case 5461: + return "silkmeter", true + case 5462: + return "ttl-publisher", true + case 5463: + return "ttlpriceproxy", true + case 5464: + return "quailnet", true + case 5465: + return "netops-broker", true + case 5474: + return "apsolab-rpc", true + case 5500: + return "fcp-addr-srvr1", true + case 5501: + return "fcp-addr-srvr2", true + case 5502: + return "fcp-srvr-inst1", true + case 5503: + return "fcp-srvr-inst2", true + case 5504: + return "fcp-cics-gw1", true + case 5505: + return "checkoutdb", true + case 5506: + return "amc", true + case 5540: + return "matter", true + case 5553: + return "sgi-eventmond", true + case 5554: + return "sgi-esphttp", true + case 5555: + return "personal-agent", true + case 5556: + return "freeciv", true + case 5567: + return "dof-dps-mc-sec", true + case 5568: + return "sdt", true + case 5569: + return "rdmnet-device", true + case 5573: + return "sdmmp", true + case 5580: + return "tmosms0", true + case 5581: + return "tmosms1", true + case 5582: + return "fac-restore", true + case 5583: + return "tmo-icon-sync", true + case 5584: + return "bis-web", true + case 5585: + return "bis-sync", true + case 5597: + return "ininmessaging", true + case 5598: + return "mctfeed", true + case 5599: + return "esinstall", true + case 5600: + return "esmmanager", true + case 5601: + return "esmagent", true + case 5602: + return "a1-msc", true + case 5603: + return "a1-bs", true + case 5604: + return "a3-sdunode", true + case 5605: + return "a4-sdunode", true + case 5627: + return "ninaf", true + case 5628: + return "htrust", true + case 5629: + return "symantec-sfdb", true + case 5630: + return "precise-comm", true + case 5631: + return "pcanywheredata", true + case 5632: + return "pcanywherestat", true + case 5633: + return "beorl", true + case 5634: + return "xprtld", true + case 5670: + return "zre-disc", true + case 5671: + return "amqps", true + case 5672: + return "amqp", true + case 5673: + return "jms", true + case 5674: + return "hyperscsi-port", true + case 5675: + return "v5ua", true + case 5676: + return "raadmin", true + case 5677: + return "questdb2-lnchr", true + case 5678: + return "rrac", true + case 5679: + return "dccm", true + case 5680: + return "auriga-router", true + case 5681: + return "ncxcp", true + case 5682: + return "brightcore", true + case 5683: + return "coap", true + case 5684: + return "coaps", true + case 5687: + return "gog-multiplayer", true + case 5688: + return "ggz", true + case 5689: + return "qmvideo", true + case 5713: + return "proshareaudio", true + case 5714: + return "prosharevideo", true + case 5715: + return "prosharedata", true + case 5716: + return "prosharerequest", true + case 5717: + return "prosharenotify", true + case 5718: + return "dpm", true + case 5719: + return "dpm-agent", true + case 5720: + return "ms-licensing", true + case 5721: + return "dtpt", true + case 5722: + return "msdfsr", true + case 5723: + return "omhs", true + case 5724: + return "omsdk", true + case 5728: + return "io-dist-group", true + case 5729: + return "openmail", true + case 5730: + return "unieng", true + case 5741: + return "ida-discover1", true + case 5742: + return "ida-discover2", true + case 5743: + return "watchdoc-pod", true + case 5744: + return "watchdoc", true + case 5745: + return "fcopy-server", true + case 5746: + return "fcopys-server", true + case 5747: + return "tunatic", true + case 5748: + return "tunalyzer", true + case 5750: + return "rscd", true + case 5755: + return "openmailg", true + case 5757: + return "x500ms", true + case 5766: + return "openmailns", true + case 5767: + return "s-openmail", true + case 5768: + return "openmailpxy", true + case 5769: + return "spramsca", true + case 5770: + return "spramsd", true + case 5771: + return "netagent", true + case 5777: + return "starfield-io", true + case 5781: + return "3par-evts", true + case 5782: + return "3par-mgmt", true + case 5783: + return "3par-mgmt-ssl", true + case 5784: + return "ibar", true + case 5785: + return "3par-rcopy", true + case 5786: + return "cisco-redu", true + case 5787: + return "waascluster", true + case 5793: + return "xtreamx", true + case 5794: + return "spdp", true + case 5813: + return "icmpd", true + case 5814: + return "spt-automation", true + case 5859: + return "wherehoo", true + case 5863: + return "ppsuitemsg", true + case 5900: + return "rfb", true + case 5903: + return "ff-ice", true + case 5904: + return "ag-swim", true + case 5905: + return "asmgcs", true + case 5906: + return "rpas-c2", true + case 5907: + return "dsd", true + case 5908: + return "ipsma", true + case 5909: + return "agma", true + case 5910: + return "ats-atn", true + case 5911: + return "ats-acars", true + case 5912: + return "ais-met", true + case 5913: + return "aoc-acars", true + case 5963: + return "indy", true + case 5968: + return "mppolicy-v5", true + case 5969: + return "mppolicy-mgr", true + case 5984: + return "couchdb", true + case 5985: + return "wsman", true + case 5986: + return "wsmans", true + case 5987: + return "wbem-rmi", true + case 5988: + return "wbem-http", true + case 5989: + return "wbem-https", true + case 5990: + return "wbem-exp-https", true + case 5991: + return "nuxsl", true + case 5992: + return "consul-insight", true + case 5999: + return "cvsup", true + case 6064: + return "ndl-ahp-svc", true + case 6065: + return "winpharaoh", true + case 6066: + return "ewctsp", true + case 6069: + return "trip", true + case 6070: + return "messageasap", true + case 6071: + return "ssdtp", true + case 6072: + return "diagnose-proc", true + case 6073: + return "directplay8", true + case 6074: + return "max", true + case 6080: + return "gue", true + case 6081: + return "geneve", true + case 6082: + return "p25cai", true + case 6083: + return "miami-bcast", true + case 6085: + return "konspire2b", true + case 6086: + return "pdtp", true + case 6087: + return "ldss", true + case 6088: + return "doglms-notify", true + case 6100: + return "synchronet-db", true + case 6101: + return "synchronet-rtc", true + case 6102: + return "synchronet-upd", true + case 6103: + return "rets", true + case 6104: + return "dbdb", true + case 6105: + return "primaserver", true + case 6106: + return "mpsserver", true + case 6107: + return "etc-control", true + case 6108: + return "sercomm-scadmin", true + case 6109: + return "globecast-id", true + case 6110: + return "softcm", true + case 6111: + return "spc", true + case 6112: + return "dtspcd", true + case 6118: + return "tipc", true + case 6122: + return "bex-webadmin", true + case 6123: + return "backup-express", true + case 6124: + return "pnbs", true + case 6133: + return "nbt-wol", true + case 6140: + return "pulsonixnls", true + case 6141: + return "meta-corp", true + case 6142: + return "aspentec-lm", true + case 6143: + return "watershed-lm", true + case 6144: + return "statsci1-lm", true + case 6145: + return "statsci2-lm", true + case 6146: + return "lonewolf-lm", true + case 6147: + return "montage-lm", true + case 6148: + return "ricardo-lm", true + case 6149: + return "tal-pod", true + case 6160: + return "ecmp-data", true + case 6161: + return "patrol-ism", true + case 6162: + return "patrol-coll", true + case 6163: + return "pscribe", true + case 6200: + return "lm-x", true + case 6201: + return "thermo-calc", true + case 6209: + return "qmtps", true + case 6222: + return "radmind", true + case 6241: + return "jeol-nsddp-1", true + case 6242: + return "jeol-nsddp-2", true + case 6243: + return "jeol-nsddp-3", true + case 6244: + return "jeol-nsddp-4", true + case 6251: + return "tl1-raw-ssl", true + case 6252: + return "tl1-ssh", true + case 6253: + return "crip", true + case 6268: + return "grid", true + case 6269: + return "grid-alt", true + case 6300: + return "bmc-grx", true + case 6301: + return "bmc-ctd-ldap", true + case 6306: + return "ufmp", true + case 6315: + return "scup-disc", true + case 6316: + return "abb-escp", true + case 6317: + return "nav-data", true + case 6320: + return "repsvc", true + case 6321: + return "emp-server1", true + case 6322: + return "emp-server2", true + case 6324: + return "hrd-ns-disc", true + case 6343: + return "sflow", true + case 6346: + return "gnutella-svc", true + case 6347: + return "gnutella-rtr", true + case 6350: + return "adap", true + case 6355: + return "pmcs", true + case 6360: + return "metaedit-mu", true + case 6363: + return "ndn", true + case 6370: + return "metaedit-se", true + case 6382: + return "metatude-mds", true + case 6389: + return "clariion-evr01", true + case 6390: + return "metaedit-ws", true + case 6417: + return "faxcomservice", true + case 6419: + return "svdrp-disc", true + case 6420: + return "nim-vdrshell", true + case 6421: + return "nim-wan", true + case 6443: + return "sun-sr-https", true + case 6444: + return "sge-qmaster", true + case 6445: + return "sge-execd", true + case 6446: + return "mysql-proxy", true + case 6455: + return "skip-cert-recv", true + case 6456: + return "skip-cert-send", true + case 6464: + return "ieee11073-20701", true + case 6471: + return "lvision-lm", true + case 6480: + return "sun-sr-http", true + case 6481: + return "servicetags", true + case 6482: + return "ldoms-mgmt", true + case 6483: + return "SunVTS-RMI", true + case 6484: + return "sun-sr-jms", true + case 6485: + return "sun-sr-iiop", true + case 6486: + return "sun-sr-iiops", true + case 6487: + return "sun-sr-iiop-aut", true + case 6488: + return "sun-sr-jmx", true + case 6489: + return "sun-sr-admin", true + case 6500: + return "boks", true + case 6501: + return "boks-servc", true + case 6502: + return "boks-servm", true + case 6503: + return "boks-clntd", true + case 6505: + return "badm-priv", true + case 6506: + return "badm-pub", true + case 6507: + return "bdir-priv", true + case 6508: + return "bdir-pub", true + case 6509: + return "mgcs-mfp-port", true + case 6510: + return "mcer-port", true + case 6511: + return "dccp-udp", true + case 6514: + return "syslog-tls", true + case 6515: + return "elipse-rec", true + case 6543: + return "lds-distrib", true + case 6544: + return "lds-dump", true + case 6547: + return "apc-6547", true + case 6548: + return "apc-6548", true + case 6549: + return "apc-6549", true + case 6550: + return "fg-sysupdate", true + case 6551: + return "sum", true + case 6558: + return "xdsxdm", true + case 6566: + return "sane-port", true + case 6568: + return "rp-reputation", true + case 6579: + return "affiliate", true + case 6580: + return "parsec-master", true + case 6581: + return "parsec-peer", true + case 6582: + return "parsec-game", true + case 6583: + return "joaJewelSuite", true + case 6619: + return "odette-ftps", true + case 6620: + return "kftp-data", true + case 6621: + return "kftp", true + case 6622: + return "mcftp", true + case 6623: + return "ktelnet", true + case 6626: + return "wago-service", true + case 6627: + return "nexgen", true + case 6628: + return "afesc-mc", true + case 6629: + return "nexgen-aux", true + case 6633: + return "cisco-vpath-tun", true + case 6634: + return "mpls-pm", true + case 6635: + return "mpls-udp", true + case 6636: + return "mpls-udp-dtls", true + case 6653: + return "openflow", true + case 6657: + return "palcom-disc", true + case 6670: + return "vocaltec-gold", true + case 6671: + return "p4p-portal", true + case 6672: + return "vision-server", true + case 6673: + return "vision-elmd", true + case 6678: + return "vfbp-disc", true + case 6679: + return "osaut", true + case 6689: + return "tsa", true + case 6696: + return "babel", true + case 6699: + return "babel-dtls", true + case 6701: + return "kti-icad-srvr", true + case 6702: + return "e-design-net", true + case 6703: + return "e-design-web", true + case 6714: + return "ibprotocol", true + case 6715: + return "fibotrader-com", true + case 6767: + return "bmc-perf-agent", true + case 6768: + return "bmc-perf-mgrd", true + case 6769: + return "adi-gxp-srvprt", true + case 6770: + return "plysrv-http", true + case 6771: + return "plysrv-https", true + case 6784: + return "bfd-lag", true + case 6785: + return "dgpf-exchg", true + case 6786: + return "smc-jmx", true + case 6787: + return "smc-admin", true + case 6788: + return "smc-http", true + case 6790: + return "hnmp", true + case 6791: + return "hnm", true + case 6801: + return "acnet", true + case 6831: + return "ambit-lm", true + case 6841: + return "netmo-default", true + case 6842: + return "netmo-http", true + case 6850: + return "iccrushmore", true + case 6868: + return "acctopus-st", true + case 6888: + return "muse", true + case 6924: + return "split-ping", true + case 6935: + return "ethoscan", true + case 6936: + return "xsmsvc", true + case 6946: + return "bioserver", true + case 6951: + return "otlp", true + case 6961: + return "jmact3", true + case 6962: + return "jmevt2", true + case 6963: + return "swismgr1", true + case 6964: + return "swismgr2", true + case 6965: + return "swistrap", true + case 6966: + return "swispol", true + case 6969: + return "acmsoda", true + case 6980: + return "qolyester", true + case 6997: + return "MobilitySrv", true + case 6998: + return "iatp-highpri", true + case 6999: + return "iatp-normalpri", true + case 7000: + return "afs3-fileserver", true + case 7001: + return "afs3-callback", true + case 7002: + return "afs3-prserver", true + case 7003: + return "afs3-vlserver", true + case 7004: + return "afs3-kaserver", true + case 7005: + return "afs3-volser", true + case 7006: + return "afs3-errors", true + case 7007: + return "afs3-bos", true + case 7008: + return "afs3-update", true + case 7009: + return "afs3-rmtsys", true + case 7010: + return "ups-onlinet", true + case 7011: + return "talon-disc", true + case 7012: + return "talon-engine", true + case 7013: + return "microtalon-dis", true + case 7014: + return "microtalon-com", true + case 7015: + return "talon-webserver", true + case 7016: + return "spg", true + case 7017: + return "grasp", true + case 7019: + return "doceri-view", true + case 7020: + return "dpserve", true + case 7021: + return "dpserveadmin", true + case 7022: + return "ctdp", true + case 7023: + return "ct2nmcs", true + case 7024: + return "vmsvc", true + case 7025: + return "vmsvc-2", true + case 7030: + return "op-probe", true + case 7040: + return "quest-disc", true + case 7070: + return "arcp", true + case 7071: + return "iwg1", true + case 7072: + return "iba-cfg-disc", true + case 7080: + return "empowerid", true + case 7088: + return "zixi-transport", true + case 7095: + return "jdp-disc", true + case 7099: + return "lazy-ptop", true + case 7100: + return "font-service", true + case 7101: + return "elcn", true + case 7107: + return "aes-x170", true + case 7121: + return "virprot-lm", true + case 7128: + return "scenidm", true + case 7129: + return "scenccs", true + case 7161: + return "cabsm-comm", true + case 7162: + return "caistoragemgr", true + case 7163: + return "cacsambroker", true + case 7164: + return "fsr", true + case 7165: + return "doc-server", true + case 7166: + return "aruba-server", true + case 7169: + return "ccag-pib", true + case 7170: + return "nsrp", true + case 7171: + return "drm-production", true + case 7174: + return "clutild", true + case 7181: + return "janus-disc", true + case 7200: + return "fodms", true + case 7201: + return "dlip", true + case 7227: + return "ramp", true + case 7235: + return "aspcoordination", true + case 7244: + return "frc-hicp-disc", true + case 7262: + return "cnap", true + case 7272: + return "watchme-7272", true + case 7273: + return "oma-rlp", true + case 7274: + return "oma-rlp-s", true + case 7275: + return "oma-ulp", true + case 7276: + return "oma-ilp", true + case 7277: + return "oma-ilp-s", true + case 7278: + return "oma-dcdocbs", true + case 7279: + return "ctxlic", true + case 7280: + return "itactionserver1", true + case 7281: + return "itactionserver2", true + case 7282: + return "mzca-alert", true + case 7365: + return "lcm-server", true + case 7391: + return "mindfilesys", true + case 7392: + return "mrssrendezvous", true + case 7393: + return "nfoldman", true + case 7394: + return "fse", true + case 7395: + return "winqedit", true + case 7397: + return "hexarc", true + case 7400: + return "rtps-discovery", true + case 7401: + return "rtps-dd-ut", true + case 7402: + return "rtps-dd-mt", true + case 7410: + return "ionixnetmon", true + case 7411: + return "daqstream", true + case 7420: + return "ipluminary", true + case 7421: + return "mtportmon", true + case 7426: + return "pmdmgr", true + case 7427: + return "oveadmgr", true + case 7428: + return "ovladmgr", true + case 7429: + return "opi-sock", true + case 7430: + return "xmpv7", true + case 7431: + return "pmd", true + case 7437: + return "faximum", true + case 7443: + return "oracleas-https", true + case 7473: + return "rise", true + case 7491: + return "telops-lmd", true + case 7500: + return "silhouette", true + case 7501: + return "ovbus", true + case 7510: + return "ovhpas", true + case 7511: + return "pafec-lm", true + case 7542: + return "saratoga", true + case 7543: + return "atul", true + case 7544: + return "nta-ds", true + case 7545: + return "nta-us", true + case 7546: + return "cfs", true + case 7547: + return "cwmp", true + case 7548: + return "tidp", true + case 7549: + return "nls-tl", true + case 7550: + return "cloudsignaling", true + case 7560: + return "sncp", true + case 7566: + return "vsi-omega", true + case 7570: + return "aries-kfinder", true + case 7574: + return "coherence-disc", true + case 7588: + return "sun-lm", true + case 7606: + return "mipi-debug", true + case 7624: + return "indi", true + case 7627: + return "soap-http", true + case 7628: + return "zen-pawn", true + case 7629: + return "xdas", true + case 7633: + return "pmdfmgt", true + case 7648: + return "cuseeme", true + case 7663: + return "rome", true + case 7674: + return "imqtunnels", true + case 7675: + return "imqtunnel", true + case 7676: + return "imqbrokerd", true + case 7677: + return "sun-user-https", true + case 7680: + return "ms-do", true + case 7689: + return "collaber", true + case 7697: + return "klio", true + case 7707: + return "sync-em7", true + case 7708: + return "scinet", true + case 7720: + return "medimageportal", true + case 7724: + return "nsdeepfreezectl", true + case 7725: + return "nitrogen", true + case 7726: + return "freezexservice", true + case 7727: + return "trident-data", true + case 7728: + return "osvr", true + case 7734: + return "smip", true + case 7738: + return "aiagent", true + case 7741: + return "scriptview", true + case 7743: + return "sstp-1", true + case 7744: + return "raqmon-pdu", true + case 7747: + return "prgp", true + case 7777: + return "cbt", true + case 7778: + return "interwise", true + case 7779: + return "vstat", true + case 7781: + return "accu-lmgr", true + case 7784: + return "s-bfd", true + case 7786: + return "minivend", true + case 7787: + return "popup-reminders", true + case 7789: + return "office-tools", true + case 7794: + return "q3ade", true + case 7797: + return "pnet-conn", true + case 7798: + return "pnet-enc", true + case 7799: + return "altbsdp", true + case 7800: + return "asr", true + case 7801: + return "ssp-client", true + case 7802: + return "vns-tp", true + case 7810: + return "rbt-wanopt", true + case 7845: + return "apc-7845", true + case 7846: + return "apc-7846", true + case 7872: + return "mipv6tls", true + case 7880: + return "pss", true + case 7887: + return "ubroker", true + case 7900: + return "mevent", true + case 7901: + return "tnos-sp", true + case 7902: + return "tnos-dp", true + case 7903: + return "tnos-dps", true + case 7913: + return "qo-secure", true + case 7932: + return "t2-drm", true + case 7933: + return "t2-brm", true + case 7962: + return "generalsync", true + case 7967: + return "supercell", true + case 7979: + return "micromuse-ncps", true + case 7980: + return "quest-vista", true + case 7982: + return "sossd-disc", true + case 7998: + return "usicontentpush", true + case 7999: + return "irdmi2", true + case 8000: + return "irdmi", true + case 8001: + return "vcom-tunnel", true + case 8002: + return "teradataordbms", true + case 8003: + return "mcreport", true + case 8005: + return "mxi", true + case 8006: + return "wpl-disc", true + case 8007: + return "warppipe", true + case 8008: + return "http-alt", true + case 8017: + return "cisco-cloudsec", true + case 8019: + return "qbdb", true + case 8020: + return "intu-ec-svcdisc", true + case 8021: + return "intu-ec-client", true + case 8022: + return "oa-system", true + case 8023: + return "arca-api", true + case 8025: + return "ca-audit-da", true + case 8026: + return "ca-audit-ds", true + case 8027: + return "papachi-p2p-srv", true + case 8032: + return "pro-ed", true + case 8033: + return "mindprint", true + case 8034: + return "vantronix-mgmt", true + case 8040: + return "ampify", true + case 8041: + return "enguity-xccetp", true + case 8052: + return "senomix01", true + case 8053: + return "senomix02", true + case 8054: + return "senomix03", true + case 8055: + return "senomix04", true + case 8056: + return "senomix05", true + case 8057: + return "senomix06", true + case 8058: + return "senomix07", true + case 8059: + return "senomix08", true + case 8060: + return "aero", true + case 8074: + return "gadugadu", true + case 8080: + return "http-alt", true + case 8081: + return "sunproxyadmin", true + case 8082: + return "us-cli", true + case 8083: + return "us-srv", true + case 8086: + return "d-s-n", true + case 8087: + return "simplifymedia", true + case 8088: + return "radan-http", true + case 8097: + return "sac", true + case 8100: + return "xprint-server", true + case 8111: + return "skynetflow", true + case 8115: + return "mtl8000-matrix", true + case 8116: + return "cp-cluster", true + case 8118: + return "privoxy", true + case 8121: + return "apollo-data", true + case 8122: + return "apollo-admin", true + case 8128: + return "paycash-online", true + case 8129: + return "paycash-wbp", true + case 8130: + return "indigo-vrmi", true + case 8131: + return "indigo-vbcp", true + case 8132: + return "dbabble", true + case 8148: + return "isdd", true + case 8149: + return "eor-game", true + case 8160: + return "patrol", true + case 8161: + return "patrol-snmp", true + case 8182: + return "vmware-fdm", true + case 8184: + return "itach", true + case 8192: + return "spytechphone", true + case 8194: + return "blp1", true + case 8195: + return "blp2", true + case 8199: + return "vvr-data", true + case 8200: + return "trivnet1", true + case 8201: + return "trivnet2", true + case 8202: + return "aesop", true + case 8204: + return "lm-perfworks", true + case 8205: + return "lm-instmgr", true + case 8206: + return "lm-dta", true + case 8207: + return "lm-sserver", true + case 8208: + return "lm-webwatcher", true + case 8211: + return "aruba-papi", true + case 8230: + return "rexecj", true + case 8231: + return "hncp-udp-port", true + case 8232: + return "hncp-dtls-port", true + case 8243: + return "synapse-nhttps", true + case 8266: + return "espeasy-p2p", true + case 8276: + return "ms-mcc", true + case 8280: + return "synapse-nhttp", true + case 8282: + return "libelle-disc", true + case 8292: + return "blp3", true + case 8294: + return "blp4", true + case 8300: + return "tmi", true + case 8301: + return "amberon", true + case 8320: + return "tnp-discover", true + case 8321: + return "tnp", true + case 8322: + return "garmin-marine", true + case 8351: + return "server-find", true + case 8376: + return "cruise-enum", true + case 8377: + return "cruise-swroute", true + case 8378: + return "cruise-config", true + case 8379: + return "cruise-diags", true + case 8380: + return "cruise-update", true + case 8383: + return "m2mservices", true + case 8384: + return "marathontp", true + case 8400: + return "cvd", true + case 8401: + return "sabarsd", true + case 8402: + return "abarsd", true + case 8403: + return "admind", true + case 8416: + return "espeech", true + case 8417: + return "espeech-rtp", true + case 8433: + return "aws-as2", true + case 8442: + return "cybro-a-bus", true + case 8443: + return "pcsync-https", true + case 8444: + return "pcsync-http", true + case 8445: + return "copy-disc", true + case 8450: + return "npmp", true + case 8472: + return "otv", true + case 8473: + return "vp2p", true + case 8474: + return "noteshare", true + case 8500: + return "fmtp", true + case 8501: + return "cmtp-av", true + case 8503: + return "lsp-self-ping", true + case 8554: + return "rtsp-alt", true + case 8555: + return "d-fence", true + case 8567: + return "dof-tunnel", true + case 8600: + return "asterix", true + case 8609: + return "canon-cpp-disc", true + case 8610: + return "canon-mfnp", true + case 8611: + return "canon-bjnp1", true + case 8612: + return "canon-bjnp2", true + case 8613: + return "canon-bjnp3", true + case 8614: + return "canon-bjnp4", true + case 8675: + return "msi-cps-rm-disc", true + case 8686: + return "sun-as-jmxrmi", true + case 8732: + return "dtp-net", true + case 8733: + return "ibus", true + case 8763: + return "mc-appserver", true + case 8764: + return "openqueue", true + case 8765: + return "ultraseek-http", true + case 8766: + return "amcs", true + case 8770: + return "dpap", true + case 8786: + return "msgclnt", true + case 8787: + return "msgsrvr", true + case 8793: + return "acd-pm", true + case 8800: + return "sunwebadmin", true + case 8804: + return "truecm", true + case 8805: + return "pfcp", true + case 8807: + return "hes-clip", true + case 8808: + return "ssports-bcast", true + case 8809: + return "3gpp-monp", true + case 8873: + return "dxspider", true + case 8880: + return "cddbp-alt", true + case 8883: + return "secure-mqtt", true + case 8888: + return "ddi-udp-1", true + case 8889: + return "ddi-udp-2", true + case 8890: + return "ddi-udp-3", true + case 8891: + return "ddi-udp-4", true + case 8892: + return "ddi-udp-5", true + case 8893: + return "ddi-udp-6", true + case 8894: + return "ddi-udp-7", true + case 8899: + return "ospf-lite", true + case 8900: + return "jmb-cds1", true + case 8901: + return "jmb-cds2", true + case 8910: + return "manyone-http", true + case 8911: + return "manyone-xml", true + case 8912: + return "wcbackup", true + case 8913: + return "dragonfly", true + case 8954: + return "cumulus-admin", true + case 8980: + return "nod-provider", true + case 8981: + return "nod-client", true + case 8989: + return "sunwebadmins", true + case 8990: + return "http-wmap", true + case 8991: + return "https-wmap", true + case 8999: + return "bctp", true + case 9000: + return "cslistener", true + case 9001: + return "etlservicemgr", true + case 9002: + return "dynamid", true + case 9007: + return "ogs-client", true + case 9009: + return "pichat", true + case 9011: + return "d-star", true + case 9020: + return "tambora", true + case 9021: + return "panagolin-ident", true + case 9022: + return "paragent", true + case 9023: + return "swa-1", true + case 9024: + return "swa-2", true + case 9025: + return "swa-3", true + case 9026: + return "swa-4", true + case 9060: + return "CardWeb-RT", true + case 9080: + return "glrpc", true + case 9081: + return "cisco-aqos", true + case 9084: + return "aurora", true + case 9085: + return "ibm-rsyscon", true + case 9086: + return "net2display", true + case 9087: + return "classic", true + case 9088: + return "sqlexec", true + case 9089: + return "sqlexec-ssl", true + case 9090: + return "websm", true + case 9091: + return "xmltec-xmlmail", true + case 9092: + return "XmlIpcRegSvc", true + case 9100: + return "hp-pdl-datastr", true + case 9101: + return "bacula-dir", true + case 9102: + return "bacula-fd", true + case 9103: + return "bacula-sd", true + case 9104: + return "peerwire", true + case 9105: + return "xadmin", true + case 9106: + return "astergate-disc", true + case 9111: + return "hexxorecore", true + case 9119: + return "mxit", true + case 9131: + return "dddp", true + case 9160: + return "apani1", true + case 9161: + return "apani2", true + case 9162: + return "apani3", true + case 9163: + return "apani4", true + case 9164: + return "apani5", true + case 9191: + return "sun-as-jpda", true + case 9200: + return "wap-wsp", true + case 9201: + return "wap-wsp-wtp", true + case 9202: + return "wap-wsp-s", true + case 9203: + return "wap-wsp-wtp-s", true + case 9204: + return "wap-vcard", true + case 9205: + return "wap-vcal", true + case 9206: + return "wap-vcard-s", true + case 9207: + return "wap-vcal-s", true + case 9208: + return "rjcdb-vcards", true + case 9209: + return "almobile-system", true + case 9210: + return "oma-mlp", true + case 9211: + return "oma-mlp-s", true + case 9212: + return "serverviewdbms", true + case 9213: + return "serverstart", true + case 9214: + return "ipdcesgbs", true + case 9215: + return "insis", true + case 9216: + return "acme", true + case 9217: + return "fsc-port", true + case 9222: + return "teamcoherence", true + case 9255: + return "mon", true + case 9277: + return "traingpsdata", true + case 9278: + return "pegasus", true + case 9279: + return "pegasus-ctl", true + case 9280: + return "pgps", true + case 9281: + return "swtp-port1", true + case 9282: + return "swtp-port2", true + case 9283: + return "callwaveiam", true + case 9284: + return "visd", true + case 9285: + return "n2h2server", true + case 9286: + return "n2receive", true + case 9287: + return "cumulus", true + case 9292: + return "armtechdaemon", true + case 9293: + return "storview", true + case 9294: + return "armcenterhttp", true + case 9295: + return "armcenterhttps", true + case 9300: + return "vrace", true + case 9318: + return "secure-ts", true + case 9321: + return "guibase", true + case 9343: + return "mpidcmgr", true + case 9344: + return "mphlpdmc", true + case 9346: + return "ctechlicensing", true + case 9374: + return "fjdmimgr", true + case 9380: + return "boxp", true + case 9396: + return "fjinvmgr", true + case 9397: + return "mpidcagt", true + case 9400: + return "sec-t4net-srv", true + case 9401: + return "sec-t4net-clt", true + case 9402: + return "sec-pc2fax-srv", true + case 9418: + return "git", true + case 9443: + return "tungsten-https", true + case 9444: + return "wso2esb-console", true + case 9450: + return "sntlkeyssrvr", true + case 9500: + return "ismserver", true + case 9522: + return "sma-spw", true + case 9535: + return "mngsuite", true + case 9536: + return "laes-bf", true + case 9555: + return "trispen-sra", true + case 9592: + return "ldgateway", true + case 9593: + return "cba8", true + case 9594: + return "msgsys", true + case 9595: + return "pds", true + case 9596: + return "mercury-disc", true + case 9597: + return "pd-admin", true + case 9598: + return "vscp", true + case 9599: + return "robix", true + case 9600: + return "micromuse-ncpw", true + case 9612: + return "streamcomm-ds", true + case 9618: + return "condor", true + case 9628: + return "odbcpathway", true + case 9629: + return "uniport", true + case 9632: + return "mc-comm", true + case 9667: + return "xmms2", true + case 9668: + return "tec5-sdctp", true + case 9694: + return "client-wakeup", true + case 9695: + return "ccnx", true + case 9700: + return "board-roar", true + case 9747: + return "l5nas-parchan", true + case 9750: + return "board-voip", true + case 9753: + return "rasadv", true + case 9762: + return "tungsten-http", true + case 9800: + return "davsrc", true + case 9801: + return "sstp-2", true + case 9802: + return "davsrcs", true + case 9875: + return "sapv1", true + case 9878: + return "kca-service", true + case 9888: + return "cyborg-systems", true + case 9889: + return "gt-proxy", true + case 9898: + return "monkeycom", true + case 9899: + return "sctp-tunneling", true + case 9900: + return "iua", true + case 9901: + return "enrp", true + case 9903: + return "multicast-ping", true + case 9909: + return "domaintime", true + case 9911: + return "sype-transport", true + case 9950: + return "apc-9950", true + case 9951: + return "apc-9951", true + case 9952: + return "apc-9952", true + case 9953: + return "acis", true + case 9955: + return "alljoyn-mcm", true + case 9956: + return "alljoyn", true + case 9966: + return "odnsp", true + case 9987: + return "dsm-scm-target", true + case 9990: + return "osm-appsrvr", true + case 9991: + return "osm-oev", true + case 9992: + return "palace-1", true + case 9993: + return "palace-2", true + case 9994: + return "palace-3", true + case 9995: + return "palace-4", true + case 9996: + return "palace-5", true + case 9997: + return "palace-6", true + case 9998: + return "distinct32", true + case 9999: + return "distinct", true + case 10000: + return "ndmp", true + case 10001: + return "scp-config", true + case 10002: + return "documentum", true + case 10003: + return "documentum-s", true + case 10007: + return "mvs-capacity", true + case 10008: + return "octopus", true + case 10009: + return "swdtp-sv", true + case 10023: + return "cefd-vmp", true + case 10050: + return "zabbix-agent", true + case 10051: + return "zabbix-trapper", true + case 10080: + return "amanda", true + case 10081: + return "famdc", true + case 10100: + return "itap-ddtp", true + case 10101: + return "ezmeeting-2", true + case 10102: + return "ezproxy-2", true + case 10103: + return "ezrelay", true + case 10104: + return "swdtp", true + case 10107: + return "bctp-server", true + case 10110: + return "nmea-0183", true + case 10111: + return "nmea-onenet", true + case 10113: + return "netiq-endpoint", true + case 10114: + return "netiq-qcheck", true + case 10115: + return "netiq-endpt", true + case 10116: + return "netiq-voipa", true + case 10117: + return "iqrm", true + case 10128: + return "bmc-perf-sd", true + case 10160: + return "qb-db-server", true + case 10161: + return "snmpdtls", true + case 10162: + return "snmpdtls-trap", true + case 10200: + return "trisoap", true + case 10201: + return "rscs", true + case 10252: + return "apollo-relay", true + case 10253: + return "eapol-relay", true + case 10260: + return "axis-wimp-port", true + case 10288: + return "blocks", true + case 10439: + return "bngsync", true + case 10500: + return "hip-nat-t", true + case 10540: + return "MOS-lower", true + case 10541: + return "MOS-upper", true + case 10542: + return "MOS-aux", true + case 10543: + return "MOS-soap", true + case 10544: + return "MOS-soap-opt", true + case 10800: + return "gap", true + case 10805: + return "lpdg", true + case 10810: + return "nmc-disc", true + case 10860: + return "helix", true + case 10880: + return "bveapi", true + case 10990: + return "rmiaux", true + case 11000: + return "irisa", true + case 11001: + return "metasys", true + case 11095: + return "weave", true + case 11106: + return "sgi-lk", true + case 11108: + return "myq-termlink", true + case 11111: + return "vce", true + case 11112: + return "dicom", true + case 11161: + return "suncacao-snmp", true + case 11162: + return "suncacao-jmxmp", true + case 11163: + return "suncacao-rmi", true + case 11164: + return "suncacao-csa", true + case 11165: + return "suncacao-websvc", true + case 11171: + return "snss", true + case 11201: + return "smsqp", true + case 11208: + return "wifree", true + case 11211: + return "memcache", true + case 11319: + return "imip", true + case 11320: + return "imip-channels", true + case 11321: + return "arena-server", true + case 11367: + return "atm-uhas", true + case 11371: + return "hkp", true + case 11430: + return "lsdp", true + case 11600: + return "tempest-port", true + case 11720: + return "h323callsigalt", true + case 11723: + return "emc-xsw-dcache", true + case 11751: + return "intrepid-ssl", true + case 11796: + return "lanschool-mpt", true + case 11876: + return "xoraya", true + case 11877: + return "x2e-disc", true + case 11967: + return "sysinfo-sp", true + case 12000: + return "entextxid", true + case 12001: + return "entextnetwk", true + case 12002: + return "entexthigh", true + case 12003: + return "entextmed", true + case 12004: + return "entextlow", true + case 12005: + return "dbisamserver1", true + case 12006: + return "dbisamserver2", true + case 12007: + return "accuracer", true + case 12008: + return "accuracer-dbms", true + case 12009: + return "ghvpn", true + case 12012: + return "vipera", true + case 12013: + return "vipera-ssl", true + case 12109: + return "rets-ssl", true + case 12121: + return "nupaper-ss", true + case 12168: + return "cawas", true + case 12172: + return "hivep", true + case 12300: + return "linogridengine", true + case 12321: + return "warehouse-sss", true + case 12322: + return "warehouse", true + case 12345: + return "italk", true + case 12753: + return "tsaf", true + case 13160: + return "i-zipqd", true + case 13216: + return "bcslogc", true + case 13217: + return "rs-pias", true + case 13218: + return "emc-vcas-udp", true + case 13223: + return "powwow-client", true + case 13224: + return "powwow-server", true + case 13400: + return "doip-disc", true + case 13720: + return "bprd", true + case 13721: + return "bpdbm", true + case 13722: + return "bpjava-msvc", true + case 13724: + return "vnetd", true + case 13782: + return "bpcd", true + case 13783: + return "vopied", true + case 13785: + return "nbdb", true + case 13786: + return "nomdb", true + case 13818: + return "dsmcc-config", true + case 13819: + return "dsmcc-session", true + case 13820: + return "dsmcc-passthru", true + case 13821: + return "dsmcc-download", true + case 13822: + return "dsmcc-ccp", true + case 13894: + return "ucontrol", true + case 13929: + return "dta-systems", true + case 14000: + return "scotty-ft", true + case 14001: + return "sua", true + case 14002: + return "scotty-disc", true + case 14033: + return "sage-best-com1", true + case 14034: + return "sage-best-com2", true + case 14141: + return "vcs-app", true + case 14142: + return "icpp", true + case 14145: + return "gcm-app", true + case 14149: + return "vrts-tdd", true + case 14154: + return "vad", true + case 14250: + return "cps", true + case 14414: + return "ca-web-update", true + case 14936: + return "hde-lcesrvr-1", true + case 14937: + return "hde-lcesrvr-2", true + case 15000: + return "hydap", true + case 15118: + return "v2g-secc", true + case 15345: + return "xpilot", true + case 15363: + return "3link", true + case 15555: + return "cisco-snat", true + case 15660: + return "bex-xr", true + case 15740: + return "ptp", true + case 15998: + return "2ping", true + case 16003: + return "alfin", true + case 16161: + return "sun-sea-port", true + case 16309: + return "etb4j", true + case 16310: + return "pduncs", true + case 16311: + return "pdefmns", true + case 16360: + return "netserialext1", true + case 16361: + return "netserialext2", true + case 16367: + return "netserialext3", true + case 16368: + return "netserialext4", true + case 16384: + return "connected", true + case 16666: + return "vtp", true + case 16900: + return "newbay-snc-mc", true + case 16950: + return "sgcip", true + case 16991: + return "intel-rci-mp", true + case 16992: + return "amt-soap-http", true + case 16993: + return "amt-soap-https", true + case 16994: + return "amt-redir-tcp", true + case 16995: + return "amt-redir-tls", true + case 17007: + return "isode-dua", true + case 17185: + return "soundsvirtual", true + case 17219: + return "chipper", true + case 17220: + return "avtp", true + case 17221: + return "avdecc", true + case 17222: + return "cpsp", true + case 17224: + return "trdp-pd", true + case 17225: + return "trdp-md", true + case 17234: + return "integrius-stp", true + case 17235: + return "ssh-mgmt", true + case 17500: + return "db-lsp-disc", true + case 17729: + return "ea", true + case 17754: + return "zep", true + case 17755: + return "zigbee-ip", true + case 17756: + return "zigbee-ips", true + case 18000: + return "biimenu", true + case 18181: + return "opsec-cvp", true + case 18182: + return "opsec-ufp", true + case 18183: + return "opsec-sam", true + case 18184: + return "opsec-lea", true + case 18185: + return "opsec-omi", true + case 18186: + return "ohsc", true + case 18187: + return "opsec-ela", true + case 18241: + return "checkpoint-rtm", true + case 18262: + return "gv-pf", true + case 18463: + return "ac-cluster", true + case 18516: + return "heythings", true + case 18634: + return "rds-ib", true + case 18635: + return "rds-ip", true + case 18668: + return "vdmmesh-disc", true + case 18769: + return "ique", true + case 18881: + return "infotos", true + case 18888: + return "apc-necmp", true + case 19000: + return "igrid", true + case 19007: + return "scintilla", true + case 19191: + return "opsec-uaa", true + case 19194: + return "ua-secureagent", true + case 19220: + return "cora-disc", true + case 19283: + return "keysrvr", true + case 19315: + return "keyshadow", true + case 19398: + return "mtrgtrans", true + case 19410: + return "hp-sco", true + case 19411: + return "hp-sca", true + case 19412: + return "hp-sessmon", true + case 19539: + return "fxuptp", true + case 19540: + return "sxuptp", true + case 19541: + return "jcp", true + case 19788: + return "mle", true + case 19999: + return "dnp-sec", true + case 20000: + return "dnp", true + case 20001: + return "microsan", true + case 20002: + return "commtact-http", true + case 20003: + return "commtact-https", true + case 20005: + return "openwebnet", true + case 20012: + return "ss-idi-disc", true + case 20014: + return "opendeploy", true + case 20034: + return "nburn-id", true + case 20046: + return "tmophl7mts", true + case 20048: + return "mountd", true + case 20049: + return "nfsrdma", true + case 20167: + return "tolfab", true + case 20202: + return "ipdtp-port", true + case 20222: + return "ipulse-ics", true + case 20480: + return "emwavemsg", true + case 20670: + return "track", true + case 20999: + return "athand-mmp", true + case 21000: + return "irtrans", true + case 21554: + return "dfserver", true + case 21590: + return "vofr-gateway", true + case 21800: + return "tvpm", true + case 21845: + return "webphone", true + case 21846: + return "netspeak-is", true + case 21847: + return "netspeak-cs", true + case 21848: + return "netspeak-acd", true + case 21849: + return "netspeak-cps", true + case 22000: + return "snapenetio", true + case 22001: + return "optocontrol", true + case 22002: + return "optohost002", true + case 22003: + return "optohost003", true + case 22004: + return "optohost004", true + case 22005: + return "optohost004", true + case 22273: + return "wnn6", true + case 22305: + return "cis", true + case 22333: + return "showcockpit-net", true + case 22335: + return "shrewd-stream", true + case 22343: + return "cis-secure", true + case 22347: + return "wibukey", true + case 22350: + return "codemeter", true + case 22555: + return "vocaltec-phone", true + case 22763: + return "talikaserver", true + case 22800: + return "aws-brf", true + case 22951: + return "brf-gw", true + case 23000: + return "inovaport1", true + case 23001: + return "inovaport2", true + case 23002: + return "inovaport3", true + case 23003: + return "inovaport4", true + case 23004: + return "inovaport5", true + case 23005: + return "inovaport6", true + case 23272: + return "s102", true + case 23294: + return "5afe-disc", true + case 23333: + return "elxmgmt", true + case 23400: + return "novar-dbase", true + case 23401: + return "novar-alarm", true + case 23402: + return "novar-global", true + case 24000: + return "med-ltp", true + case 24001: + return "med-fsp-rx", true + case 24002: + return "med-fsp-tx", true + case 24003: + return "med-supp", true + case 24004: + return "med-ovw", true + case 24005: + return "med-ci", true + case 24006: + return "med-net-svc", true + case 24242: + return "filesphere", true + case 24249: + return "vista-4gl", true + case 24321: + return "ild", true + case 24322: + return "hid", true + case 24386: + return "intel-rci", true + case 24465: + return "tonidods", true + case 24554: + return "binkp", true + case 24577: + return "bilobit-update", true + case 24676: + return "canditv", true + case 24677: + return "flashfiler", true + case 24678: + return "proactivate", true + case 24680: + return "tcc-http", true + case 24850: + return "assoc-disc", true + case 24922: + return "find", true + case 25000: + return "icl-twobase1", true + case 25001: + return "icl-twobase2", true + case 25002: + return "icl-twobase3", true + case 25003: + return "icl-twobase4", true + case 25004: + return "icl-twobase5", true + case 25005: + return "icl-twobase6", true + case 25006: + return "icl-twobase7", true + case 25007: + return "icl-twobase8", true + case 25008: + return "icl-twobase9", true + case 25009: + return "icl-twobase10", true + case 25793: + return "vocaltec-hos", true + case 25900: + return "tasp-net", true + case 25901: + return "niobserver", true + case 25902: + return "nilinkanalyst", true + case 25903: + return "niprobe", true + case 25954: + return "bf-game", true + case 25955: + return "bf-master", true + case 26000: + return "quake", true + case 26133: + return "scscp", true + case 26208: + return "wnn6-ds", true + case 26260: + return "ezproxy", true + case 26261: + return "ezmeeting", true + case 26262: + return "k3software-svr", true + case 26263: + return "k3software-cli", true + case 26486: + return "exoline-udp", true + case 26487: + return "exoconfig", true + case 26489: + return "exonet", true + case 27345: + return "imagepump", true + case 27442: + return "jesmsjc", true + case 27504: + return "kopek-httphead", true + case 27782: + return "ars-vista", true + case 27999: + return "tw-auth-key", true + case 28000: + return "nxlmd", true + case 28119: + return "a27-ran-ran", true + case 28200: + return "voxelstorm", true + case 28240: + return "siemensgsm", true + case 29167: + return "otmp", true + case 30001: + return "pago-services1", true + case 30002: + return "pago-services2", true + case 30003: + return "amicon-fpsu-ra", true + case 30004: + return "amicon-fpsu-s", true + case 30260: + return "kingdomsonline", true + case 30832: + return "samsung-disc", true + case 30999: + return "ovobs", true + case 31016: + return "ka-kdp", true + case 31029: + return "yawn", true + case 31337: + return "eldim", true + case 31416: + return "xqosd", true + case 31457: + return "tetrinet", true + case 31620: + return "lm-mon", true + case 31765: + return "gamesmith-port", true + case 31948: + return "iceedcp-tx", true + case 31949: + return "iceedcp-rx", true + case 32034: + return "iracinghelper", true + case 32249: + return "t1distproc60", true + case 32483: + return "apm-link", true + case 32635: + return "sec-ntb-clnt", true + case 32636: + return "DMExpress", true + case 32767: + return "filenet-powsrm", true + case 32768: + return "filenet-tms", true + case 32769: + return "filenet-rpc", true + case 32770: + return "filenet-nch", true + case 32771: + return "filenet-rmi", true + case 32772: + return "filenet-pa", true + case 32773: + return "filenet-cm", true + case 32774: + return "filenet-re", true + case 32775: + return "filenet-pch", true + case 32776: + return "filenet-peior", true + case 32777: + return "filenet-obrok", true + case 32801: + return "mlsn", true + case 32896: + return "idmgratm", true + case 33123: + return "aurora-balaena", true + case 33331: + return "diamondport", true + case 33334: + return "speedtrace-disc", true + case 33434: + return "traceroute", true + case 33435: + return "mtrace", true + case 33656: + return "snip-slave", true + case 34249: + return "turbonote-2", true + case 34378: + return "p-net-local", true + case 34379: + return "p-net-remote", true + case 34567: + return "edi_service", true + case 34962: + return "profinet-rt", true + case 34963: + return "profinet-rtm", true + case 34964: + return "profinet-cm", true + case 34980: + return "ethercat", true + case 35001: + return "rt-viewer", true + case 35004: + return "rt-classmanager", true + case 35100: + return "axio-disc", true + case 35355: + return "altova-lm-disc", true + case 36001: + return "allpeers", true + case 36411: + return "wlcp", true + case 36865: + return "kastenxpipe", true + case 37475: + return "neckar", true + case 37654: + return "unisys-eportal", true + case 38002: + return "crescoctrl-disc", true + case 38201: + return "galaxy7-data", true + case 38202: + return "fairview", true + case 38203: + return "agpolicy", true + case 39681: + return "turbonote-1", true + case 40000: + return "safetynetp", true + case 40023: + return "k-patentssensor", true + case 40841: + return "cscp", true + case 40842: + return "csccredir", true + case 40843: + return "csccfirewall", true + case 40853: + return "ortec-disc", true + case 41111: + return "fs-qos", true + case 41230: + return "z-wave-s", true + case 41794: + return "crestron-cip", true + case 41795: + return "crestron-ctp", true + case 42508: + return "candp", true + case 42509: + return "candrp", true + case 42510: + return "caerpc", true + case 43000: + return "recvr-rc-disc", true + case 43188: + return "reachout", true + case 43189: + return "ndm-agent-port", true + case 43190: + return "ip-provision", true + case 43210: + return "shaperai-disc", true + case 43438: + return "hmip-routing", true + case 43439: + return "eq3-config", true + case 43440: + return "ew-disc-cmd", true + case 43441: + return "ciscocsdb", true + case 44321: + return "pmcd", true + case 44322: + return "pmcdproxy", true + case 44544: + return "domiq", true + case 44553: + return "rbr-debug", true + case 44600: + return "asihpi", true + case 44818: + return "EtherNet-IP-2", true + case 44900: + return "m3da-disc", true + case 45000: + return "asmp-mon", true + case 45054: + return "invision-ag", true + case 45514: + return "cloudcheck-ping", true + case 45678: + return "eba", true + case 45825: + return "qdb2service", true + case 45966: + return "ssr-servermgr", true + case 46999: + return "mediabox", true + case 47000: + return "mbus", true + case 47100: + return "jvl-mactalk", true + case 47557: + return "dbbrowse", true + case 47624: + return "directplaysrvr", true + case 47806: + return "ap", true + case 47808: + return "bacnet", true + case 47809: + return "presonus-ucnet", true + case 48000: + return "nimcontroller", true + case 48001: + return "nimspooler", true + case 48002: + return "nimhub", true + case 48003: + return "nimgtw", true + case 48128: + return "isnetserv", true + case 48129: + return "blp5", true + case 48556: + return "com-bardac-dw", true + case 48619: + return "iqobject", true + case 48653: + return "robotraconteur", true + case 49001: + return "nusdp-disc", true + + } + + return "", false +} + +// SCTPPortNames contains the port names for all SCTP ports. +func SCTPPortNames(port SCTPPort) (string, bool) { + switch port { + case 9: + return "discard", true + case 20: + return "ftp-data", true + case 21: + return "ftp", true + case 22: + return "ssh", true + case 80: + return "http", true + case 179: + return "bgp", true + case 443: + return "https", true + case 1021: + return "exp1", true + case 1022: + return "exp2", true + case 1167: + return "cisco-ipsla", true + case 1528: + return "norp", true + case 1720: + return "h323hostcall", true + case 2049: + return "nfs", true + case 2225: + return "rcip-itu", true + case 2904: + return "m2ua", true + case 2905: + return "m3ua", true + case 2944: + return "megaco-h248", true + case 2945: + return "h248-binary", true + case 3097: + return "itu-bicc-stc", true + case 3565: + return "m2pa", true + case 3863: + return "asap-sctp", true + case 3864: + return "asap-sctp-tls", true + case 3868: + return "diameter", true + case 4195: + return "aws-wsp", true + case 4333: + return "ahsp", true + case 4502: + return "a25-fap-fgw", true + case 4711: + return "trinity-dist", true + case 4739: + return "ipfix", true + case 4740: + return "ipfixs", true + case 5060: + return "sip", true + case 5061: + return "sips", true + case 5090: + return "car", true + case 5091: + return "cxtp", true + case 5215: + return "noteza", true + case 5445: + return "smbdirect", true + case 5672: + return "amqp", true + case 5675: + return "v5ua", true + case 5868: + return "diameters", true + case 5903: + return "ff-ice", true + case 5904: + return "ag-swim", true + case 5905: + return "asmgcs", true + case 5906: + return "rpas-c2", true + case 5907: + return "dsd", true + case 5908: + return "ipsma", true + case 5909: + return "agma", true + case 5910: + return "cm", true + case 5911: + return "cpdlc", true + case 5912: + return "fis", true + case 5913: + return "ads-c", true + case 6704: + return "frc-hp", true + case 6705: + return "frc-mp", true + case 6706: + return "frc-lp", true + case 6970: + return "conductor-mpx", true + case 7626: + return "simco", true + case 7701: + return "nfapi", true + case 7728: + return "osvr", true + case 8471: + return "pim-port", true + case 9082: + return "lcs-ap", true + case 9084: + return "aurora", true + case 9900: + return "iua", true + case 9901: + return "enrp-sctp", true + case 9902: + return "enrp-sctp-tls", true + case 11235: + return "xcompute", true + case 11997: + return "wmereceiving", true + case 11998: + return "wmedistribution", true + case 11999: + return "wmereporting", true + case 14001: + return "sua", true + case 19999: + return "dnp-sec", true + case 20000: + return "dnp", true + case 20049: + return "nfsrdma", true + case 25471: + return "rna", true + case 29118: + return "sgsap", true + case 29168: + return "sbcap", true + case 29169: + return "iuhsctpassoc", true + case 30100: + return "rwp", true + case 36412: + return "s1-control", true + case 36422: + return "x2-control", true + case 36423: + return "slmap", true + case 36424: + return "nq-ap", true + case 36443: + return "m2ap", true + case 36444: + return "m3ap", true + case 36462: + return "xw-control", true + case 37472: + return "3gpp-w1ap", true + case 38412: + return "ng-control", true + case 38422: + return "xn-control", true + case 38462: + return "e1-interface", true + case 38472: + return "f1-control", true + + } + + return "", false +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp4.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp4.go new file mode 100644 index 0000000000..da87f038d8 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp4.go @@ -0,0 +1,281 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + + "github.com/gopacket/gopacket" +) + +const ( + ICMPv4TypeEchoReply = 0 + ICMPv4TypeDestinationUnreachable = 3 + ICMPv4TypeSourceQuench = 4 + ICMPv4TypeRedirect = 5 + ICMPv4TypeEchoRequest = 8 + ICMPv4TypeRouterAdvertisement = 9 + ICMPv4TypeRouterSolicitation = 10 + ICMPv4TypeTimeExceeded = 11 + ICMPv4TypeParameterProblem = 12 + ICMPv4TypeTimestampRequest = 13 + ICMPv4TypeTimestampReply = 14 + ICMPv4TypeInfoRequest = 15 + ICMPv4TypeInfoReply = 16 + ICMPv4TypeAddressMaskRequest = 17 + ICMPv4TypeAddressMaskReply = 18 +) + +const ( + // DestinationUnreachable + ICMPv4CodeNet = 0 + ICMPv4CodeHost = 1 + ICMPv4CodeProtocol = 2 + ICMPv4CodePort = 3 + ICMPv4CodeFragmentationNeeded = 4 + ICMPv4CodeSourceRoutingFailed = 5 + ICMPv4CodeNetUnknown = 6 + ICMPv4CodeHostUnknown = 7 + ICMPv4CodeSourceIsolated = 8 + ICMPv4CodeNetAdminProhibited = 9 + ICMPv4CodeHostAdminProhibited = 10 + ICMPv4CodeNetTOS = 11 + ICMPv4CodeHostTOS = 12 + ICMPv4CodeCommAdminProhibited = 13 + ICMPv4CodeHostPrecedence = 14 + ICMPv4CodePrecedenceCutoff = 15 + + // TimeExceeded + ICMPv4CodeTTLExceeded = 0 + ICMPv4CodeFragmentReassemblyTimeExceeded = 1 + + // ParameterProblem + ICMPv4CodePointerIndicatesError = 0 + ICMPv4CodeMissingOption = 1 + ICMPv4CodeBadLength = 2 + + // Redirect + // ICMPv4CodeNet = same as for DestinationUnreachable + // ICMPv4CodeHost = same as for DestinationUnreachable + ICMPv4CodeTOSNet = 2 + ICMPv4CodeTOSHost = 3 +) + +type icmpv4TypeCodeInfoStruct struct { + typeStr string + codeStr *map[uint8]string +} + +var ( + icmpv4TypeCodeInfo = map[uint8]icmpv4TypeCodeInfoStruct{ + ICMPv4TypeDestinationUnreachable: icmpv4TypeCodeInfoStruct{ + "DestinationUnreachable", &map[uint8]string{ + ICMPv4CodeNet: "Net", + ICMPv4CodeHost: "Host", + ICMPv4CodeProtocol: "Protocol", + ICMPv4CodePort: "Port", + ICMPv4CodeFragmentationNeeded: "FragmentationNeeded", + ICMPv4CodeSourceRoutingFailed: "SourceRoutingFailed", + ICMPv4CodeNetUnknown: "NetUnknown", + ICMPv4CodeHostUnknown: "HostUnknown", + ICMPv4CodeSourceIsolated: "SourceIsolated", + ICMPv4CodeNetAdminProhibited: "NetAdminProhibited", + ICMPv4CodeHostAdminProhibited: "HostAdminProhibited", + ICMPv4CodeNetTOS: "NetTOS", + ICMPv4CodeHostTOS: "HostTOS", + ICMPv4CodeCommAdminProhibited: "CommAdminProhibited", + ICMPv4CodeHostPrecedence: "HostPrecedence", + ICMPv4CodePrecedenceCutoff: "PrecedenceCutoff", + }, + }, + ICMPv4TypeTimeExceeded: icmpv4TypeCodeInfoStruct{ + "TimeExceeded", &map[uint8]string{ + ICMPv4CodeTTLExceeded: "TTLExceeded", + ICMPv4CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded", + }, + }, + ICMPv4TypeParameterProblem: icmpv4TypeCodeInfoStruct{ + "ParameterProblem", &map[uint8]string{ + ICMPv4CodePointerIndicatesError: "PointerIndicatesError", + ICMPv4CodeMissingOption: "MissingOption", + ICMPv4CodeBadLength: "BadLength", + }, + }, + ICMPv4TypeSourceQuench: icmpv4TypeCodeInfoStruct{ + "SourceQuench", nil, + }, + ICMPv4TypeRedirect: icmpv4TypeCodeInfoStruct{ + "Redirect", &map[uint8]string{ + ICMPv4CodeNet: "Net", + ICMPv4CodeHost: "Host", + ICMPv4CodeTOSNet: "TOS+Net", + ICMPv4CodeTOSHost: "TOS+Host", + }, + }, + ICMPv4TypeEchoRequest: icmpv4TypeCodeInfoStruct{ + "EchoRequest", nil, + }, + ICMPv4TypeEchoReply: icmpv4TypeCodeInfoStruct{ + "EchoReply", nil, + }, + ICMPv4TypeTimestampRequest: icmpv4TypeCodeInfoStruct{ + "TimestampRequest", nil, + }, + ICMPv4TypeTimestampReply: icmpv4TypeCodeInfoStruct{ + "TimestampReply", nil, + }, + ICMPv4TypeInfoRequest: icmpv4TypeCodeInfoStruct{ + "InfoRequest", nil, + }, + ICMPv4TypeInfoReply: icmpv4TypeCodeInfoStruct{ + "InfoReply", nil, + }, + ICMPv4TypeRouterSolicitation: icmpv4TypeCodeInfoStruct{ + "RouterSolicitation", nil, + }, + ICMPv4TypeRouterAdvertisement: icmpv4TypeCodeInfoStruct{ + "RouterAdvertisement", nil, + }, + ICMPv4TypeAddressMaskRequest: icmpv4TypeCodeInfoStruct{ + "AddressMaskRequest", nil, + }, + ICMPv4TypeAddressMaskReply: icmpv4TypeCodeInfoStruct{ + "AddressMaskReply", nil, + }, + } +) + +type ICMPv4TypeCode uint16 + +// Type returns the ICMPv4 type field. +func (a ICMPv4TypeCode) Type() uint8 { + return uint8(a >> 8) +} + +// Code returns the ICMPv4 code field. +func (a ICMPv4TypeCode) Code() uint8 { + return uint8(a) +} + +func (a ICMPv4TypeCode) String() string { + t, c := a.Type(), a.Code() + strInfo, ok := icmpv4TypeCodeInfo[t] + if !ok { + // Unknown ICMPv4 type field + return fmt.Sprintf("%d(%d)", t, c) + } + typeStr := strInfo.typeStr + if strInfo.codeStr == nil && c == 0 { + // The ICMPv4 type does not make use of the code field + return fmt.Sprintf("%s", strInfo.typeStr) + } + if strInfo.codeStr == nil && c != 0 { + // The ICMPv4 type does not make use of the code field, but it is present anyway + return fmt.Sprintf("%s(Code: %d)", typeStr, c) + } + codeStr, ok := (*strInfo.codeStr)[c] + if !ok { + // We don't know this ICMPv4 code; print the numerical value + return fmt.Sprintf("%s(Code: %d)", typeStr, c) + } + return fmt.Sprintf("%s(%s)", typeStr, codeStr) +} + +func (a ICMPv4TypeCode) GoString() string { + t := reflect.TypeOf(a) + return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code()) +} + +// SerializeTo writes the ICMPv4TypeCode value to the 'bytes' buffer. +func (a ICMPv4TypeCode) SerializeTo(bytes []byte) { + binary.BigEndian.PutUint16(bytes, uint16(a)) +} + +// CreateICMPv4TypeCode is a convenience function to create an ICMPv4TypeCode +// gopacket type from the ICMPv4 type and code values. +func CreateICMPv4TypeCode(typ uint8, code uint8) ICMPv4TypeCode { + return ICMPv4TypeCode(binary.BigEndian.Uint16([]byte{typ, code})) +} + +// ICMPv4 is the layer for IPv4 ICMP packet data. +type ICMPv4 struct { + BaseLayer + TypeCode ICMPv4TypeCode + Checksum uint16 + Id uint16 + Seq uint16 +} + +// LayerType returns LayerTypeICMPv4. +func (i *ICMPv4) LayerType() gopacket.LayerType { return LayerTypeICMPv4 } + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return errors.New("ICMP layer less then 8 bytes for ICMPv4 packet") + } + i.TypeCode = CreateICMPv4TypeCode(data[0], data[1]) + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.Id = binary.BigEndian.Uint16(data[4:6]) + i.Seq = binary.BigEndian.Uint16(data[6:8]) + i.BaseLayer = BaseLayer{data[:8], data[8:]} + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + i.TypeCode.SerializeTo(bytes) + binary.BigEndian.PutUint16(bytes[4:], i.Id) + binary.BigEndian.PutUint16(bytes[6:], i.Seq) + if opts.ComputeChecksums { + bytes[2] = 0 + bytes[3] = 0 + csum := gopacket.ComputeChecksum(b.Bytes(), 0) + i.Checksum = gopacket.FoldChecksum(csum) + } + binary.BigEndian.PutUint16(bytes[2:], i.Checksum) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv4) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv4 +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv4) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func (i *ICMPv4) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + bytes := append(i.Contents, i.Payload...) + + existing := i.Checksum + verification := gopacket.ComputeChecksum(bytes, 0) + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} + +func decodeICMPv4(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv4{} + return decodingLayerDecoder(i, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6.go new file mode 100644 index 0000000000..c275a5bae8 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6.go @@ -0,0 +1,282 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + + "github.com/gopacket/gopacket" +) + +const ( + // The following are from RFC 4443 + ICMPv6TypeDestinationUnreachable = 1 + ICMPv6TypePacketTooBig = 2 + ICMPv6TypeTimeExceeded = 3 + ICMPv6TypeParameterProblem = 4 + ICMPv6TypeEchoRequest = 128 + ICMPv6TypeEchoReply = 129 + + // The following are from RFC 4861 + ICMPv6TypeRouterSolicitation = 133 + ICMPv6TypeRouterAdvertisement = 134 + ICMPv6TypeNeighborSolicitation = 135 + ICMPv6TypeNeighborAdvertisement = 136 + ICMPv6TypeRedirect = 137 + + // The following are from RFC 2710 + ICMPv6TypeMLDv1MulticastListenerQueryMessage = 130 + ICMPv6TypeMLDv1MulticastListenerReportMessage = 131 + ICMPv6TypeMLDv1MulticastListenerDoneMessage = 132 + + // The following are from RFC 3810 + ICMPv6TypeMLDv2MulticastListenerReportMessageV2 = 143 +) + +const ( + // DestinationUnreachable + ICMPv6CodeNoRouteToDst = 0 + ICMPv6CodeAdminProhibited = 1 + ICMPv6CodeBeyondScopeOfSrc = 2 + ICMPv6CodeAddressUnreachable = 3 + ICMPv6CodePortUnreachable = 4 + ICMPv6CodeSrcAddressFailedPolicy = 5 + ICMPv6CodeRejectRouteToDst = 6 + + // TimeExceeded + ICMPv6CodeHopLimitExceeded = 0 + ICMPv6CodeFragmentReassemblyTimeExceeded = 1 + + // ParameterProblem + ICMPv6CodeErroneousHeaderField = 0 + ICMPv6CodeUnrecognizedNextHeader = 1 + ICMPv6CodeUnrecognizedIPv6Option = 2 +) + +type icmpv6TypeCodeInfoStruct struct { + typeStr string + codeStr *map[uint8]string +} + +var ( + icmpv6TypeCodeInfo = map[uint8]icmpv6TypeCodeInfoStruct{ + ICMPv6TypeDestinationUnreachable: icmpv6TypeCodeInfoStruct{ + "DestinationUnreachable", &map[uint8]string{ + ICMPv6CodeNoRouteToDst: "NoRouteToDst", + ICMPv6CodeAdminProhibited: "AdminProhibited", + ICMPv6CodeBeyondScopeOfSrc: "BeyondScopeOfSrc", + ICMPv6CodeAddressUnreachable: "AddressUnreachable", + ICMPv6CodePortUnreachable: "PortUnreachable", + ICMPv6CodeSrcAddressFailedPolicy: "SrcAddressFailedPolicy", + ICMPv6CodeRejectRouteToDst: "RejectRouteToDst", + }, + }, + ICMPv6TypePacketTooBig: icmpv6TypeCodeInfoStruct{ + "PacketTooBig", nil, + }, + ICMPv6TypeTimeExceeded: icmpv6TypeCodeInfoStruct{ + "TimeExceeded", &map[uint8]string{ + ICMPv6CodeHopLimitExceeded: "HopLimitExceeded", + ICMPv6CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded", + }, + }, + ICMPv6TypeParameterProblem: icmpv6TypeCodeInfoStruct{ + "ParameterProblem", &map[uint8]string{ + ICMPv6CodeErroneousHeaderField: "ErroneousHeaderField", + ICMPv6CodeUnrecognizedNextHeader: "UnrecognizedNextHeader", + ICMPv6CodeUnrecognizedIPv6Option: "UnrecognizedIPv6Option", + }, + }, + ICMPv6TypeEchoRequest: icmpv6TypeCodeInfoStruct{ + "EchoRequest", nil, + }, + ICMPv6TypeEchoReply: icmpv6TypeCodeInfoStruct{ + "EchoReply", nil, + }, + ICMPv6TypeRouterSolicitation: icmpv6TypeCodeInfoStruct{ + "RouterSolicitation", nil, + }, + ICMPv6TypeRouterAdvertisement: icmpv6TypeCodeInfoStruct{ + "RouterAdvertisement", nil, + }, + ICMPv6TypeNeighborSolicitation: icmpv6TypeCodeInfoStruct{ + "NeighborSolicitation", nil, + }, + ICMPv6TypeNeighborAdvertisement: icmpv6TypeCodeInfoStruct{ + "NeighborAdvertisement", nil, + }, + ICMPv6TypeRedirect: icmpv6TypeCodeInfoStruct{ + "Redirect", nil, + }, + } +) + +type ICMPv6TypeCode uint16 + +// Type returns the ICMPv6 type field. +func (a ICMPv6TypeCode) Type() uint8 { + return uint8(a >> 8) +} + +// Code returns the ICMPv6 code field. +func (a ICMPv6TypeCode) Code() uint8 { + return uint8(a) +} + +func (a ICMPv6TypeCode) String() string { + t, c := a.Type(), a.Code() + strInfo, ok := icmpv6TypeCodeInfo[t] + if !ok { + // Unknown ICMPv6 type field + return fmt.Sprintf("%d(%d)", t, c) + } + typeStr := strInfo.typeStr + if strInfo.codeStr == nil && c == 0 { + // The ICMPv6 type does not make use of the code field + return fmt.Sprintf("%s", strInfo.typeStr) + } + if strInfo.codeStr == nil && c != 0 { + // The ICMPv6 type does not make use of the code field, but it is present anyway + return fmt.Sprintf("%s(Code: %d)", typeStr, c) + } + codeStr, ok := (*strInfo.codeStr)[c] + if !ok { + // We don't know this ICMPv6 code; print the numerical value + return fmt.Sprintf("%s(Code: %d)", typeStr, c) + } + return fmt.Sprintf("%s(%s)", typeStr, codeStr) +} + +func (a ICMPv6TypeCode) GoString() string { + t := reflect.TypeOf(a) + return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code()) +} + +// SerializeTo writes the ICMPv6TypeCode value to the 'bytes' buffer. +func (a ICMPv6TypeCode) SerializeTo(bytes []byte) { + binary.BigEndian.PutUint16(bytes, uint16(a)) +} + +// CreateICMPv6TypeCode is a convenience function to create an ICMPv6TypeCode +// gopacket type from the ICMPv6 type and code values. +func CreateICMPv6TypeCode(typ uint8, code uint8) ICMPv6TypeCode { + return ICMPv6TypeCode(binary.BigEndian.Uint16([]byte{typ, code})) +} + +// ICMPv6 is the layer for IPv6 ICMP packet data +type ICMPv6 struct { + BaseLayer + TypeCode ICMPv6TypeCode + Checksum uint16 + // TypeBytes is deprecated and always nil. See the different ICMPv6 message types + // instead (e.g. ICMPv6TypeRouterSolicitation). + TypeBytes []byte + tcpipchecksum +} + +// LayerType returns LayerTypeICMPv6. +func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 } + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return errors.New("ICMP layer less then 4 bytes for ICMPv6 packet") + } + i.TypeCode = CreateICMPv6TypeCode(data[0], data[1]) + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.BaseLayer = BaseLayer{data[:4], data[4:]} + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + i.TypeCode.SerializeTo(bytes) + + if opts.ComputeChecksums { + bytes[2] = 0 + bytes[3] = 0 + csum, err := i.computeChecksum(b.Bytes(), IPProtocolICMPv6) + if err != nil { + return err + } + i.Checksum = gopacket.FoldChecksum(csum) + } + binary.BigEndian.PutUint16(bytes[2:], i.Checksum) + + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6 +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6) NextLayerType() gopacket.LayerType { + switch i.TypeCode.Type() { + case ICMPv6TypeEchoRequest: + return LayerTypeICMPv6Echo + case ICMPv6TypeEchoReply: + return LayerTypeICMPv6Echo + case ICMPv6TypeRouterSolicitation: + return LayerTypeICMPv6RouterSolicitation + case ICMPv6TypeRouterAdvertisement: + return LayerTypeICMPv6RouterAdvertisement + case ICMPv6TypeNeighborSolicitation: + return LayerTypeICMPv6NeighborSolicitation + case ICMPv6TypeNeighborAdvertisement: + return LayerTypeICMPv6NeighborAdvertisement + case ICMPv6TypeRedirect: + return LayerTypeICMPv6Redirect + case ICMPv6TypeMLDv1MulticastListenerQueryMessage: // Same Code for MLDv1 Query and MLDv2 Query + if len(i.Payload) > 20 { // Only payload size differs + return LayerTypeMLDv2MulticastListenerQuery + } else { + return LayerTypeMLDv1MulticastListenerQuery + } + case ICMPv6TypeMLDv1MulticastListenerDoneMessage: + return LayerTypeMLDv1MulticastListenerDone + case ICMPv6TypeMLDv1MulticastListenerReportMessage: + return LayerTypeMLDv1MulticastListenerReport + case ICMPv6TypeMLDv2MulticastListenerReportMessageV2: + return LayerTypeMLDv2MulticastListenerReport + } + + return gopacket.LayerTypePayload +} + +func (i *ICMPv6) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + bytes := append(i.Contents, i.Payload...) + + existing := i.Checksum + verification, err := i.computeChecksum(bytes, IPProtocolICMPv6) + if err != nil { + return err, gopacket.ChecksumVerificationResult{} + } + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} + +func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6{} + return decodingLayerDecoder(i, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6msg.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6msg.go new file mode 100644 index 0000000000..2c897b6393 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/icmp6msg.go @@ -0,0 +1,595 @@ +// 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 layers + +import ( + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "net" + "strings" + "time" + + "github.com/gopacket/gopacket" +) + +// Based on RFC 4861 + +// ICMPv6Opt indicate how to decode the data associated with each ICMPv6Option. +type ICMPv6Opt uint8 + +const ( + _ ICMPv6Opt = iota + + // ICMPv6OptSourceAddress contains the link-layer address of the sender of + // the packet. It is used in the Neighbor Solicitation, Router + // Solicitation, and Router Advertisement packets. Must be ignored for other + // Neighbor discovery messages. + ICMPv6OptSourceAddress + + // ICMPv6OptTargetAddress contains the link-layer address of the target. It + // is used in Neighbor Advertisement and Redirect packets. Must be ignored + // for other Neighbor discovery messages. + ICMPv6OptTargetAddress + + // ICMPv6OptPrefixInfo provides hosts with on-link prefixes and prefixes + // for Address Autoconfiguration. The Prefix Information option appears in + // Router Advertisement packets and MUST be silently ignored for other + // messages. + ICMPv6OptPrefixInfo + + // ICMPv6OptRedirectedHeader is used in Redirect messages and contains all + // or part of the packet that is being redirected. + ICMPv6OptRedirectedHeader + + // ICMPv6OptMTU is used in Router Advertisement messages to ensure that all + // nodes on a link use the same MTU value in those cases where the link MTU + // is not well known. This option MUST be silently ignored for other + // Neighbor Discovery messages. + ICMPv6OptMTU + + // ICMPv6OptRecursiveDNSServer is used in Router Advertisement messages to + // advertise recursive DNS servers. + ICMPv6OptRecursiveDNSServer = 25 +) + +// ICMPv6Echo represents the structure of a ping. +type ICMPv6Echo struct { + BaseLayer + Identifier uint16 + SeqNumber uint16 +} + +// ICMPv6RouterSolicitation is sent by hosts to find routers. +type ICMPv6RouterSolicitation struct { + BaseLayer + Options ICMPv6Options +} + +// ICMPv6RouterAdvertisement is sent by routers in response to Solicitation. +type ICMPv6RouterAdvertisement struct { + BaseLayer + HopLimit uint8 + Flags uint8 + RouterLifetime uint16 + ReachableTime uint32 + RetransTimer uint32 + Options ICMPv6Options +} + +// ICMPv6NeighborSolicitation is sent to request the link-layer address of a +// target node. +type ICMPv6NeighborSolicitation struct { + BaseLayer + TargetAddress net.IP + Options ICMPv6Options +} + +// ICMPv6NeighborAdvertisement is sent by nodes in response to Solicitation. +type ICMPv6NeighborAdvertisement struct { + BaseLayer + Flags uint8 + TargetAddress net.IP + Options ICMPv6Options +} + +// ICMPv6Redirect is sent by routers to inform hosts of a better first-hop node +// on the path to a destination. +type ICMPv6Redirect struct { + BaseLayer + TargetAddress net.IP + DestinationAddress net.IP + Options ICMPv6Options +} + +// ICMPv6Option contains the type and data for a single option. +type ICMPv6Option struct { + Type ICMPv6Opt + Data []byte +} + +// ICMPv6Options is a slice of ICMPv6Option. +type ICMPv6Options []ICMPv6Option + +func (i ICMPv6Opt) String() string { + switch i { + case ICMPv6OptSourceAddress: + return "SourceAddress" + case ICMPv6OptTargetAddress: + return "TargetAddress" + case ICMPv6OptPrefixInfo: + return "PrefixInfo" + case ICMPv6OptRedirectedHeader: + return "RedirectedHeader" + case ICMPv6OptMTU: + return "MTU" + case ICMPv6OptRecursiveDNSServer: + return "RecursiveDNSServer" + default: + return fmt.Sprintf("Unknown(%d)", i) + } +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6Echo) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6Echo +} + +// LayerType returns LayerTypeICMPv6Echo. +func (i *ICMPv6Echo) LayerType() gopacket.LayerType { + return LayerTypeICMPv6Echo +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6Echo) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6Echo) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return errors.New("ICMP layer less then 4 bytes for ICMPv6 Echo") + } + i.Identifier = binary.BigEndian.Uint16(data[0:2]) + i.SeqNumber = binary.BigEndian.Uint16(data[2:4]) + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6Echo) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(4) + if err != nil { + return err + } + + binary.BigEndian.PutUint16(buf, i.Identifier) + binary.BigEndian.PutUint16(buf[2:], i.SeqNumber) + return nil +} + +// LayerType returns LayerTypeICMPv6. +func (i *ICMPv6RouterSolicitation) LayerType() gopacket.LayerType { + return LayerTypeICMPv6RouterSolicitation +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6RouterSolicitation) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6RouterSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + // first 4 bytes are reserved followed by options + if len(data) < 4 { + df.SetTruncated() + return errors.New("ICMP layer less then 4 bytes for ICMPv6 router solicitation") + } + + // truncate old options + i.Options = i.Options[:0] + + return i.Options.DecodeFromBytes(data[4:], df) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6RouterSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := i.Options.SerializeTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(4) + if err != nil { + return err + } + + copy(buf, lotsOfZeros[:4]) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6RouterSolicitation) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6RouterSolicitation +} + +// LayerType returns LayerTypeICMPv6RouterAdvertisement. +func (i *ICMPv6RouterAdvertisement) LayerType() gopacket.LayerType { + return LayerTypeICMPv6RouterAdvertisement +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6RouterAdvertisement) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6RouterAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 12 { + df.SetTruncated() + return errors.New("ICMP layer less then 12 bytes for ICMPv6 router advertisement") + } + + i.HopLimit = uint8(data[0]) + // M, O bit followed by 6 reserved bits + i.Flags = uint8(data[1]) + i.RouterLifetime = binary.BigEndian.Uint16(data[2:4]) + i.ReachableTime = binary.BigEndian.Uint32(data[4:8]) + i.RetransTimer = binary.BigEndian.Uint32(data[8:12]) + i.BaseLayer = BaseLayer{data, nil} // assume no payload + + // truncate old options + i.Options = i.Options[:0] + + return i.Options.DecodeFromBytes(data[12:], df) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6RouterAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := i.Options.SerializeTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(12) + if err != nil { + return err + } + + buf[0] = byte(i.HopLimit) + buf[1] = byte(i.Flags) + binary.BigEndian.PutUint16(buf[2:], i.RouterLifetime) + binary.BigEndian.PutUint32(buf[4:], i.ReachableTime) + binary.BigEndian.PutUint32(buf[8:], i.RetransTimer) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6RouterAdvertisement) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6RouterAdvertisement +} + +// ManagedAddressConfig is true when addresses are available via DHCPv6. If +// set, the OtherConfig flag is redundant. +func (i *ICMPv6RouterAdvertisement) ManagedAddressConfig() bool { + return i.Flags&0x80 != 0 +} + +// OtherConfig is true when there is other configuration information available +// via DHCPv6. For example, DNS-related information. +func (i *ICMPv6RouterAdvertisement) OtherConfig() bool { + return i.Flags&0x40 != 0 +} + +// LayerType returns LayerTypeICMPv6NeighborSolicitation. +func (i *ICMPv6NeighborSolicitation) LayerType() gopacket.LayerType { + return LayerTypeICMPv6NeighborSolicitation +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6NeighborSolicitation) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6NeighborSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + df.SetTruncated() + return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor solicitation") + } + + i.TargetAddress = net.IP(data[4:20]) + i.BaseLayer = BaseLayer{data, nil} // assume no payload + + // truncate old options + i.Options = i.Options[:0] + + return i.Options.DecodeFromBytes(data[20:], df) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6NeighborSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := i.Options.SerializeTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(20) + if err != nil { + return err + } + + copy(buf, lotsOfZeros[:4]) + copy(buf[4:], i.TargetAddress) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6NeighborSolicitation) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6NeighborSolicitation +} + +// LayerType returns LayerTypeICMPv6NeighborAdvertisement. +func (i *ICMPv6NeighborAdvertisement) LayerType() gopacket.LayerType { + return LayerTypeICMPv6NeighborAdvertisement +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6NeighborAdvertisement) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6NeighborAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + df.SetTruncated() + return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor advertisement") + } + + i.Flags = uint8(data[0]) + i.TargetAddress = net.IP(data[4:20]) + i.BaseLayer = BaseLayer{data, nil} // assume no payload + + // truncate old options + i.Options = i.Options[:0] + + return i.Options.DecodeFromBytes(data[20:], df) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6NeighborAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := i.Options.SerializeTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(20) + if err != nil { + return err + } + + buf[0] = byte(i.Flags) + copy(buf[1:], lotsOfZeros[:3]) + copy(buf[4:], i.TargetAddress) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6NeighborAdvertisement) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6NeighborAdvertisement +} + +// Router indicates whether the sender is a router or not. +func (i *ICMPv6NeighborAdvertisement) Router() bool { + return i.Flags&0x80 != 0 +} + +// Solicited indicates whether the advertisement was solicited or not. +func (i *ICMPv6NeighborAdvertisement) Solicited() bool { + return i.Flags&0x40 != 0 +} + +// Override indicates whether the advertisement should Override an existing +// cache entry. +func (i *ICMPv6NeighborAdvertisement) Override() bool { + return i.Flags&0x20 != 0 +} + +// LayerType returns LayerTypeICMPv6Redirect. +func (i *ICMPv6Redirect) LayerType() gopacket.LayerType { + return LayerTypeICMPv6Redirect +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *ICMPv6Redirect) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6Redirect) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 36 { + df.SetTruncated() + return errors.New("ICMP layer less then 36 bytes for ICMPv6 redirect") + } + + i.TargetAddress = net.IP(data[4:20]) + i.DestinationAddress = net.IP(data[20:36]) + i.BaseLayer = BaseLayer{data, nil} // assume no payload + + // truncate old options + i.Options = i.Options[:0] + + return i.Options.DecodeFromBytes(data[36:], df) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6Redirect) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := i.Options.SerializeTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(36) + if err != nil { + return err + } + + copy(buf, lotsOfZeros[:4]) + copy(buf[4:], i.TargetAddress) + copy(buf[20:], i.DestinationAddress) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *ICMPv6Redirect) CanDecode() gopacket.LayerClass { + return LayerTypeICMPv6Redirect +} + +func (i ICMPv6Option) String() string { + hd := hex.EncodeToString(i.Data) + if len(hd) > 0 { + hd = " 0x" + hd + } + + switch i.Type { + case ICMPv6OptSourceAddress, ICMPv6OptTargetAddress: + return fmt.Sprintf("ICMPv6Option(%s:%v)", + i.Type, + net.HardwareAddr(i.Data)) + case ICMPv6OptPrefixInfo: + if len(i.Data) == 30 { + prefixLen := uint8(i.Data[0]) + onLink := (i.Data[1]&0x80 != 0) + autonomous := (i.Data[1]&0x40 != 0) + validLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[2:6])) * time.Second + preferredLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[6:10])) * time.Second + + prefix := net.IP(i.Data[14:]) + + return fmt.Sprintf("ICMPv6Option(%s:%v/%v:%t:%t:%v:%v)", + i.Type, + prefix, prefixLen, + onLink, autonomous, + validLifetime, preferredLifetime) + } + case ICMPv6OptRedirectedHeader: + // could invoke IP decoder on data... probably best not to + break + case ICMPv6OptMTU: + if len(i.Data) == 6 { + return fmt.Sprintf("ICMPv6Option(%s:%v)", + i.Type, + binary.BigEndian.Uint32(i.Data[2:])) + } + case ICMPv6OptRecursiveDNSServer: + lifetime := time.Duration(binary.BigEndian.Uint32(i.Data[2:6])) * time.Second + num := (len(i.Data) - 6) / 16 + ips := make([]string, num) + for j := 0; j < num; j++ { + ips[j] = net.IP(i.Data[6+j*16 : 6+(j+1)*16]).String() + } + return fmt.Sprintf("ICMPv6Option(%s:%v:%v)", + i.Type, + lifetime, + strings.Join(ips, ":")) + } + return fmt.Sprintf("ICMPv6Option(%s:%s)", i.Type, hd) +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *ICMPv6Options) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + for len(data) > 0 { + if len(data) < 2 { + df.SetTruncated() + return errors.New("ICMP layer less then 2 bytes for ICMPv6 message option") + } + + // unit is 8 octets, convert to bytes + length := int(data[1]) * 8 + + if length == 0 { + df.SetTruncated() + return errors.New("ICMPv6 message option with length 0") + } + + if len(data) < length { + df.SetTruncated() + return fmt.Errorf("ICMP layer only %v bytes for ICMPv6 message option with length %v", len(data), length) + } + + o := ICMPv6Option{ + Type: ICMPv6Opt(data[0]), + Data: data[2:length], + } + + // chop off option we just consumed + data = data[length:] + + *i = append(*i, o) + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *ICMPv6Options) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + for _, opt := range []ICMPv6Option(*i) { + length := len(opt.Data) + 2 + buf, err := b.PrependBytes(length) + if err != nil { + return err + } + + buf[0] = byte(opt.Type) + buf[1] = byte(length / 8) + copy(buf[2:], opt.Data) + } + + return nil +} + +func decodeICMPv6Echo(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6Echo{} + return decodingLayerDecoder(i, data, p) +} + +func decodeICMPv6RouterSolicitation(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6RouterSolicitation{} + return decodingLayerDecoder(i, data, p) +} + +func decodeICMPv6RouterAdvertisement(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6RouterAdvertisement{} + return decodingLayerDecoder(i, data, p) +} + +func decodeICMPv6NeighborSolicitation(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6NeighborSolicitation{} + return decodingLayerDecoder(i, data, p) +} + +func decodeICMPv6NeighborAdvertisement(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6NeighborAdvertisement{} + return decodingLayerDecoder(i, data, p) +} + +func decodeICMPv6Redirect(data []byte, p gopacket.PacketBuilder) error { + i := &ICMPv6Redirect{} + return decodingLayerDecoder(i, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/igmp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/igmp.go new file mode 100644 index 0000000000..3d086d5be4 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/igmp.go @@ -0,0 +1,357 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "net" + "time" + + "github.com/gopacket/gopacket" +) + +type IGMPType uint8 + +const ( + IGMPMembershipQuery IGMPType = 0x11 // General or group specific query + IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report + IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report + IGMPLeaveGroup IGMPType = 0x17 // Leave Group + IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report +) + +// String conversions for IGMP message types +func (i IGMPType) String() string { + switch i { + case IGMPMembershipQuery: + return "IGMP Membership Query" + case IGMPMembershipReportV1: + return "IGMPv1 Membership Report" + case IGMPMembershipReportV2: + return "IGMPv2 Membership Report" + case IGMPMembershipReportV3: + return "IGMPv3 Membership Report" + case IGMPLeaveGroup: + return "Leave Group" + default: + return "" + } +} + +type IGMPv3GroupRecordType uint8 + +const ( + IGMPIsIn IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x + IGMPIsEx IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x + IGMPToIn IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x + IGMPToEx IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x + IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x + IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x +) + +func (i IGMPv3GroupRecordType) String() string { + switch i { + case IGMPIsIn: + return "MODE_IS_INCLUDE" + case IGMPIsEx: + return "MODE_IS_EXCLUDE" + case IGMPToIn: + return "CHANGE_TO_INCLUDE_MODE" + case IGMPToEx: + return "CHANGE_TO_EXCLUDE_MODE" + case IGMPAllow: + return "ALLOW_NEW_SOURCES" + case IGMPBlock: + return "BLOCK_OLD_SOURCES" + default: + return "" + } +} + +// IGMP represents an IGMPv3 message. +type IGMP struct { + BaseLayer + Type IGMPType + MaxResponseTime time.Duration + Checksum uint16 + GroupAddress net.IP + SupressRouterProcessing bool + RobustnessValue uint8 + IntervalTime time.Duration + SourceAddresses []net.IP + NumberOfGroupRecords uint16 + NumberOfSources uint16 + GroupRecords []IGMPv3GroupRecord + Version uint8 // IGMP protocol version +} + +// IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet. +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Max Resp Time | Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Group Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +type IGMPv1or2 struct { + BaseLayer + Type IGMPType // IGMP message type + MaxResponseTime time.Duration // meaningful only in Membership Query messages + Checksum uint16 // 16-bit checksum of entire ip payload + GroupAddress net.IP // either 0 or an IP multicast address + Version uint8 +} + +// decodeResponse dissects IGMPv1 or IGMPv2 packet. +func (i *IGMPv1or2) decodeResponse(data []byte) error { + if len(data) < 8 { + return errors.New("IGMP packet too small") + } + + i.MaxResponseTime = igmpTimeDecode(data[1]) + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.GroupAddress = net.IP(data[4:8]) + + return nil +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type = 0x22 | Reserved | Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Reserved | Number of Group Records (M) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . Group Record [1] . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . Group Record [2] . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . Group Record [M] . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Record Type | Aux Data Len | Number of Sources (N) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Multicast Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Source Address [1] | +// +- -+ +// | Source Address [2] | +// +- -+ +// | Source Address [N] | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . Auxiliary Data . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// IGMPv3GroupRecord stores individual group records for a V3 Membership Report message. +type IGMPv3GroupRecord struct { + Type IGMPv3GroupRecordType + AuxDataLen uint8 // this should always be 0 as per IGMPv3 spec. + NumberOfSources uint16 + MulticastAddress net.IP + SourceAddresses []net.IP + AuxData uint32 // NOT USED +} + +func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error { + if len(data) < 8 { + return errors.New("IGMPv3 Membership Report too small #1") + } + + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8]) + + recordOffset := 8 + for j := 0; j < int(i.NumberOfGroupRecords); j++ { + if len(data) < recordOffset+8 { + return errors.New("IGMPv3 Membership Report too small #2") + } + + var gr IGMPv3GroupRecord + gr.Type = IGMPv3GroupRecordType(data[recordOffset]) + gr.AuxDataLen = data[recordOffset+1] + gr.NumberOfSources = binary.BigEndian.Uint16(data[recordOffset+2 : recordOffset+4]) + gr.MulticastAddress = net.IP(data[recordOffset+4 : recordOffset+8]) + + if len(data) < recordOffset+8+int(gr.NumberOfSources)*4 { + return errors.New("IGMPv3 Membership Report too small #3") + } + + // append source address records. + for i := 0; i < int(gr.NumberOfSources); i++ { + sourceAddr := net.IP(data[recordOffset+8+i*4 : recordOffset+12+i*4]) + gr.SourceAddresses = append(gr.SourceAddresses, sourceAddr) + } + + i.GroupRecords = append(i.GroupRecords, gr) + recordOffset += 8 + 4*int(gr.NumberOfSources) + } + return nil +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type = 0x11 | Max Resp Code | Checksum | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Group Address | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Resv |S| QRV | QQIC | Number of Sources (N) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Source Address [1] | +// +- -+ +// | Source Address [2] | +// +- . -+ +// | Source Address [N] | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11 +func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error { + if len(data) < 12 { + return errors.New("IGMPv3 Membership Query too small #1") + } + + i.MaxResponseTime = igmpTimeDecode(data[1]) + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.SupressRouterProcessing = data[8]&0x8 != 0 + i.GroupAddress = net.IP(data[4:8]) + i.RobustnessValue = data[8] & 0x7 + i.IntervalTime = igmpTimeDecode(data[9]) + i.NumberOfSources = binary.BigEndian.Uint16(data[10:12]) + + if len(data) < 12+int(i.NumberOfSources)*4 { + return errors.New("IGMPv3 Membership Query too small #2") + } + + for j := 0; j < int(i.NumberOfSources); j++ { + i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4])) + } + + return nil +} + +// igmpTimeDecode decodes the duration created by the given byte, using the +// algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1. +func igmpTimeDecode(t uint8) time.Duration { + if t&0x80 == 0 { + return time.Millisecond * 100 * time.Duration(t) + } + mant := (t & 0x70) >> 4 + exp := t & 0x0F + return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3)) +} + +// LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats. +func (i *IGMP) LayerType() gopacket.LayerType { return LayerTypeIGMP } +func (i *IGMPv1or2) LayerType() gopacket.LayerType { return LayerTypeIGMP } + +func (i *IGMPv1or2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + return errors.New("IGMP Packet too small") + } + + i.Type = IGMPType(data[0]) + i.MaxResponseTime = igmpTimeDecode(data[1]) + i.Checksum = binary.BigEndian.Uint16(data[2:4]) + i.GroupAddress = net.IP(data[4:8]) + + return nil +} + +func (i *IGMPv1or2) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +func (i *IGMPv1or2) CanDecode() gopacket.LayerClass { + return LayerTypeIGMP +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 1 { + return errors.New("IGMP packet is too small") + } + + // common IGMP header values between versions 1..3 of IGMP specification.. + i.Type = IGMPType(data[0]) + + switch i.Type { + case IGMPMembershipQuery: + i.decodeIGMPv3MembershipQuery(data) + case IGMPMembershipReportV3: + i.decodeIGMPv3MembershipReport(data) + default: + return errors.New("unsupported IGMP type") + } + + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (i *IGMP) CanDecode() gopacket.LayerClass { + return LayerTypeIGMP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (i *IGMP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the +// IGMP type are performed against byte[0], logic then iniitalizes and +// passes the appropriate struct (IGMP or IGMPv1or2) to +// decodingLayerDecoder. +func decodeIGMP(data []byte, p gopacket.PacketBuilder) error { + if len(data) < 1 { + return errors.New("IGMP packet is too small") + } + + // byte 0 contains IGMP message type. + switch IGMPType(data[0]) { + case IGMPMembershipQuery: + // IGMPv3 Membership Query payload is >= 12 + if len(data) >= 12 { + i := &IGMP{Version: 3} + return decodingLayerDecoder(i, data, p) + } else if len(data) == 8 { + i := &IGMPv1or2{} + if data[1] == 0x00 { + i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0 + } else { + i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0 + } + + return decodingLayerDecoder(i, data, p) + } + case IGMPMembershipReportV3: + i := &IGMP{Version: 3} + return decodingLayerDecoder(i, data, p) + case IGMPMembershipReportV1: + i := &IGMPv1or2{Version: 1} + return decodingLayerDecoder(i, data, p) + case IGMPLeaveGroup, IGMPMembershipReportV2: + // leave group and Query Report v2 used in IGMPv2 only. + i := &IGMPv1or2{Version: 2} + return decodingLayerDecoder(i, data, p) + default: + } + + return errors.New("Unable to determine IGMP type.") +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip4.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip4.go new file mode 100644 index 0000000000..1538ab080d --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip4.go @@ -0,0 +1,324 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + "strings" + + "github.com/gopacket/gopacket" +) + +type IPv4Flag uint8 + +const ( + IPv4EvilBit IPv4Flag = 1 << 2 // http://tools.ietf.org/html/rfc3514 ;) + IPv4DontFragment IPv4Flag = 1 << 1 + IPv4MoreFragments IPv4Flag = 1 << 0 +) + +func (f IPv4Flag) String() string { + var s []string + if f&IPv4EvilBit != 0 { + s = append(s, "Evil") + } + if f&IPv4DontFragment != 0 { + s = append(s, "DF") + } + if f&IPv4MoreFragments != 0 { + s = append(s, "MF") + } + return strings.Join(s, "|") +} + +// IPv4 is the header of an IP packet. +type IPv4 struct { + BaseLayer + Version uint8 + IHL uint8 + TOS uint8 + Length uint16 + Id uint16 + Flags IPv4Flag + FragOffset uint16 + TTL uint8 + Protocol IPProtocol + Checksum uint16 + SrcIP net.IP + DstIP net.IP + Options []IPv4Option + Padding []byte +} + +// LayerType returns LayerTypeIPv4 +func (i *IPv4) LayerType() gopacket.LayerType { return LayerTypeIPv4 } +func (i *IPv4) NetworkFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointIPv4, i.SrcIP, i.DstIP) +} + +type IPv4Option struct { + OptionType uint8 + OptionLength uint8 + OptionData []byte +} + +func (i IPv4Option) String() string { + return fmt.Sprintf("IPv4Option(%v:%v)", i.OptionType, i.OptionData) +} + +// for the current ipv4 options, return the number of bytes (including +// padding that the options used) +func (ip *IPv4) getIPv4OptionSize() uint8 { + optionSize := uint8(0) + for _, opt := range ip.Options { + switch opt.OptionType { + case 0: + // this is the end of option lists + optionSize++ + case 1: + // this is the padding + optionSize++ + default: + optionSize += opt.OptionLength + + } + } + // make sure the options are aligned to 32 bit boundary + if (optionSize % 4) != 0 { + optionSize += 4 - (optionSize % 4) + } + return optionSize +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +func (ip *IPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + optionLength := ip.getIPv4OptionSize() + bytes, err := b.PrependBytes(20 + int(optionLength)) + if err != nil { + return err + } + if opts.FixLengths { + ip.IHL = 5 + (optionLength / 4) + ip.Length = uint16(len(b.Bytes())) + } + bytes[0] = (ip.Version << 4) | ip.IHL + bytes[1] = ip.TOS + binary.BigEndian.PutUint16(bytes[2:], ip.Length) + binary.BigEndian.PutUint16(bytes[4:], ip.Id) + binary.BigEndian.PutUint16(bytes[6:], ip.flagsfrags()) + bytes[8] = ip.TTL + bytes[9] = byte(ip.Protocol) + if err := ip.AddressTo4(); err != nil { + return err + } + copy(bytes[12:16], ip.SrcIP) + copy(bytes[16:20], ip.DstIP) + + curLocation := 20 + // Now, we will encode the options + for _, opt := range ip.Options { + switch opt.OptionType { + case 0: + // this is the end of option lists + bytes[curLocation] = 0 + curLocation++ + case 1: + // this is the padding + bytes[curLocation] = 1 + curLocation++ + default: + bytes[curLocation] = opt.OptionType + bytes[curLocation+1] = opt.OptionLength + + // sanity checking to protect us from buffer overrun + if len(opt.OptionData) > int(opt.OptionLength-2) { + return errors.New("option length is smaller than length of option data") + } + copy(bytes[curLocation+2:curLocation+int(opt.OptionLength)], opt.OptionData) + curLocation += int(opt.OptionLength) + } + } + + if opts.ComputeChecksums { + // Clear checksum bytes + bytes[10] = 0 + bytes[11] = 0 + + csum := gopacket.ComputeChecksum(bytes, 0) + ip.Checksum = gopacket.FoldChecksum(csum) + } + binary.BigEndian.PutUint16(bytes[10:], ip.Checksum) + return nil +} + +func (ip *IPv4) flagsfrags() (ff uint16) { + ff |= uint16(ip.Flags) << 13 + ff |= ip.FragOffset + return +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (ip *IPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + df.SetTruncated() + return fmt.Errorf("Invalid ip4 header. Length %d less than 20", len(data)) + } + + ip.Length = binary.BigEndian.Uint16(data[2:4]) + ip.IHL = uint8(data[0]) & 0x0F + + // This code is added for the following enviroment: + // * Windows 10 with TSO option activated. ( tested on Hyper-V, RealTek ethernet driver ) + if ip.Length == 0 { + // If using TSO(TCP Segmentation Offload), length is zero. + // The actual packet length is the length of data. + ip.Length = uint16(len(data)) + } + + if ip.Length < 20 { + return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length) + } else if ip.IHL < 5 { + return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL) + } else if int(ip.IHL*4) > int(ip.Length) { + return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length) + } + + if cmp := len(data) - int(ip.Length); cmp > 0 { + data = data[:ip.Length] + } else if cmp < 0 { + df.SetTruncated() + if int(ip.IHL)*4 > len(data) { + return errors.New("Not all IP header bytes available") + } + } + + ip.Options = ip.Options[:0] + ip.Contents = data[:ip.IHL*4] + ip.Payload = data[ip.IHL*4:] + + // From here on, data contains the header options. + headerOptionsData := data[20 : ip.IHL*4] + // Pull out IP options +pullOutOptions: + for len(headerOptionsData) > 0 { + if ip.Options == nil { + // Pre-allocate to avoid growing the slice too much. + ip.Options = make([]IPv4Option, 0, 4) + } + + opt := IPv4Option{OptionType: headerOptionsData[0]} + switch opt.OptionType { + case 0: // End of options + opt.OptionLength = 1 + ip.Options = append(ip.Options, opt) + ip.Padding = headerOptionsData[1:] + headerOptionsData = headerOptionsData[1:] + break pullOutOptions + case 1: // 1 byte padding + opt.OptionLength = 1 + headerOptionsData = headerOptionsData[1:] + ip.Options = append(ip.Options, opt) + default: + if len(headerOptionsData) < 2 { + df.SetTruncated() + return fmt.Errorf("Invalid ip4 option length. Length %d less than 2", len(headerOptionsData)) + } + + opt.OptionLength = headerOptionsData[1] + if len(headerOptionsData) < int(opt.OptionLength) { + df.SetTruncated() + return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength) + } + if opt.OptionLength <= 2 { + return fmt.Errorf("Invalid IP option type %v length %d. Must be greater than 2", opt.OptionType, opt.OptionLength) + } + opt.OptionData = headerOptionsData[2:opt.OptionLength] + headerOptionsData = headerOptionsData[opt.OptionLength:] + ip.Options = append(ip.Options, opt) + } + } + + flagsfrags := binary.BigEndian.Uint16(data[6:8]) + ip.Version = data[0] >> 4 + ip.TOS = data[1] + ip.Id = binary.BigEndian.Uint16(data[4:6]) + ip.Flags = IPv4Flag(flagsfrags >> 13) + ip.FragOffset = flagsfrags & 0x1FFF + ip.TTL = data[8] + ip.Protocol = IPProtocol(data[9]) + ip.Checksum = binary.BigEndian.Uint16(data[10:12]) + ip.SrcIP = data[12:16] + ip.DstIP = data[16:20] + + return nil +} + +func (i *IPv4) CanDecode() gopacket.LayerClass { + return LayerTypeIPv4 +} + +func (i *IPv4) NextLayerType() gopacket.LayerType { + if i.Flags&IPv4MoreFragments != 0 || i.FragOffset != 0 { + return gopacket.LayerTypeFragment + } + return i.Protocol.LayerType() +} + +func decodeIPv4(data []byte, p gopacket.PacketBuilder) error { + ip := &IPv4{} + err := ip.DecodeFromBytes(data, p) + p.AddLayer(ip) + p.SetNetworkLayer(ip) + if err != nil { + return err + } + return p.NextDecoder(ip.NextLayerType()) +} + +func checkIPv4Address(addr net.IP) (net.IP, error) { + if c := addr.To4(); c != nil { + return c, nil + } + if len(addr) == net.IPv6len { + return nil, errors.New("address is IPv6") + } + return nil, fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv4len) +} + +func (ip *IPv4) AddressTo4() error { + var src, dst net.IP + + if addr, err := checkIPv4Address(ip.SrcIP); err != nil { + return fmt.Errorf("Invalid source IPv4 address (%s)", err) + } else { + src = addr + } + if addr, err := checkIPv4Address(ip.DstIP); err != nil { + return fmt.Errorf("Invalid destination IPv4 address (%s)", err) + } else { + dst = addr + } + ip.SrcIP = src + ip.DstIP = dst + return nil +} + +func (ip *IPv4) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + existing := ip.Checksum + verification := gopacket.ComputeChecksum(ip.Contents, 0) + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip6.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip6.go new file mode 100644 index 0000000000..bbb012420b --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ip6.go @@ -0,0 +1,761 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +const ( + // IPv6HopByHopOptionJumbogram code as defined in RFC 2675 + IPv6HopByHopOptionJumbogram = 0xC2 +) + +const ( + ipv6MaxPayloadLength = 65535 +) + +// IPv6 is the layer for the IPv6 header. +type IPv6 struct { + // http://www.networksorcery.com/enp/protocol/ipv6.htm + BaseLayer + Version uint8 + TrafficClass uint8 + FlowLabel uint32 + Length uint16 + NextHeader IPProtocol + HopLimit uint8 + SrcIP net.IP + DstIP net.IP + HopByHop *IPv6HopByHop + // hbh will be pointed to by HopByHop if that layer exists. + hbh IPv6HopByHop +} + +// LayerType returns LayerTypeIPv6 +func (ipv6 *IPv6) LayerType() gopacket.LayerType { return LayerTypeIPv6 } + +// NetworkFlow returns this new Flow (EndpointIPv6, SrcIP, DstIP) +func (ipv6 *IPv6) NetworkFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointIPv6, ipv6.SrcIP, ipv6.DstIP) +} + +// Search for Jumbo Payload TLV in IPv6HopByHop and return (length, true) if found +func getIPv6HopByHopJumboLength(hopopts *IPv6HopByHop) (uint32, bool, error) { + var tlv *IPv6HopByHopOption + + for _, t := range hopopts.Options { + if t.OptionType == IPv6HopByHopOptionJumbogram { + tlv = t + break + } + } + if tlv == nil { + // Not found + return 0, false, nil + } + if len(tlv.OptionData) != 4 { + return 0, false, errors.New("Jumbo length TLV data must have length 4") + } + l := binary.BigEndian.Uint32(tlv.OptionData) + if l <= ipv6MaxPayloadLength { + return 0, false, fmt.Errorf("Jumbo length cannot be less than %d", ipv6MaxPayloadLength+1) + } + // Found + return l, true, nil +} + +// Adds zero-valued Jumbo TLV to IPv6 header if it does not exist +// (if necessary add hop-by-hop header) +func addIPv6JumboOption(ip6 *IPv6) { + var tlv *IPv6HopByHopOption + + if ip6.HopByHop == nil { + // Add IPv6 HopByHop + ip6.HopByHop = &IPv6HopByHop{} + ip6.HopByHop.NextHeader = ip6.NextHeader + ip6.HopByHop.HeaderLength = 0 + ip6.NextHeader = IPProtocolIPv6HopByHop + } + for _, t := range ip6.HopByHop.Options { + if t.OptionType == IPv6HopByHopOptionJumbogram { + tlv = t + break + } + } + if tlv == nil { + // Add Jumbo TLV + tlv = &IPv6HopByHopOption{} + ip6.HopByHop.Options = append(ip6.HopByHop.Options, tlv) + } + tlv.SetJumboLength(0) +} + +// Set jumbo length in serialized IPv6 payload (starting with HopByHop header) +func setIPv6PayloadJumboLength(hbh []byte) error { + pLen := len(hbh) + if pLen < 8 { + //HopByHop is minimum 8 bytes + return fmt.Errorf("Invalid IPv6 payload (length %d)", pLen) + } + hbhLen := int((hbh[1] + 1) * 8) + if hbhLen > pLen { + return fmt.Errorf("Invalid hop-by-hop length (length: %d, payload: %d", hbhLen, pLen) + } + offset := 2 //start with options + for offset < hbhLen { + opt := hbh[offset] + if opt == 0 { + //Pad1 + offset++ + continue + } + optLen := int(hbh[offset+1]) + if opt == IPv6HopByHopOptionJumbogram { + if optLen == 4 { + binary.BigEndian.PutUint32(hbh[offset+2:], uint32(pLen)) + return nil + } + return fmt.Errorf("Jumbo TLV too short (%d bytes)", optLen) + } + offset += 2 + optLen + } + return errors.New("Jumbo TLV not found") +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (ipv6 *IPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var jumbo bool + var err error + + payload := b.Bytes() + pLen := len(payload) + if pLen > ipv6MaxPayloadLength { + jumbo = true + if opts.FixLengths { + // We need to set the length later because the hop-by-hop header may + // not exist or else need padding, so pLen may yet change + addIPv6JumboOption(ipv6) + } else if ipv6.HopByHop == nil { + return fmt.Errorf("Cannot fit payload length of %d into IPv6 packet", pLen) + } else { + _, ok, err := getIPv6HopByHopJumboLength(ipv6.HopByHop) + if err != nil { + return err + } + if !ok { + return errors.New("Missing jumbo length hop-by-hop option") + } + } + } + + hbhAlreadySerialized := false + if ipv6.HopByHop != nil { + for _, l := range b.Layers() { + if l == LayerTypeIPv6HopByHop { + hbhAlreadySerialized = true + break + } + } + } + if ipv6.HopByHop != nil && !hbhAlreadySerialized { + if ipv6.NextHeader != IPProtocolIPv6HopByHop { + // Just fix it instead of throwing an error + ipv6.NextHeader = IPProtocolIPv6HopByHop + } + err = ipv6.HopByHop.SerializeTo(b, opts) + if err != nil { + return err + } + payload = b.Bytes() + pLen = len(payload) + if opts.FixLengths && jumbo { + err := setIPv6PayloadJumboLength(payload) + if err != nil { + return err + } + } + } + + if !jumbo && pLen > ipv6MaxPayloadLength { + return errors.New("Cannot fit payload into IPv6 header") + } + bytes, err := b.PrependBytes(40) + if err != nil { + return err + } + bytes[0] = (ipv6.Version << 4) | (ipv6.TrafficClass >> 4) + bytes[1] = (ipv6.TrafficClass << 4) | uint8(ipv6.FlowLabel>>16) + binary.BigEndian.PutUint16(bytes[2:], uint16(ipv6.FlowLabel)) + if opts.FixLengths { + if jumbo { + ipv6.Length = 0 + } else { + ipv6.Length = uint16(pLen) + } + } + binary.BigEndian.PutUint16(bytes[4:], ipv6.Length) + bytes[6] = byte(ipv6.NextHeader) + bytes[7] = byte(ipv6.HopLimit) + if err := ipv6.AddressTo16(); err != nil { + return err + } + copy(bytes[8:], ipv6.SrcIP) + copy(bytes[24:], ipv6.DstIP) + return nil +} + +// DecodeFromBytes implementation according to gopacket.DecodingLayer +func (ipv6 *IPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 40 { + df.SetTruncated() + return fmt.Errorf("Invalid ip6 header. Length %d less than 40", len(data)) + } + ipv6.Version = uint8(data[0]) >> 4 + ipv6.TrafficClass = uint8((binary.BigEndian.Uint16(data[0:2]) >> 4) & 0x00FF) + ipv6.FlowLabel = binary.BigEndian.Uint32(data[0:4]) & 0x000FFFFF + ipv6.Length = binary.BigEndian.Uint16(data[4:6]) + ipv6.NextHeader = IPProtocol(data[6]) + ipv6.HopLimit = data[7] + ipv6.SrcIP = data[8:24] + ipv6.DstIP = data[24:40] + ipv6.HopByHop = nil + ipv6.BaseLayer = BaseLayer{data[:40], data[40:]} + + // We treat a HopByHop IPv6 option as part of the IPv6 packet, since its + // options are crucial for understanding what's actually happening per packet. + if ipv6.NextHeader == IPProtocolIPv6HopByHop { + err := ipv6.hbh.DecodeFromBytes(ipv6.Payload, df) + if err != nil { + return err + } + ipv6.HopByHop = &ipv6.hbh + pEnd, jumbo, err := getIPv6HopByHopJumboLength(ipv6.HopByHop) + if err != nil { + return err + } + if jumbo && ipv6.Length == 0 { + pEnd := int(pEnd) + if pEnd > len(ipv6.Payload) { + df.SetTruncated() + pEnd = len(ipv6.Payload) + } + ipv6.Payload = ipv6.Payload[:pEnd] + return nil + } else if jumbo && ipv6.Length != 0 { + return errors.New("IPv6 has jumbo length and IPv6 length is not 0") + } else if !jumbo && ipv6.Length == 0 { + return errors.New("IPv6 length 0, but HopByHop header does not have jumbogram option") + } else { + ipv6.Payload = ipv6.Payload[ipv6.hbh.ActualLength:] + } + } + + if ipv6.Length == 0 { + return fmt.Errorf("IPv6 length 0, but next header is %v, not HopByHop", ipv6.NextHeader) + } + + pEnd := int(ipv6.Length) + if pEnd > len(ipv6.Payload) { + df.SetTruncated() + pEnd = len(ipv6.Payload) + } + ipv6.Payload = ipv6.Payload[:pEnd] + + return nil +} + +// CanDecode implementation according to gopacket.DecodingLayer +func (ipv6 *IPv6) CanDecode() gopacket.LayerClass { + return LayerTypeIPv6 +} + +// NextLayerType implementation according to gopacket.DecodingLayer +func (ipv6 *IPv6) NextLayerType() gopacket.LayerType { + if ipv6.HopByHop != nil { + return ipv6.HopByHop.NextHeader.LayerType() + } + return ipv6.NextHeader.LayerType() +} + +func decodeIPv6(data []byte, p gopacket.PacketBuilder) error { + ip6 := &IPv6{} + err := ip6.DecodeFromBytes(data, p) + p.AddLayer(ip6) + p.SetNetworkLayer(ip6) + if ip6.HopByHop != nil { + p.AddLayer(ip6.HopByHop) + } + if err != nil { + return err + } + return p.NextDecoder(ip6.NextLayerType()) +} + +type ipv6HeaderTLVOption struct { + OptionType, OptionLength uint8 + ActualLength int + OptionData []byte + OptionAlignment [2]uint8 // Xn+Y = [2]uint8{X, Y} +} + +func (h *ipv6HeaderTLVOption) serializeTo(data []byte, fixLengths bool, dryrun bool) int { + if fixLengths { + h.OptionLength = uint8(len(h.OptionData)) + } + length := int(h.OptionLength) + 2 + if !dryrun { + data[0] = h.OptionType + data[1] = h.OptionLength + copy(data[2:], h.OptionData) + } + return length +} + +func decodeIPv6HeaderTLVOption(data []byte, df gopacket.DecodeFeedback) (h *ipv6HeaderTLVOption, _ error) { + if len(data) < 2 { + df.SetTruncated() + return nil, errors.New("IPv6 header option too small") + } + h = &ipv6HeaderTLVOption{} + if data[0] == 0 { + h.ActualLength = 1 + return + } + h.OptionType = data[0] + h.OptionLength = data[1] + h.ActualLength = int(h.OptionLength) + 2 + if len(data) < h.ActualLength { + df.SetTruncated() + return nil, errors.New("IPv6 header TLV option too small") + } + h.OptionData = data[2:h.ActualLength] + return +} + +func serializeTLVOptionPadding(data []byte, padLength int) { + if padLength <= 0 { + return + } + if padLength == 1 { + data[0] = 0x0 + return + } + tlvLength := uint8(padLength) - 2 + data[0] = 0x1 + data[1] = tlvLength + if tlvLength != 0 { + for k := range data[2:] { + data[k+2] = 0x0 + } + } + return +} + +// If buf is 'nil' do a serialize dry run +func serializeIPv6HeaderTLVOptions(buf []byte, options []*ipv6HeaderTLVOption, fixLengths bool) int { + var l int + + dryrun := buf == nil + length := 2 + for _, opt := range options { + if fixLengths { + x := int(opt.OptionAlignment[0]) + y := int(opt.OptionAlignment[1]) + if x != 0 { + n := length / x + offset := x*n + y + if offset < length { + offset += x + } + if length != offset { + pad := offset - length + if !dryrun { + serializeTLVOptionPadding(buf[length-2:], pad) + } + length += pad + } + } + } + if dryrun { + l = opt.serializeTo(nil, fixLengths, true) + } else { + l = opt.serializeTo(buf[length-2:], fixLengths, false) + } + length += l + } + if fixLengths { + pad := length % 8 + if pad != 0 { + if !dryrun { + serializeTLVOptionPadding(buf[length-2:], pad) + } + length += pad + } + } + return length - 2 +} + +type ipv6ExtensionBase struct { + BaseLayer + NextHeader IPProtocol + HeaderLength uint8 + ActualLength int +} + +func decodeIPv6ExtensionBase(data []byte, df gopacket.DecodeFeedback) (i ipv6ExtensionBase, returnedErr error) { + if len(data) < 2 { + df.SetTruncated() + return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than 2", len(data)) + } + i.NextHeader = IPProtocol(data[0]) + i.HeaderLength = data[1] + i.ActualLength = int(i.HeaderLength)*8 + 8 + if len(data) < i.ActualLength { + return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than specified length %d", len(data), i.ActualLength) + } + i.Contents = data[:i.ActualLength] + i.Payload = data[i.ActualLength:] + return +} + +// IPv6ExtensionSkipper is a DecodingLayer which decodes and ignores v6 +// extensions. You can use it with a DecodingLayerParser to handle IPv6 stacks +// which may or may not have extensions. +type IPv6ExtensionSkipper struct { + NextHeader IPProtocol + BaseLayer +} + +// DecodeFromBytes implementation according to gopacket.DecodingLayer +func (i *IPv6ExtensionSkipper) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + extension, err := decodeIPv6ExtensionBase(data, df) + if err != nil { + return err + } + i.BaseLayer = BaseLayer{data[:extension.ActualLength], data[extension.ActualLength:]} + i.NextHeader = extension.NextHeader + return nil +} + +// CanDecode implementation according to gopacket.DecodingLayer +func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass { + return LayerClassIPv6Extension +} + +// NextLayerType implementation according to gopacket.DecodingLayer +func (i *IPv6ExtensionSkipper) NextLayerType() gopacket.LayerType { + return i.NextHeader.LayerType() +} + +// IPv6HopByHopOption is a TLV option present in an IPv6 hop-by-hop extension. +type IPv6HopByHopOption ipv6HeaderTLVOption + +// IPv6HopByHop is the IPv6 hop-by-hop extension. +type IPv6HopByHop struct { + ipv6ExtensionBase + Options []*IPv6HopByHopOption +} + +// LayerType returns LayerTypeIPv6HopByHop. +func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop } + +// SerializeTo implementation according to gopacket.SerializableLayer +func (i *IPv6HopByHop) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var bytes []byte + var err error + + o := make([]*ipv6HeaderTLVOption, 0, len(i.Options)) + for _, v := range i.Options { + o = append(o, (*ipv6HeaderTLVOption)(v)) + } + + l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths) + bytes, err = b.PrependBytes(l) + if err != nil { + return err + } + serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths) + + length := len(bytes) + 2 + if length%8 != 0 { + return errors.New("IPv6HopByHop actual length must be multiple of 8") + } + bytes, err = b.PrependBytes(2) + if err != nil { + return err + } + bytes[0] = uint8(i.NextHeader) + if opts.FixLengths { + i.HeaderLength = uint8((length / 8) - 1) + } + bytes[1] = uint8(i.HeaderLength) + return nil +} + +// DecodeFromBytes implementation according to gopacket.DecodingLayer +func (i *IPv6HopByHop) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + var err error + i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df) + if err != nil { + return err + } + i.Options = i.Options[:0] + offset := 2 + for offset < i.ActualLength { + opt, err := decodeIPv6HeaderTLVOption(data[offset:], df) + if err != nil { + return err + } + i.Options = append(i.Options, (*IPv6HopByHopOption)(opt)) + offset += opt.ActualLength + } + return nil +} + +func decodeIPv6HopByHop(data []byte, p gopacket.PacketBuilder) error { + i := &IPv6HopByHop{} + err := i.DecodeFromBytes(data, p) + p.AddLayer(i) + if err != nil { + return err + } + return p.NextDecoder(i.NextHeader) +} + +// SetJumboLength adds the IPv6HopByHopOptionJumbogram with the given length +func (o *IPv6HopByHopOption) SetJumboLength(len uint32) { + o.OptionType = IPv6HopByHopOptionJumbogram + o.OptionLength = 4 + o.ActualLength = 6 + if o.OptionData == nil { + o.OptionData = make([]byte, 4) + } + binary.BigEndian.PutUint32(o.OptionData, len) + o.OptionAlignment = [2]uint8{4, 2} +} + +// IPv6Routing is the IPv6 routing extension. +type IPv6Routing struct { + ipv6ExtensionBase + RoutingType uint8 + SegmentsLeft uint8 + // This segment is supposed to be zero according to RFC2460, the second set of + // 4 bytes in the extension. + Reserved []byte + // SourceRoutingIPs is the set of IPv6 addresses requested for source routing, + // set only if RoutingType == 0. + SourceRoutingIPs []net.IP +} + +// LayerType returns LayerTypeIPv6Routing. +func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing } + +// SerializeTo implementation according to gopacket.SerializableLayer +func (i *IPv6Routing) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + const ipv6HeaderBaseLen = 8 + totalLen := ipv6HeaderBaseLen + len(i.SourceRoutingIPs)*net.IPv6len + hdrExtLen := (totalLen - ipv6HeaderBaseLen) / ipv6HeaderBaseLen + + bytes, err := b.PrependBytes(totalLen) + if err != nil { + return err + } + bytes[0] = byte(i.ipv6ExtensionBase.NextHeader) + bytes[1] = byte(hdrExtLen) + bytes[2] = i.RoutingType + bytes[3] = i.SegmentsLeft + copy(bytes[4:8], i.Reserved) + for i, ip := range i.SourceRoutingIPs { + offset := 8 + i*16 + copy(bytes[offset:offset+16], ip.To16()) + } + return nil +} + +func decodeIPv6Routing(data []byte, p gopacket.PacketBuilder) error { + base, err := decodeIPv6ExtensionBase(data, p) + if err != nil { + return err + } + i := &IPv6Routing{ + ipv6ExtensionBase: base, + RoutingType: data[2], + SegmentsLeft: data[3], + Reserved: data[4:8], + } + switch i.RoutingType { + case 0: // Source routing + if (i.ActualLength-8)%16 != 0 { + return fmt.Errorf("Invalid IPv6 source routing, length of type 0 packet %d", i.ActualLength) + } + for d := i.Contents[8:]; len(d) >= 16; d = d[16:] { + i.SourceRoutingIPs = append(i.SourceRoutingIPs, net.IP(d[:16])) + } + default: + return fmt.Errorf("Unknown IPv6 routing header type %d", i.RoutingType) + } + p.AddLayer(i) + return p.NextDecoder(i.NextHeader) +} + +// IPv6Fragment is the IPv6 fragment header, used for packet +// fragmentation/defragmentation. +type IPv6Fragment struct { + BaseLayer + NextHeader IPProtocol + // Reserved1 is bits [8-16), from least to most significant, 0-indexed + Reserved1 uint8 + FragmentOffset uint16 + // Reserved2 is bits [29-31), from least to most significant, 0-indexed + Reserved2 uint8 + MoreFragments bool + Identification uint32 +} + +func (i *IPv6Fragment) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + data, err := b.PrependBytes(8) + if err != nil { + return err + } + + data[0] = uint8(i.NextHeader) + data[1] = i.Reserved1 + binary.BigEndian.PutUint16(data[2:4], i.FragmentOffset<<3) + data[3] = data[3] | ((i.Reserved2 << 1) & 0x6) + if i.MoreFragments { + data[3] = data[3] | 0x1 + } + binary.BigEndian.PutUint32(data[4:8], i.Identification) + return nil +} + +// LayerType returns LayerTypeIPv6Fragment. +func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment } + +func decodeIPv6Fragment(data []byte, p gopacket.PacketBuilder) error { + if len(data) < 8 { + p.SetTruncated() + return fmt.Errorf("Invalid ip6-fragment header. Length %d less than 8", len(data)) + } + i := &IPv6Fragment{ + BaseLayer: BaseLayer{data[:8], data[8:]}, + NextHeader: IPProtocol(data[0]), + Reserved1: data[1], + FragmentOffset: binary.BigEndian.Uint16(data[2:4]) >> 3, + Reserved2: data[3] & 0x6 >> 1, + MoreFragments: data[3]&0x1 != 0, + Identification: binary.BigEndian.Uint32(data[4:8]), + } + p.AddLayer(i) + return p.NextDecoder(gopacket.DecodeFragment) +} + +// IPv6DestinationOption is a TLV option present in an IPv6 destination options extension. +type IPv6DestinationOption ipv6HeaderTLVOption + +// IPv6Destination is the IPv6 destination options header. +type IPv6Destination struct { + ipv6ExtensionBase + Options []*IPv6DestinationOption +} + +// LayerType returns LayerTypeIPv6Destination. +func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination } + +// DecodeFromBytes implementation according to gopacket.DecodingLayer +func (i *IPv6Destination) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + var err error + i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df) + if err != nil { + return err + } + offset := 2 + for offset < i.ActualLength { + opt, err := decodeIPv6HeaderTLVOption(data[offset:], df) + if err != nil { + return err + } + i.Options = append(i.Options, (*IPv6DestinationOption)(opt)) + offset += opt.ActualLength + } + return nil +} + +func decodeIPv6Destination(data []byte, p gopacket.PacketBuilder) error { + i := &IPv6Destination{} + err := i.DecodeFromBytes(data, p) + p.AddLayer(i) + if err != nil { + return err + } + return p.NextDecoder(i.NextHeader) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (i *IPv6Destination) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var bytes []byte + var err error + + o := make([]*ipv6HeaderTLVOption, 0, len(i.Options)) + for _, v := range i.Options { + o = append(o, (*ipv6HeaderTLVOption)(v)) + } + + l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths) + bytes, err = b.PrependBytes(l) + if err != nil { + return err + } + serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths) + + length := len(bytes) + 2 + if length%8 != 0 { + return errors.New("IPv6Destination actual length must be multiple of 8") + } + bytes, err = b.PrependBytes(2) + if err != nil { + return err + } + bytes[0] = uint8(i.NextHeader) + if opts.FixLengths { + i.HeaderLength = uint8((length / 8) - 1) + } + bytes[1] = uint8(i.HeaderLength) + return nil +} + +func checkIPv6Address(addr net.IP) error { + if len(addr) == net.IPv6len { + return nil + } + if len(addr) == net.IPv4len { + return errors.New("address is IPv4") + } + return fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv6len) +} + +// AddressTo16 ensures IPv6.SrcIP and IPv6.DstIP are actually IPv6 addresses (i.e. 16 byte addresses) +func (ipv6 *IPv6) AddressTo16() error { + if err := checkIPv6Address(ipv6.SrcIP); err != nil { + return fmt.Errorf("Invalid source IPv6 address (%s)", err) + } + if err := checkIPv6Address(ipv6.DstIP); err != nil { + return fmt.Errorf("Invalid destination IPv6 address (%s)", err) + } + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ipsec.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ipsec.go new file mode 100644 index 0000000000..91fc845028 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ipsec.go @@ -0,0 +1,114 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// IPSecAH is the authentication header for IPv4/6 defined in +// http://tools.ietf.org/html/rfc2402 +type IPSecAH struct { + // While the auth header can be used for both IPv4 and v6, its format is that of + // an IPv6 extension (NextHeader, PayloadLength, etc...), so we use ipv6ExtensionBase + // to build it. + ipv6ExtensionBase + Reserved uint16 + SPI, Seq uint32 + AuthenticationData []byte +} + +// LayerType returns LayerTypeIPSecAH. +func (i *IPSecAH) LayerType() gopacket.LayerType { return LayerTypeIPSecAH } + +func decodeIPSecAH(data []byte, p gopacket.PacketBuilder) error { + i := &IPSecAH{} + return decodingLayerDecoder(i, data, p) +} + +// DecodeFromBytes takes a byte buffer and decodes +func (i *IPSecAH) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 12 { + df.SetTruncated() + return errors.New("IPSec AH packet less than 12 bytes") + } + + i.ipv6ExtensionBase = ipv6ExtensionBase{ + NextHeader: IPProtocol(data[0]), + HeaderLength: data[1], + } + + i.Reserved = binary.BigEndian.Uint16(data[2:4]) + i.SPI = binary.BigEndian.Uint32(data[4:8]) + i.Seq = binary.BigEndian.Uint32(data[8:12]) + + i.ActualLength = (int(i.HeaderLength) + 2) * 4 + if len(data) < i.ActualLength { + df.SetTruncated() + return errors.New("Truncated AH packet < ActualLength") + } + i.AuthenticationData = data[12:i.ActualLength] + i.Contents = data[:i.ActualLength] + i.Payload = data[i.ActualLength:] + + return nil +} + +// CanDecode returns the layer type this DecodingLayer can decode +func (i *IPSecAH) CanDecode() gopacket.LayerClass { + return LayerTypeIPSecAH +} + +// NextLayerType returns the next layer we should see after IPSecAH +func (i *IPSecAH) NextLayerType() gopacket.LayerType { + return i.NextHeader.LayerType() +} + +// IPSecESP is the encapsulating security payload defined in +// http://tools.ietf.org/html/rfc2406 +type IPSecESP struct { + BaseLayer + SPI, Seq uint32 + // Encrypted contains the encrypted set of bytes sent in an ESP + Encrypted []byte +} + +// LayerType returns LayerTypeIPSecESP. +func (i *IPSecESP) LayerType() gopacket.LayerType { return LayerTypeIPSecESP } + +func decodeIPSecESP(data []byte, p gopacket.PacketBuilder) error { + i := &IPSecESP{} + return decodingLayerDecoder(i, data, p) +} + +// DecodeFromBytes takes a byte buffer and decodes +func (i *IPSecESP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return errors.New("IPSec ESP packet less than 8 bytes") + } + + i.BaseLayer = BaseLayer{data, nil} + i.SPI = binary.BigEndian.Uint32(data[:4]) + i.Seq = binary.BigEndian.Uint32(data[4:8]) + i.Encrypted = data[8:] + + return nil +} + +// CanDecode returns the layer type this DecodingLayer can decode +func (i *IPSecESP) CanDecode() gopacket.LayerClass { + return LayerTypeIPSecESP +} + +// NextLayerType retuns the next layer we should see after IPSecESP +func (i *IPSecESP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/layertypes.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/layertypes.go new file mode 100644 index 0000000000..30931e762d --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/layertypes.go @@ -0,0 +1,231 @@ +// 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 layers + +import ( + "github.com/gopacket/gopacket" +) + +var ( + LayerTypeARP = gopacket.RegisterLayerType(10, gopacket.LayerTypeMetadata{Name: "ARP", Decoder: gopacket.DecodeFunc(decodeARP)}) + LayerTypeCiscoDiscovery = gopacket.RegisterLayerType(11, gopacket.LayerTypeMetadata{Name: "CiscoDiscovery", Decoder: gopacket.DecodeFunc(decodeCiscoDiscovery)}) + LayerTypeEthernetCTP = gopacket.RegisterLayerType(12, gopacket.LayerTypeMetadata{Name: "EthernetCTP", Decoder: gopacket.DecodeFunc(decodeEthernetCTP)}) + LayerTypeEthernetCTPForwardData = gopacket.RegisterLayerType(13, gopacket.LayerTypeMetadata{Name: "EthernetCTPForwardData", Decoder: nil}) + LayerTypeEthernetCTPReply = gopacket.RegisterLayerType(14, gopacket.LayerTypeMetadata{Name: "EthernetCTPReply", Decoder: nil}) + LayerTypeDot1Q = gopacket.RegisterLayerType(15, gopacket.LayerTypeMetadata{Name: "Dot1Q", Decoder: gopacket.DecodeFunc(decodeDot1Q)}) + LayerTypeEtherIP = gopacket.RegisterLayerType(16, gopacket.LayerTypeMetadata{Name: "EtherIP", Decoder: gopacket.DecodeFunc(decodeEtherIP)}) + LayerTypeEthernet = gopacket.RegisterLayerType(17, gopacket.LayerTypeMetadata{Name: "Ethernet", Decoder: gopacket.DecodeFunc(decodeEthernet)}) + LayerTypeGRE = gopacket.RegisterLayerType(18, gopacket.LayerTypeMetadata{Name: "GRE", Decoder: gopacket.DecodeFunc(decodeGRE)}) + LayerTypeICMPv4 = gopacket.RegisterLayerType(19, gopacket.LayerTypeMetadata{Name: "ICMPv4", Decoder: gopacket.DecodeFunc(decodeICMPv4)}) + LayerTypeIPv4 = gopacket.RegisterLayerType(20, gopacket.LayerTypeMetadata{Name: "IPv4", Decoder: gopacket.DecodeFunc(decodeIPv4)}) + LayerTypeIPv6 = gopacket.RegisterLayerType(21, gopacket.LayerTypeMetadata{Name: "IPv6", Decoder: gopacket.DecodeFunc(decodeIPv6)}) + LayerTypeLLC = gopacket.RegisterLayerType(22, gopacket.LayerTypeMetadata{Name: "LLC", Decoder: gopacket.DecodeFunc(decodeLLC)}) + LayerTypeSNAP = gopacket.RegisterLayerType(23, gopacket.LayerTypeMetadata{Name: "SNAP", Decoder: gopacket.DecodeFunc(decodeSNAP)}) + LayerTypeMPLS = gopacket.RegisterLayerType(24, gopacket.LayerTypeMetadata{Name: "MPLS", Decoder: gopacket.DecodeFunc(decodeMPLS)}) + LayerTypePPP = gopacket.RegisterLayerType(25, gopacket.LayerTypeMetadata{Name: "PPP", Decoder: gopacket.DecodeFunc(decodePPP)}) + LayerTypePPPoE = gopacket.RegisterLayerType(26, gopacket.LayerTypeMetadata{Name: "PPPoE", Decoder: gopacket.DecodeFunc(decodePPPoE)}) + LayerTypeRUDP = gopacket.RegisterLayerType(27, gopacket.LayerTypeMetadata{Name: "RUDP", Decoder: gopacket.DecodeFunc(decodeRUDP)}) + LayerTypeSCTP = gopacket.RegisterLayerType(28, gopacket.LayerTypeMetadata{Name: "SCTP", Decoder: gopacket.DecodeFunc(decodeSCTP)}) + LayerTypeSCTPUnknownChunkType = gopacket.RegisterLayerType(29, gopacket.LayerTypeMetadata{Name: "SCTPUnknownChunkType", Decoder: nil}) + LayerTypeSCTPData = gopacket.RegisterLayerType(30, gopacket.LayerTypeMetadata{Name: "SCTPData", Decoder: nil}) + LayerTypeSCTPInit = gopacket.RegisterLayerType(31, gopacket.LayerTypeMetadata{Name: "SCTPInit", Decoder: nil}) + LayerTypeSCTPSack = gopacket.RegisterLayerType(32, gopacket.LayerTypeMetadata{Name: "SCTPSack", Decoder: nil}) + LayerTypeSCTPHeartbeat = gopacket.RegisterLayerType(33, gopacket.LayerTypeMetadata{Name: "SCTPHeartbeat", Decoder: nil}) + LayerTypeSCTPError = gopacket.RegisterLayerType(34, gopacket.LayerTypeMetadata{Name: "SCTPError", Decoder: nil}) + LayerTypeSCTPShutdown = gopacket.RegisterLayerType(35, gopacket.LayerTypeMetadata{Name: "SCTPShutdown", Decoder: nil}) + LayerTypeSCTPShutdownAck = gopacket.RegisterLayerType(36, gopacket.LayerTypeMetadata{Name: "SCTPShutdownAck", Decoder: nil}) + LayerTypeSCTPCookieEcho = gopacket.RegisterLayerType(37, gopacket.LayerTypeMetadata{Name: "SCTPCookieEcho", Decoder: nil}) + LayerTypeSCTPEmptyLayer = gopacket.RegisterLayerType(38, gopacket.LayerTypeMetadata{Name: "SCTPEmptyLayer", Decoder: nil}) + LayerTypeSCTPInitAck = gopacket.RegisterLayerType(39, gopacket.LayerTypeMetadata{Name: "SCTPInitAck", Decoder: nil}) + LayerTypeSCTPHeartbeatAck = gopacket.RegisterLayerType(40, gopacket.LayerTypeMetadata{Name: "SCTPHeartbeatAck", Decoder: nil}) + LayerTypeSCTPAbort = gopacket.RegisterLayerType(41, gopacket.LayerTypeMetadata{Name: "SCTPAbort", Decoder: nil}) + LayerTypeSCTPShutdownComplete = gopacket.RegisterLayerType(42, gopacket.LayerTypeMetadata{Name: "SCTPShutdownComplete", Decoder: nil}) + LayerTypeSCTPCookieAck = gopacket.RegisterLayerType(43, gopacket.LayerTypeMetadata{Name: "SCTPCookieAck", Decoder: nil}) + LayerTypeTCP = gopacket.RegisterLayerType(44, gopacket.LayerTypeMetadata{Name: "TCP", Decoder: gopacket.DecodeFunc(decodeTCP)}) + LayerTypeUDP = gopacket.RegisterLayerType(45, gopacket.LayerTypeMetadata{Name: "UDP", Decoder: gopacket.DecodeFunc(decodeUDP)}) + LayerTypeIPv6HopByHop = gopacket.RegisterLayerType(46, gopacket.LayerTypeMetadata{Name: "IPv6HopByHop", Decoder: gopacket.DecodeFunc(decodeIPv6HopByHop)}) + LayerTypeIPv6Routing = gopacket.RegisterLayerType(47, gopacket.LayerTypeMetadata{Name: "IPv6Routing", Decoder: gopacket.DecodeFunc(decodeIPv6Routing)}) + LayerTypeIPv6Fragment = gopacket.RegisterLayerType(48, gopacket.LayerTypeMetadata{Name: "IPv6Fragment", Decoder: gopacket.DecodeFunc(decodeIPv6Fragment)}) + LayerTypeIPv6Destination = gopacket.RegisterLayerType(49, gopacket.LayerTypeMetadata{Name: "IPv6Destination", Decoder: gopacket.DecodeFunc(decodeIPv6Destination)}) + LayerTypeIPSecAH = gopacket.RegisterLayerType(50, gopacket.LayerTypeMetadata{Name: "IPSecAH", Decoder: gopacket.DecodeFunc(decodeIPSecAH)}) + LayerTypeIPSecESP = gopacket.RegisterLayerType(51, gopacket.LayerTypeMetadata{Name: "IPSecESP", Decoder: gopacket.DecodeFunc(decodeIPSecESP)}) + LayerTypeUDPLite = gopacket.RegisterLayerType(52, gopacket.LayerTypeMetadata{Name: "UDPLite", Decoder: gopacket.DecodeFunc(decodeUDPLite)}) + LayerTypeFDDI = gopacket.RegisterLayerType(53, gopacket.LayerTypeMetadata{Name: "FDDI", Decoder: gopacket.DecodeFunc(decodeFDDI)}) + LayerTypeLoopback = gopacket.RegisterLayerType(54, gopacket.LayerTypeMetadata{Name: "Loopback", Decoder: gopacket.DecodeFunc(decodeLoopback)}) + LayerTypeEAP = gopacket.RegisterLayerType(55, gopacket.LayerTypeMetadata{Name: "EAP", Decoder: gopacket.DecodeFunc(decodeEAP)}) + LayerTypeEAPOL = gopacket.RegisterLayerType(56, gopacket.LayerTypeMetadata{Name: "EAPOL", Decoder: gopacket.DecodeFunc(decodeEAPOL)}) + LayerTypeICMPv6 = gopacket.RegisterLayerType(57, gopacket.LayerTypeMetadata{Name: "ICMPv6", Decoder: gopacket.DecodeFunc(decodeICMPv6)}) + LayerTypeLinkLayerDiscovery = gopacket.RegisterLayerType(58, gopacket.LayerTypeMetadata{Name: "LinkLayerDiscovery", Decoder: gopacket.DecodeFunc(decodeLinkLayerDiscovery)}) + LayerTypeCiscoDiscoveryInfo = gopacket.RegisterLayerType(59, gopacket.LayerTypeMetadata{Name: "CiscoDiscoveryInfo", Decoder: gopacket.DecodeFunc(decodeCiscoDiscoveryInfo)}) + LayerTypeLinkLayerDiscoveryInfo = gopacket.RegisterLayerType(60, gopacket.LayerTypeMetadata{Name: "LinkLayerDiscoveryInfo", Decoder: nil}) + LayerTypeNortelDiscovery = gopacket.RegisterLayerType(61, gopacket.LayerTypeMetadata{Name: "NortelDiscovery", Decoder: gopacket.DecodeFunc(decodeNortelDiscovery)}) + LayerTypeIGMP = gopacket.RegisterLayerType(62, gopacket.LayerTypeMetadata{Name: "IGMP", Decoder: gopacket.DecodeFunc(decodeIGMP)}) + LayerTypePFLog = gopacket.RegisterLayerType(63, gopacket.LayerTypeMetadata{Name: "PFLog", Decoder: gopacket.DecodeFunc(decodePFLog)}) + LayerTypeRadioTap = gopacket.RegisterLayerType(64, gopacket.LayerTypeMetadata{Name: "RadioTap", Decoder: gopacket.DecodeFunc(decodeRadioTap)}) + LayerTypeDot11 = gopacket.RegisterLayerType(65, gopacket.LayerTypeMetadata{Name: "Dot11", Decoder: gopacket.DecodeFunc(decodeDot11)}) + LayerTypeDot11Ctrl = gopacket.RegisterLayerType(66, gopacket.LayerTypeMetadata{Name: "Dot11Ctrl", Decoder: gopacket.DecodeFunc(decodeDot11Ctrl)}) + LayerTypeDot11Data = gopacket.RegisterLayerType(67, gopacket.LayerTypeMetadata{Name: "Dot11Data", Decoder: gopacket.DecodeFunc(decodeDot11Data)}) + LayerTypeDot11DataCFAck = gopacket.RegisterLayerType(68, gopacket.LayerTypeMetadata{Name: "Dot11DataCFAck", Decoder: gopacket.DecodeFunc(decodeDot11DataCFAck)}) + LayerTypeDot11DataCFPoll = gopacket.RegisterLayerType(69, gopacket.LayerTypeMetadata{Name: "Dot11DataCFPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataCFPoll)}) + LayerTypeDot11DataCFAckPoll = gopacket.RegisterLayerType(70, gopacket.LayerTypeMetadata{Name: "Dot11DataCFAckPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataCFAckPoll)}) + LayerTypeDot11DataNull = gopacket.RegisterLayerType(71, gopacket.LayerTypeMetadata{Name: "Dot11DataNull", Decoder: gopacket.DecodeFunc(decodeDot11DataNull)}) + LayerTypeDot11DataCFAckNoData = gopacket.RegisterLayerType(72, gopacket.LayerTypeMetadata{Name: "Dot11DataCFAck", Decoder: gopacket.DecodeFunc(decodeDot11DataCFAck)}) + LayerTypeDot11DataCFPollNoData = gopacket.RegisterLayerType(73, gopacket.LayerTypeMetadata{Name: "Dot11DataCFPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataCFPoll)}) + LayerTypeDot11DataCFAckPollNoData = gopacket.RegisterLayerType(74, gopacket.LayerTypeMetadata{Name: "Dot11DataCFAckPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataCFAckPoll)}) + LayerTypeDot11DataQOSData = gopacket.RegisterLayerType(75, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSData", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSData)}) + LayerTypeDot11DataQOSDataCFAck = gopacket.RegisterLayerType(76, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSDataCFAck", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAck)}) + LayerTypeDot11DataQOSDataCFPoll = gopacket.RegisterLayerType(77, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSDataCFPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSDataCFPoll)}) + LayerTypeDot11DataQOSDataCFAckPoll = gopacket.RegisterLayerType(78, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSDataCFAckPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSDataCFAckPoll)}) + LayerTypeDot11DataQOSNull = gopacket.RegisterLayerType(79, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSNull", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSNull)}) + LayerTypeDot11DataQOSCFPollNoData = gopacket.RegisterLayerType(80, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSCFPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSCFPollNoData)}) + LayerTypeDot11DataQOSCFAckPollNoData = gopacket.RegisterLayerType(81, gopacket.LayerTypeMetadata{Name: "Dot11DataQOSCFAckPoll", Decoder: gopacket.DecodeFunc(decodeDot11DataQOSCFAckPollNoData)}) + LayerTypeDot11InformationElement = gopacket.RegisterLayerType(82, gopacket.LayerTypeMetadata{Name: "Dot11InformationElement", Decoder: gopacket.DecodeFunc(decodeDot11InformationElement)}) + LayerTypeDot11CtrlCTS = gopacket.RegisterLayerType(83, gopacket.LayerTypeMetadata{Name: "Dot11CtrlCTS", Decoder: gopacket.DecodeFunc(decodeDot11CtrlCTS)}) + LayerTypeDot11CtrlRTS = gopacket.RegisterLayerType(84, gopacket.LayerTypeMetadata{Name: "Dot11CtrlRTS", Decoder: gopacket.DecodeFunc(decodeDot11CtrlRTS)}) + LayerTypeDot11CtrlBlockAckReq = gopacket.RegisterLayerType(85, gopacket.LayerTypeMetadata{Name: "Dot11CtrlBlockAckReq", Decoder: gopacket.DecodeFunc(decodeDot11CtrlBlockAckReq)}) + LayerTypeDot11CtrlBlockAck = gopacket.RegisterLayerType(86, gopacket.LayerTypeMetadata{Name: "Dot11CtrlBlockAck", Decoder: gopacket.DecodeFunc(decodeDot11CtrlBlockAck)}) + LayerTypeDot11CtrlPowersavePoll = gopacket.RegisterLayerType(87, gopacket.LayerTypeMetadata{Name: "Dot11CtrlPowersavePoll", Decoder: gopacket.DecodeFunc(decodeDot11CtrlPowersavePoll)}) + LayerTypeDot11CtrlAck = gopacket.RegisterLayerType(88, gopacket.LayerTypeMetadata{Name: "Dot11CtrlAck", Decoder: gopacket.DecodeFunc(decodeDot11CtrlAck)}) + LayerTypeDot11CtrlCFEnd = gopacket.RegisterLayerType(89, gopacket.LayerTypeMetadata{Name: "Dot11CtrlCFEnd", Decoder: gopacket.DecodeFunc(decodeDot11CtrlCFEnd)}) + LayerTypeDot11CtrlCFEndAck = gopacket.RegisterLayerType(90, gopacket.LayerTypeMetadata{Name: "Dot11CtrlCFEndAck", Decoder: gopacket.DecodeFunc(decodeDot11CtrlCFEndAck)}) + LayerTypeDot11MgmtAssociationReq = gopacket.RegisterLayerType(91, gopacket.LayerTypeMetadata{Name: "Dot11MgmtAssociationReq", Decoder: gopacket.DecodeFunc(decodeDot11MgmtAssociationReq)}) + LayerTypeDot11MgmtAssociationResp = gopacket.RegisterLayerType(92, gopacket.LayerTypeMetadata{Name: "Dot11MgmtAssociationResp", Decoder: gopacket.DecodeFunc(decodeDot11MgmtAssociationResp)}) + LayerTypeDot11MgmtReassociationReq = gopacket.RegisterLayerType(93, gopacket.LayerTypeMetadata{Name: "Dot11MgmtReassociationReq", Decoder: gopacket.DecodeFunc(decodeDot11MgmtReassociationReq)}) + LayerTypeDot11MgmtReassociationResp = gopacket.RegisterLayerType(94, gopacket.LayerTypeMetadata{Name: "Dot11MgmtReassociationResp", Decoder: gopacket.DecodeFunc(decodeDot11MgmtReassociationResp)}) + LayerTypeDot11MgmtProbeReq = gopacket.RegisterLayerType(95, gopacket.LayerTypeMetadata{Name: "Dot11MgmtProbeReq", Decoder: gopacket.DecodeFunc(decodeDot11MgmtProbeReq)}) + LayerTypeDot11MgmtProbeResp = gopacket.RegisterLayerType(96, gopacket.LayerTypeMetadata{Name: "Dot11MgmtProbeResp", Decoder: gopacket.DecodeFunc(decodeDot11MgmtProbeResp)}) + LayerTypeDot11MgmtMeasurementPilot = gopacket.RegisterLayerType(97, gopacket.LayerTypeMetadata{Name: "Dot11MgmtMeasurementPilot", Decoder: gopacket.DecodeFunc(decodeDot11MgmtMeasurementPilot)}) + LayerTypeDot11MgmtBeacon = gopacket.RegisterLayerType(98, gopacket.LayerTypeMetadata{Name: "Dot11MgmtBeacon", Decoder: gopacket.DecodeFunc(decodeDot11MgmtBeacon)}) + LayerTypeDot11MgmtATIM = gopacket.RegisterLayerType(99, gopacket.LayerTypeMetadata{Name: "Dot11MgmtATIM", Decoder: gopacket.DecodeFunc(decodeDot11MgmtATIM)}) + LayerTypeDot11MgmtDisassociation = gopacket.RegisterLayerType(100, gopacket.LayerTypeMetadata{Name: "Dot11MgmtDisassociation", Decoder: gopacket.DecodeFunc(decodeDot11MgmtDisassociation)}) + LayerTypeDot11MgmtAuthentication = gopacket.RegisterLayerType(101, gopacket.LayerTypeMetadata{Name: "Dot11MgmtAuthentication", Decoder: gopacket.DecodeFunc(decodeDot11MgmtAuthentication)}) + LayerTypeDot11MgmtDeauthentication = gopacket.RegisterLayerType(102, gopacket.LayerTypeMetadata{Name: "Dot11MgmtDeauthentication", Decoder: gopacket.DecodeFunc(decodeDot11MgmtDeauthentication)}) + LayerTypeDot11MgmtAction = gopacket.RegisterLayerType(103, gopacket.LayerTypeMetadata{Name: "Dot11MgmtAction", Decoder: gopacket.DecodeFunc(decodeDot11MgmtAction)}) + LayerTypeDot11MgmtActionNoAck = gopacket.RegisterLayerType(104, gopacket.LayerTypeMetadata{Name: "Dot11MgmtActionNoAck", Decoder: gopacket.DecodeFunc(decodeDot11MgmtActionNoAck)}) + LayerTypeDot11MgmtArubaWLAN = gopacket.RegisterLayerType(105, gopacket.LayerTypeMetadata{Name: "Dot11MgmtArubaWLAN", Decoder: gopacket.DecodeFunc(decodeDot11MgmtArubaWLAN)}) + LayerTypeDot11WEP = gopacket.RegisterLayerType(106, gopacket.LayerTypeMetadata{Name: "Dot11WEP", Decoder: gopacket.DecodeFunc(decodeDot11WEP)}) + LayerTypeDNS = gopacket.RegisterLayerType(107, gopacket.LayerTypeMetadata{Name: "DNS", Decoder: gopacket.DecodeFunc(decodeDNS)}) + LayerTypeUSB = gopacket.RegisterLayerType(108, gopacket.LayerTypeMetadata{Name: "USB", Decoder: gopacket.DecodeFunc(decodeUSB)}) + LayerTypeUSBRequestBlockSetup = gopacket.RegisterLayerType(109, gopacket.LayerTypeMetadata{Name: "USBRequestBlockSetup", Decoder: gopacket.DecodeFunc(decodeUSBRequestBlockSetup)}) + LayerTypeUSBControl = gopacket.RegisterLayerType(110, gopacket.LayerTypeMetadata{Name: "USBControl", Decoder: gopacket.DecodeFunc(decodeUSBControl)}) + LayerTypeUSBInterrupt = gopacket.RegisterLayerType(111, gopacket.LayerTypeMetadata{Name: "USBInterrupt", Decoder: gopacket.DecodeFunc(decodeUSBInterrupt)}) + LayerTypeUSBBulk = gopacket.RegisterLayerType(112, gopacket.LayerTypeMetadata{Name: "USBBulk", Decoder: gopacket.DecodeFunc(decodeUSBBulk)}) + LayerTypeLinuxSLL = gopacket.RegisterLayerType(113, gopacket.LayerTypeMetadata{Name: "Linux SLL", Decoder: gopacket.DecodeFunc(decodeLinuxSLL)}) + LayerTypeSFlow = gopacket.RegisterLayerType(114, gopacket.LayerTypeMetadata{Name: "SFlow", Decoder: gopacket.DecodeFunc(decodeSFlow)}) + LayerTypePrismHeader = gopacket.RegisterLayerType(115, gopacket.LayerTypeMetadata{Name: "Prism monitor mode header", Decoder: gopacket.DecodeFunc(decodePrismHeader)}) + LayerTypeVXLAN = gopacket.RegisterLayerType(116, gopacket.LayerTypeMetadata{Name: "VXLAN", Decoder: gopacket.DecodeFunc(decodeVXLAN)}) + LayerTypeNTP = gopacket.RegisterLayerType(117, gopacket.LayerTypeMetadata{Name: "NTP", Decoder: gopacket.DecodeFunc(decodeNTP)}) + LayerTypeDHCPv4 = gopacket.RegisterLayerType(118, gopacket.LayerTypeMetadata{Name: "DHCPv4", Decoder: gopacket.DecodeFunc(decodeDHCPv4)}) + LayerTypeVRRP = gopacket.RegisterLayerType(119, gopacket.LayerTypeMetadata{Name: "VRRP", Decoder: gopacket.DecodeFunc(decodeVRRP)}) + LayerTypeGeneve = gopacket.RegisterLayerType(120, gopacket.LayerTypeMetadata{Name: "Geneve", Decoder: gopacket.DecodeFunc(decodeGeneve)}) + LayerTypeSTP = gopacket.RegisterLayerType(121, gopacket.LayerTypeMetadata{Name: "STP", Decoder: gopacket.DecodeFunc(decodeSTP)}) + LayerTypeBFD = gopacket.RegisterLayerType(122, gopacket.LayerTypeMetadata{Name: "BFD", Decoder: gopacket.DecodeFunc(decodeBFD)}) + LayerTypeOSPF = gopacket.RegisterLayerType(123, gopacket.LayerTypeMetadata{Name: "OSPF", Decoder: gopacket.DecodeFunc(decodeOSPF)}) + LayerTypeICMPv6RouterSolicitation = gopacket.RegisterLayerType(124, gopacket.LayerTypeMetadata{Name: "ICMPv6RouterSolicitation", Decoder: gopacket.DecodeFunc(decodeICMPv6RouterSolicitation)}) + LayerTypeICMPv6RouterAdvertisement = gopacket.RegisterLayerType(125, gopacket.LayerTypeMetadata{Name: "ICMPv6RouterAdvertisement", Decoder: gopacket.DecodeFunc(decodeICMPv6RouterAdvertisement)}) + LayerTypeICMPv6NeighborSolicitation = gopacket.RegisterLayerType(126, gopacket.LayerTypeMetadata{Name: "ICMPv6NeighborSolicitation", Decoder: gopacket.DecodeFunc(decodeICMPv6NeighborSolicitation)}) + LayerTypeICMPv6NeighborAdvertisement = gopacket.RegisterLayerType(127, gopacket.LayerTypeMetadata{Name: "ICMPv6NeighborAdvertisement", Decoder: gopacket.DecodeFunc(decodeICMPv6NeighborAdvertisement)}) + LayerTypeICMPv6Redirect = gopacket.RegisterLayerType(128, gopacket.LayerTypeMetadata{Name: "ICMPv6Redirect", Decoder: gopacket.DecodeFunc(decodeICMPv6Redirect)}) + LayerTypeGTPv1U = gopacket.RegisterLayerType(129, gopacket.LayerTypeMetadata{Name: "GTPv1U", Decoder: gopacket.DecodeFunc(decodeGTPv1u)}) + LayerTypeGTPv2 = gopacket.RegisterLayerType(1010, gopacket.LayerTypeMetadata{Name: "GTPv2", Decoder: gopacket.DecodeFunc(decodeGTPv2)}) + LayerTypeEAPOLKey = gopacket.RegisterLayerType(130, gopacket.LayerTypeMetadata{Name: "EAPOLKey", Decoder: gopacket.DecodeFunc(decodeEAPOLKey)}) + LayerTypeLCM = gopacket.RegisterLayerType(131, gopacket.LayerTypeMetadata{Name: "LCM", Decoder: gopacket.DecodeFunc(decodeLCM)}) + LayerTypeICMPv6Echo = gopacket.RegisterLayerType(132, gopacket.LayerTypeMetadata{Name: "ICMPv6Echo", Decoder: gopacket.DecodeFunc(decodeICMPv6Echo)}) + LayerTypeSIP = gopacket.RegisterLayerType(133, gopacket.LayerTypeMetadata{Name: "SIP", Decoder: gopacket.DecodeFunc(decodeSIP)}) + LayerTypeDHCPv6 = gopacket.RegisterLayerType(134, gopacket.LayerTypeMetadata{Name: "DHCPv6", Decoder: gopacket.DecodeFunc(decodeDHCPv6)}) + LayerTypeMLDv1MulticastListenerReport = gopacket.RegisterLayerType(135, gopacket.LayerTypeMetadata{Name: "MLDv1MulticastListenerReport", Decoder: gopacket.DecodeFunc(decodeMLDv1MulticastListenerReport)}) + LayerTypeMLDv1MulticastListenerDone = gopacket.RegisterLayerType(136, gopacket.LayerTypeMetadata{Name: "MLDv1MulticastListenerDone", Decoder: gopacket.DecodeFunc(decodeMLDv1MulticastListenerDone)}) + LayerTypeMLDv1MulticastListenerQuery = gopacket.RegisterLayerType(137, gopacket.LayerTypeMetadata{Name: "MLDv1MulticastListenerQuery", Decoder: gopacket.DecodeFunc(decodeMLDv1MulticastListenerQuery)}) + LayerTypeMLDv2MulticastListenerReport = gopacket.RegisterLayerType(138, gopacket.LayerTypeMetadata{Name: "MLDv2MulticastListenerReport", Decoder: gopacket.DecodeFunc(decodeMLDv2MulticastListenerReport)}) + LayerTypeMLDv2MulticastListenerQuery = gopacket.RegisterLayerType(139, gopacket.LayerTypeMetadata{Name: "MLDv2MulticastListenerQuery", Decoder: gopacket.DecodeFunc(decodeMLDv2MulticastListenerQuery)}) + LayerTypeTLS = gopacket.RegisterLayerType(140, gopacket.LayerTypeMetadata{Name: "TLS", Decoder: gopacket.DecodeFunc(decodeTLS)}) + LayerTypeModbusTCP = gopacket.RegisterLayerType(141, gopacket.LayerTypeMetadata{Name: "ModbusTCP", Decoder: gopacket.DecodeFunc(decodeModbusTCP)}) + LayerTypeRMCP = gopacket.RegisterLayerType(142, gopacket.LayerTypeMetadata{Name: "RMCP", Decoder: gopacket.DecodeFunc(decodeRMCP)}) + LayerTypeASF = gopacket.RegisterLayerType(143, gopacket.LayerTypeMetadata{Name: "ASF", Decoder: gopacket.DecodeFunc(decodeASF)}) + LayerTypeASFPresencePong = gopacket.RegisterLayerType(144, gopacket.LayerTypeMetadata{Name: "ASFPresencePong", Decoder: gopacket.DecodeFunc(decodeASFPresencePong)}) + LayerTypeERSPANII = gopacket.RegisterLayerType(145, gopacket.LayerTypeMetadata{Name: "ERSPAN Type II", Decoder: gopacket.DecodeFunc(decodeERSPANII)}) + LayerTypeRADIUS = gopacket.RegisterLayerType(146, gopacket.LayerTypeMetadata{Name: "RADIUS", Decoder: gopacket.DecodeFunc(decodeRADIUS)}) + LayerTypeMDP = gopacket.RegisterLayerType(147, gopacket.LayerTypeMetadata{Name: "MDP", Decoder: gopacket.DecodeFunc(decodeMDP)}) + LayerTypeAGUEVar0 = gopacket.RegisterLayerType(148, gopacket.LayerTypeMetadata{Name: "AGUEVar0", Decoder: gopacket.DecodeFunc(decodeAGUE)}) + LayerTypeAGUEVar1 = gopacket.RegisterLayerType(149, gopacket.LayerTypeMetadata{Name: "AGUEVar1", Decoder: gopacket.DecodeFunc(decodeAGUE)}) + LayerTypeAPSP = gopacket.RegisterLayerType(150, gopacket.LayerTypeMetadata{Name: "APSP", Decoder: gopacket.DecodeFunc(decodeAPSP)}) + LayerTypeENIP = gopacket.RegisterLayerType(151, gopacket.LayerTypeMetadata{Name: "ENIP", Decoder: gopacket.DecodeFunc(decodeENIP)}) + LayerTypeCIP = gopacket.RegisterLayerType(152, gopacket.LayerTypeMetadata{Name: "CIP", Decoder: gopacket.DecodeFunc(decodeCIP)}) + LayerTypeLinuxSLL2 = gopacket.RegisterLayerType(276, gopacket.LayerTypeMetadata{Name: "Linux SLL2", Decoder: gopacket.DecodeFunc(decodeLinuxSLL2)}) +) + +var ( + // LayerClassIPNetwork contains TCP/IP network layer types. + LayerClassIPNetwork = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeIPv4, + LayerTypeIPv6, + }) + // LayerClassIPTransport contains TCP/IP transport layer types. + LayerClassIPTransport = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeTCP, + LayerTypeUDP, + LayerTypeSCTP, + }) + // LayerClassIPControl contains TCP/IP control protocols. + LayerClassIPControl = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeICMPv4, + LayerTypeICMPv6, + }) + // LayerClassSCTPChunk contains SCTP chunk types (not the top-level SCTP + // layer). + LayerClassSCTPChunk = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeSCTPUnknownChunkType, + LayerTypeSCTPData, + LayerTypeSCTPInit, + LayerTypeSCTPSack, + LayerTypeSCTPHeartbeat, + LayerTypeSCTPError, + LayerTypeSCTPShutdown, + LayerTypeSCTPShutdownAck, + LayerTypeSCTPCookieEcho, + LayerTypeSCTPEmptyLayer, + LayerTypeSCTPInitAck, + LayerTypeSCTPHeartbeatAck, + LayerTypeSCTPAbort, + LayerTypeSCTPShutdownComplete, + LayerTypeSCTPCookieAck, + }) + // LayerClassIPv6Extension contains IPv6 extension headers. + LayerClassIPv6Extension = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeIPv6HopByHop, + LayerTypeIPv6Routing, + LayerTypeIPv6Fragment, + LayerTypeIPv6Destination, + }) + LayerClassIPSec = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeIPSecAH, + LayerTypeIPSecESP, + }) + // LayerClassICMPv6NDP contains ICMPv6 neighbor discovery protocol + // messages. + LayerClassICMPv6NDP = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeICMPv6RouterSolicitation, + LayerTypeICMPv6RouterAdvertisement, + LayerTypeICMPv6NeighborSolicitation, + LayerTypeICMPv6NeighborAdvertisement, + LayerTypeICMPv6Redirect, + }) + // LayerClassMLDv1 contains multicast listener discovery protocol + LayerClassMLDv1 = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeMLDv1MulticastListenerQuery, + LayerTypeMLDv1MulticastListenerReport, + LayerTypeMLDv1MulticastListenerDone, + }) + // LayerClassMLDv2 contains multicast listener discovery protocol v2 + LayerClassMLDv2 = gopacket.NewLayerClass([]gopacket.LayerType{ + LayerTypeMLDv1MulticastListenerReport, + LayerTypeMLDv1MulticastListenerDone, + LayerTypeMLDv2MulticastListenerReport, + LayerTypeMLDv1MulticastListenerQuery, + LayerTypeMLDv2MulticastListenerQuery, + }) +) diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lcm.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lcm.go new file mode 100644 index 0000000000..04db3bc3fb --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lcm.go @@ -0,0 +1,219 @@ +// Copyright 2018 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +const ( + // LCMShortHeaderMagic is the LCM small message header magic number + LCMShortHeaderMagic uint32 = 0x4c433032 + // LCMFragmentedHeaderMagic is the LCM fragmented message header magic number + LCMFragmentedHeaderMagic uint32 = 0x4c433033 +) + +// LCM (Lightweight Communications and Marshalling) is a set of libraries and +// tools for message passing and data marshalling, targeted at real-time systems +// where high-bandwidth and low latency are critical. It provides a +// publish/subscribe message passing model and automatic +// marshalling/unmarshalling code generation with bindings for applications in a +// variety of programming languages. +// +// References +// +// https://lcm-proj.github.io/ +// https://github.com/lcm-proj/lcm +type LCM struct { + // Common (short & fragmented header) fields + Magic uint32 + SequenceNumber uint32 + // Fragmented header only fields + PayloadSize uint32 + FragmentOffset uint32 + FragmentNumber uint16 + TotalFragments uint16 + // Common field + ChannelName string + // Gopacket helper fields + Fragmented bool + fingerprint LCMFingerprint + contents []byte + payload []byte +} + +// LCMFingerprint is the type of a LCM fingerprint. +type LCMFingerprint uint64 + +var ( + // lcmLayerTypes contains a map of all LCM fingerprints that we support and + // their LayerType + lcmLayerTypes = map[LCMFingerprint]gopacket.LayerType{} + layerTypeIndex = 1001 +) + +// RegisterLCMLayerType allows users to register decoders for the underlying +// LCM payload. This is done based on the fingerprint that every LCM message +// contains and which identifies it uniquely. If num is not the zero value it +// will be used when registering with RegisterLayerType towards gopacket, +// otherwise an incremental value starting from 1001 will be used. +func RegisterLCMLayerType(num int, name string, fingerprint LCMFingerprint, + decoder gopacket.Decoder) gopacket.LayerType { + metadata := gopacket.LayerTypeMetadata{Name: name, Decoder: decoder} + + if num == 0 { + num = layerTypeIndex + layerTypeIndex++ + } + + lcmLayerTypes[fingerprint] = gopacket.RegisterLayerType(num, metadata) + + return lcmLayerTypes[fingerprint] +} + +// SupportedLCMFingerprints returns a slice of all LCM fingerprints that has +// been registered so far. +func SupportedLCMFingerprints() []LCMFingerprint { + fingerprints := make([]LCMFingerprint, 0, len(lcmLayerTypes)) + for fp := range lcmLayerTypes { + fingerprints = append(fingerprints, fp) + } + return fingerprints +} + +// GetLCMLayerType returns the underlying LCM message's LayerType. +// This LayerType has to be registered by using RegisterLCMLayerType. +func GetLCMLayerType(fingerprint LCMFingerprint) gopacket.LayerType { + layerType, ok := lcmLayerTypes[fingerprint] + if !ok { + return gopacket.LayerTypePayload + } + + return layerType +} + +func decodeLCM(data []byte, p gopacket.PacketBuilder) error { + lcm := &LCM{} + + err := lcm.DecodeFromBytes(data, p) + if err != nil { + return err + } + + p.AddLayer(lcm) + p.SetApplicationLayer(lcm) + + return p.NextDecoder(lcm.NextLayerType()) +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (lcm *LCM) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return errors.New("LCM < 8 bytes") + } + offset := 0 + + lcm.Magic = binary.BigEndian.Uint32(data[offset:4]) + offset += 4 + + if lcm.Magic != LCMShortHeaderMagic && lcm.Magic != LCMFragmentedHeaderMagic { + return fmt.Errorf("Received LCM header magic %v does not match know "+ + "LCM magic numbers. Dropping packet.", lcm.Magic) + } + + lcm.SequenceNumber = binary.BigEndian.Uint32(data[offset:8]) + offset += 4 + + if lcm.Magic == LCMFragmentedHeaderMagic { + lcm.Fragmented = true + + lcm.PayloadSize = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + + lcm.FragmentOffset = binary.BigEndian.Uint32(data[offset : offset+4]) + offset += 4 + + lcm.FragmentNumber = binary.BigEndian.Uint16(data[offset : offset+2]) + offset += 2 + + lcm.TotalFragments = binary.BigEndian.Uint16(data[offset : offset+2]) + offset += 2 + } else { + lcm.Fragmented = false + } + + if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) { + buffer := make([]byte, 0) + for _, b := range data[offset:] { + offset++ + + if b == 0 { + break + } + + buffer = append(buffer, b) + } + + lcm.ChannelName = string(buffer) + } + + lcm.fingerprint = LCMFingerprint( + binary.BigEndian.Uint64(data[offset : offset+8])) + + lcm.contents = data[:offset] + lcm.payload = data[offset:] + + return nil +} + +// CanDecode returns a set of layers that LCM objects can decode. +// As LCM objects can only decode the LCM layer, we just return that layer. +func (lcm LCM) CanDecode() gopacket.LayerClass { + return LayerTypeLCM +} + +// NextLayerType specifies the LCM payload layer type following this header. +// As LCM packets are serialized structs with uniq fingerprints for each uniq +// combination of data types, lookup of correct layer type is based on that +// fingerprint. +func (lcm LCM) NextLayerType() gopacket.LayerType { + if !lcm.Fragmented || (lcm.Fragmented && lcm.FragmentNumber == 0) { + return GetLCMLayerType(lcm.fingerprint) + } + + return gopacket.LayerTypeFragment +} + +// LayerType returns LayerTypeLCM +func (lcm LCM) LayerType() gopacket.LayerType { + return LayerTypeLCM +} + +// LayerContents returns the contents of the LCM header. +func (lcm LCM) LayerContents() []byte { + return lcm.contents +} + +// LayerPayload returns the payload following this LCM header. +func (lcm LCM) LayerPayload() []byte { + return lcm.payload +} + +// Payload returns the payload following this LCM header. +func (lcm LCM) Payload() []byte { + return lcm.LayerPayload() +} + +// Fingerprint returns the LCM fingerprint of the underlying message. +func (lcm LCM) Fingerprint() LCMFingerprint { + return lcm.fingerprint +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll.go new file mode 100644 index 0000000000..e1d05caea7 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll.go @@ -0,0 +1,106 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +type LinuxSLLPacketType uint16 + +const ( + LinuxSLLPacketTypeHost LinuxSLLPacketType = 0 // To us + LinuxSLLPacketTypeBroadcast LinuxSLLPacketType = 1 // To all + LinuxSLLPacketTypeMulticast LinuxSLLPacketType = 2 // To group + LinuxSLLPacketTypeOtherhost LinuxSLLPacketType = 3 // To someone else + LinuxSLLPacketTypeOutgoing LinuxSLLPacketType = 4 // Outgoing of any type + // These ones are invisible by user level + LinuxSLLPacketTypeLoopback LinuxSLLPacketType = 5 // MC/BRD frame looped back + LinuxSLLPacketTypeFastroute LinuxSLLPacketType = 6 // Fastrouted frame +) + +func (l LinuxSLLPacketType) String() string { + switch l { + case LinuxSLLPacketTypeHost: + return "host" + case LinuxSLLPacketTypeBroadcast: + return "broadcast" + case LinuxSLLPacketTypeMulticast: + return "multicast" + case LinuxSLLPacketTypeOtherhost: + return "otherhost" + case LinuxSLLPacketTypeOutgoing: + return "outgoing" + case LinuxSLLPacketTypeLoopback: + return "loopback" + case LinuxSLLPacketTypeFastroute: + return "fastroute" + } + return fmt.Sprintf("Unknown(%d)", int(l)) +} + +type LinuxSLL struct { + BaseLayer + PacketType LinuxSLLPacketType + AddrLen uint16 + Addr net.HardwareAddr + EthernetType EthernetType + AddrType uint16 +} + +// LayerType returns LayerTypeLinuxSLL. +func (sll *LinuxSLL) LayerType() gopacket.LayerType { return LayerTypeLinuxSLL } + +func (sll *LinuxSLL) CanDecode() gopacket.LayerClass { + return LayerTypeLinuxSLL +} + +func (sll *LinuxSLL) LinkFlow() gopacket.Flow { + // Truncate address to MaxEndpointSize to prevent panics + // Linux SLL addresses should normally be 6-8 bytes, but malformed + // packets may claim larger sizes. This gracefully handles such cases + // by truncating oversized addresses instead of panicking. + addr := sll.Addr + if len(addr) > gopacket.MaxEndpointSize { + addr = addr[:gopacket.MaxEndpointSize] + } + return gopacket.NewFlow(EndpointMAC, addr, nil) +} + +func (sll *LinuxSLL) NextLayerType() gopacket.LayerType { + return sll.EthernetType.LayerType() +} + +func (sll *LinuxSLL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 16 { + return errors.New("Linux SLL packet too small") + } + sll.PacketType = LinuxSLLPacketType(binary.BigEndian.Uint16(data[0:2])) + sll.AddrType = binary.BigEndian.Uint16(data[2:4]) + sll.AddrLen = binary.BigEndian.Uint16(data[4:6]) + + sll.Addr = net.HardwareAddr(data[6 : sll.AddrLen+6]) + sll.EthernetType = EthernetType(binary.BigEndian.Uint16(data[14:16])) + sll.BaseLayer = BaseLayer{data[:16], data[16:]} + + return nil +} + +func decodeLinuxSLL(data []byte, p gopacket.PacketBuilder) error { + sll := &LinuxSLL{} + if err := sll.DecodeFromBytes(data, p); err != nil { + return err + } + p.AddLayer(sll) + p.SetLinkLayer(sll) + return p.NextDecoder(sll.EthernetType) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll2.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll2.go new file mode 100644 index 0000000000..7b37e747f0 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/linux_sll2.go @@ -0,0 +1,184 @@ +// Copyright 2022 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// The ARPHardwareType contains a Linux ARPHRD_ value for the link-layer device type +type ARPHardwareType uint16 + +const ( + ARPHardwareTypeEthernet ARPHardwareType = 1 + ARPHardwareTypeFRAD ARPHardwareType = 770 + ARPHardwareTypeLoopback ARPHardwareType = 772 + ARPHardwareTypeIPGRE ARPHardwareType = 778 + ARPHardwareTypeDot11Radiotap ARPHardwareType = 803 +) + +func (l ARPHardwareType) String() string { + switch l { + case ARPHardwareTypeEthernet: + return "Ethernet" + case ARPHardwareTypeFRAD: + return "Frame Relay Access Device" + case ARPHardwareTypeLoopback: + return "Loopback device" + case ARPHardwareTypeIPGRE: + return "GRE over IP" + case ARPHardwareTypeDot11Radiotap: + return "IEEE 802.11 + radiotap header" + } + + return fmt.Sprintf("Unknown(%d)", int(l)) +} + +// The LinuxSLL2PacketType can contain the same values as LinuxSLLPacketType accept it is a uint8 instread of a uint16 +type LinuxSLL2PacketType uint8 + +const ( + LinuxSLL2PacketTypeHost LinuxSLL2PacketType = 0 // To us + LinuxSLL2PacketTypeBroadcast LinuxSLL2PacketType = 1 // To all + LinuxSLL2PacketTypeMulticast LinuxSLL2PacketType = 2 // To group + LinuxSLL2PacketTypeOtherhost LinuxSLL2PacketType = 3 // To someone else + LinuxSLL2PacketTypeOutgoing LinuxSLL2PacketType = 4 // Outgoing of any type + // These ones are invisible by user level + LinuxSLL2PacketTypeLoopback LinuxSLL2PacketType = 5 // MC/BRD frame looped back + LinuxSLL2PacketTypeFastroute LinuxSLL2PacketType = 6 // Fastrouted frame +) + +func (l LinuxSLL2PacketType) String() string { + switch l { + case LinuxSLL2PacketTypeHost: + return "host" + case LinuxSLL2PacketTypeBroadcast: + return "broadcast" + case LinuxSLL2PacketTypeMulticast: + return "multicast" + case LinuxSLL2PacketTypeOtherhost: + return "otherhost" + case LinuxSLL2PacketTypeOutgoing: + return "outgoing" + case LinuxSLL2PacketTypeLoopback: + return "loopback" + case LinuxSLL2PacketTypeFastroute: + return "fastroute" + } + return fmt.Sprintf("Unknown(%d)", int(l)) +} + +const ( + LinuxSLL2EthernetTypeDot3 EthernetType = 0x0001 + LinuxSLL2EthernetTypeUnknown EthernetType = 0x0003 + LinuxSLL2EthernetTypeLLC EthernetType = 0x0004 + LinuxSLL2EthernetTypeCAN EthernetType = 0x000C +) + +// LinuxSLL2 is the second version of the Linux "cooked" capture encapsulation protocol. It is used to encapsulate +// packets within packet capture files, particularly by libpcap/tcpdump when making a packet capture with -i any +// https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL2.html +type LinuxSLL2 struct { + BaseLayer + ProtocolType EthernetType + InterfaceIndex uint32 + ARPHardwareType ARPHardwareType + PacketType LinuxSLL2PacketType + AddrLength uint8 + Addr net.HardwareAddr +} + +// LayerType returns LayerTypeLinuxSLL. +func (sll *LinuxSLL2) LayerType() gopacket.LayerType { return LayerTypeLinuxSLL2 } + +func (sll *LinuxSLL2) CanDecode() gopacket.LayerClass { + return LayerTypeLinuxSLL2 +} + +func (sll *LinuxSLL2) LinkFlow() gopacket.Flow { + // Truncate address to MaxEndpointSize to prevent panics + // Linux SLL2 addresses should normally be 6-8 bytes, but malformed + // packets may claim larger sizes. This gracefully handles such cases + // by truncating oversized addresses instead of panicking. + addr := sll.Addr + if len(addr) > gopacket.MaxEndpointSize { + addr = addr[:gopacket.MaxEndpointSize] + } + return gopacket.NewFlow(EndpointMAC, addr, nil) +} + +func (sll *LinuxSLL2) NextLayerType() gopacket.LayerType { + switch sll.ARPHardwareType { + case ARPHardwareTypeFRAD: + // If the ARPHRD_ type is ARPHRD_FRAD (770), the protocol type field is ignored, + // and the payload following the LINKTYPE_LINUX_SLL header is a Frame Relay LAPF frame, + // beginning with a ITU-T Recommendation Q.922 LAPF header starting with the address field, + // and without an FCS at the end of the frame. + return gopacket.LayerTypeZero // LAPF layer not yet implemented + + case ARPHardwareTypeDot11Radiotap: + return LayerTypeRadioTap + + case ARPHardwareTypeIPGRE: + // Docs: If the ARPHRD_ type is ARPHRD_IPGRE (778), the protocol type field contains a GRE protocol type. + // + // It doesn't clearly state if if the next header should be GRE or Ethernet in this case. Will assume ethernet + // for now + return LayerTypeEthernet + + default: + switch sll.ProtocolType { + case LinuxSLL2EthernetTypeDot3: + // Docs: if the frame is a Novell 802.3 frame without an 802.2 LLC header + return gopacket.LayerTypeZero // Novell 802.3 frame layer not yet implemented + + case LinuxSLL2EthernetTypeUnknown: + // Docs: in some mysterious cases; + return gopacket.LayerTypeZero // Mysterious cases not implemented + + case LinuxSLL2EthernetTypeLLC: + return LayerTypeLLC + + case LinuxSLL2EthernetTypeCAN: + // Docs: if the frame is a CAN bus frame that begins with a header of the form + return gopacket.LayerTypeZero + } + + return sll.ProtocolType.LayerType() + } +} + +func (sll *LinuxSLL2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + return errors.New("Linux SLL2 packet too small") + } + sll.ProtocolType = EthernetType(binary.BigEndian.Uint16(data[0:2])) + sll.InterfaceIndex = binary.BigEndian.Uint32(data[4:8]) + sll.ARPHardwareType = ARPHardwareType(binary.BigEndian.Uint16(data[8:10])) + sll.PacketType = LinuxSLL2PacketType(data[10]) + sll.AddrLength = data[11] + sll.Addr = data[12:20] + sll.Addr = sll.Addr[:sll.AddrLength] + sll.BaseLayer = BaseLayer{data[:20], data[20:]} + + return nil +} + +func decodeLinuxSLL2(data []byte, p gopacket.PacketBuilder) error { + sll := &LinuxSLL2{} + if err := sll.DecodeFromBytes(data, p); err != nil { + return err + } + p.AddLayer(sll) + p.SetLinkLayer(sll) + return p.NextDecoder(sll.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/llc.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/llc.go new file mode 100644 index 0000000000..7c3a282f98 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/llc.go @@ -0,0 +1,194 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// LLC is the layer used for 802.2 Logical Link Control headers. +// See http://standards.ieee.org/getieee802/download/802.2-1998.pdf +type LLC struct { + BaseLayer + DSAP uint8 + IG bool // true means group, false means individual + SSAP uint8 + CR bool // true means response, false means command + Control uint16 +} + +// LayerType returns gopacket.LayerTypeLLC. +func (l *LLC) LayerType() gopacket.LayerType { return LayerTypeLLC } + +// DecodeFromBytes decodes the given bytes into this layer. +func (l *LLC) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 3 { + return errors.New("LLC header too small") + } + l.DSAP = data[0] & 0xFE + l.IG = data[0]&0x1 != 0 + l.SSAP = data[1] & 0xFE + l.CR = data[1]&0x1 != 0 + l.Control = uint16(data[2]) + + if l.Control&0x1 == 0 || l.Control&0x3 == 0x1 { + if len(data) < 4 { + return errors.New("LLC header too small") + } + l.Control = l.Control<<8 | uint16(data[3]) + l.Contents = data[:4] + l.Payload = data[4:] + } else { + l.Contents = data[:3] + l.Payload = data[3:] + } + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (l *LLC) CanDecode() gopacket.LayerClass { + return LayerTypeLLC +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (l *LLC) NextLayerType() gopacket.LayerType { + switch { + case l.DSAP == 0xAA && l.SSAP == 0xAA: + return LayerTypeSNAP + case l.DSAP == 0x42 && l.SSAP == 0x42: + return LayerTypeSTP + } + return gopacket.LayerTypeZero // Not implemented +} + +// SNAP is used inside LLC. See +// http://standards.ieee.org/getieee802/download/802-2001.pdf. +// From http://en.wikipedia.org/wiki/Subnetwork_Access_Protocol: +// +// "[T]he Subnetwork Access Protocol (SNAP) is a mechanism for multiplexing, +// on networks using IEEE 802.2 LLC, more protocols than can be distinguished +// by the 8-bit 802.2 Service Access Point (SAP) fields." +type SNAP struct { + BaseLayer + OrganizationalCode []byte + Type EthernetType +} + +// LayerType returns gopacket.LayerTypeSNAP. +func (s *SNAP) LayerType() gopacket.LayerType { return LayerTypeSNAP } + +// DecodeFromBytes decodes the given bytes into this layer. +func (s *SNAP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 5 { + return errors.New("SNAP header too small") + } + s.OrganizationalCode = data[:3] + s.Type = EthernetType(binary.BigEndian.Uint16(data[3:5])) + s.BaseLayer = BaseLayer{data[:5], data[5:]} + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (s *SNAP) CanDecode() gopacket.LayerClass { + return LayerTypeSNAP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (s *SNAP) NextLayerType() gopacket.LayerType { + // See BUG(gconnel) in decodeSNAP + return s.Type.LayerType() +} + +func decodeLLC(data []byte, p gopacket.PacketBuilder) error { + l := &LLC{} + err := l.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(l) + return p.NextDecoder(l.NextLayerType()) +} + +func decodeSNAP(data []byte, p gopacket.PacketBuilder) error { + s := &SNAP{} + err := s.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(s) + // BUG(gconnell): When decoding SNAP, we treat the SNAP type as an Ethernet + // type. This may not actually be an ethernet type in all cases, + // depending on the organizational code. Right now, we don't check. + return p.NextDecoder(s.Type) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (l *LLC) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var igFlag, crFlag byte + var length int + + if l.Control&0xFF00 != 0 { + length = 4 + } else { + length = 3 + } + + if l.DSAP&0x1 != 0 { + return errors.New("DSAP value invalid, should not include IG flag bit") + } + + if l.SSAP&0x1 != 0 { + return errors.New("SSAP value invalid, should not include CR flag bit") + } + + if buf, err := b.PrependBytes(length); err != nil { + return err + } else { + igFlag = 0 + if l.IG { + igFlag = 0x1 + } + + crFlag = 0 + if l.CR { + crFlag = 0x1 + } + + buf[0] = l.DSAP + igFlag + buf[1] = l.SSAP + crFlag + + if length == 4 { + buf[2] = uint8(l.Control >> 8) + buf[3] = uint8(l.Control) + } else { + buf[2] = uint8(l.Control) + } + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (s *SNAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if buf, err := b.PrependBytes(5); err != nil { + return err + } else { + buf[0] = s.OrganizationalCode[0] + buf[1] = s.OrganizationalCode[1] + buf[2] = s.OrganizationalCode[2] + binary.BigEndian.PutUint16(buf[3:5], uint16(s.Type)) + } + + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lldp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lldp.go new file mode 100644 index 0000000000..c97fd4513b --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/lldp.go @@ -0,0 +1,1603 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// LLDPTLVType is the type of each TLV value in a LinkLayerDiscovery packet. +type LLDPTLVType byte + +const ( + LLDPTLVEnd LLDPTLVType = 0 + LLDPTLVChassisID LLDPTLVType = 1 + LLDPTLVPortID LLDPTLVType = 2 + LLDPTLVTTL LLDPTLVType = 3 + LLDPTLVPortDescription LLDPTLVType = 4 + LLDPTLVSysName LLDPTLVType = 5 + LLDPTLVSysDescription LLDPTLVType = 6 + LLDPTLVSysCapabilities LLDPTLVType = 7 + LLDPTLVMgmtAddress LLDPTLVType = 8 + LLDPTLVOrgSpecific LLDPTLVType = 127 +) + +// LinkLayerDiscoveryValue is a TLV value inside a LinkLayerDiscovery packet layer. +type LinkLayerDiscoveryValue struct { + Type LLDPTLVType + Length uint16 + Value []byte +} + +func (c *LinkLayerDiscoveryValue) len() int { + return 0 +} + +// LLDPChassisIDSubType specifies the value type for a single LLDPChassisID.ID +type LLDPChassisIDSubType byte + +// LLDP Chassis Types +const ( + LLDPChassisIDSubTypeReserved LLDPChassisIDSubType = 0 + LLDPChassisIDSubTypeChassisComp LLDPChassisIDSubType = 1 + LLDPChassisIDSubtypeIfaceAlias LLDPChassisIDSubType = 2 + LLDPChassisIDSubTypePortComp LLDPChassisIDSubType = 3 + LLDPChassisIDSubTypeMACAddr LLDPChassisIDSubType = 4 + LLDPChassisIDSubTypeNetworkAddr LLDPChassisIDSubType = 5 + LLDPChassisIDSubtypeIfaceName LLDPChassisIDSubType = 6 + LLDPChassisIDSubTypeLocal LLDPChassisIDSubType = 7 +) + +type LLDPChassisID struct { + Subtype LLDPChassisIDSubType + ID []byte +} + +func (c *LLDPChassisID) serialize() []byte { + + var buf = make([]byte, c.serializedLen()) + idLen := uint16(LLDPTLVChassisID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype + binary.BigEndian.PutUint16(buf[0:2], idLen) + buf[2] = byte(c.Subtype) + copy(buf[3:], c.ID) + return buf +} + +func (c *LLDPChassisID) serializedLen() int { + return len(c.ID) + 3 // +2 for id and length, +1 for subtype +} + +// LLDPPortIDSubType specifies the value type for a single LLDPPortID.ID +type LLDPPortIDSubType byte + +// LLDP PortID types +const ( + LLDPPortIDSubtypeReserved LLDPPortIDSubType = 0 + LLDPPortIDSubtypeIfaceAlias LLDPPortIDSubType = 1 + LLDPPortIDSubtypePortComp LLDPPortIDSubType = 2 + LLDPPortIDSubtypeMACAddr LLDPPortIDSubType = 3 + LLDPPortIDSubtypeNetworkAddr LLDPPortIDSubType = 4 + LLDPPortIDSubtypeIfaceName LLDPPortIDSubType = 5 + LLDPPortIDSubtypeAgentCircuitID LLDPPortIDSubType = 6 + LLDPPortIDSubtypeLocal LLDPPortIDSubType = 7 +) + +type LLDPPortID struct { + Subtype LLDPPortIDSubType + ID []byte +} + +func (c *LLDPPortID) serialize() []byte { + + var buf = make([]byte, c.serializedLen()) + idLen := uint16(LLDPTLVPortID)<<9 | uint16(len(c.ID)+1) //id should take 7 bits, length should take 9 bits, +1 for subtype + binary.BigEndian.PutUint16(buf[0:2], idLen) + buf[2] = byte(c.Subtype) + copy(buf[3:], c.ID) + return buf +} + +func (c *LLDPPortID) serializedLen() int { + return len(c.ID) + 3 // +2 for id and length, +1 for subtype +} + +// LinkLayerDiscovery is a packet layer containing the LinkLayer Discovery Protocol. +// See http:http://standards.ieee.org/getieee802/download/802.1AB-2009.pdf +// ChassisID, PortID and TTL are mandatory TLV's. Other values can be decoded +// with DecodeValues() +type LinkLayerDiscovery struct { + BaseLayer + ChassisID LLDPChassisID + PortID LLDPPortID + TTL uint16 + Values []LinkLayerDiscoveryValue +} + +type IEEEOUI uint32 + +// http://standards.ieee.org/develop/regauth/oui/oui.txt +const ( + IEEEOUI8021 IEEEOUI = 0x0080c2 + IEEEOUI8023 IEEEOUI = 0x00120f + IEEEOUI80211 IEEEOUI = 0x000fac + IEEEOUI8021Qbg IEEEOUI = 0x0013BF + IEEEOUICisco2 IEEEOUI = 0x000142 + IEEEOUIMedia IEEEOUI = 0x0012bb // TR-41 + IEEEOUIProfinet IEEEOUI = 0x000ecf + IEEEOUIDCBX IEEEOUI = 0x001b21 +) + +// LLDPOrgSpecificTLV is an Organisation-specific TLV +type LLDPOrgSpecificTLV struct { + OUI IEEEOUI + SubType uint8 + Info []byte +} + +// LLDPCapabilities Types +const ( + LLDPCapsOther uint16 = 1 << 0 + LLDPCapsRepeater uint16 = 1 << 1 + LLDPCapsBridge uint16 = 1 << 2 + LLDPCapsWLANAP uint16 = 1 << 3 + LLDPCapsRouter uint16 = 1 << 4 + LLDPCapsPhone uint16 = 1 << 5 + LLDPCapsDocSis uint16 = 1 << 6 + LLDPCapsStationOnly uint16 = 1 << 7 + LLDPCapsCVLAN uint16 = 1 << 8 + LLDPCapsSVLAN uint16 = 1 << 9 + LLDPCapsTmpr uint16 = 1 << 10 +) + +// LLDPCapabilities represents the capabilities of a device +type LLDPCapabilities struct { + Other bool + Repeater bool + Bridge bool + WLANAP bool + Router bool + Phone bool + DocSis bool + StationOnly bool + CVLAN bool + SVLAN bool + TMPR bool +} + +type LLDPSysCapabilities struct { + SystemCap LLDPCapabilities + EnabledCap LLDPCapabilities +} + +type IANAAddressFamily byte + +// LLDP Management Address Subtypes +// http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml +const ( + IANAAddressFamilyReserved IANAAddressFamily = 0 + IANAAddressFamilyIPV4 IANAAddressFamily = 1 + IANAAddressFamilyIPV6 IANAAddressFamily = 2 + IANAAddressFamilyNSAP IANAAddressFamily = 3 + IANAAddressFamilyHDLC IANAAddressFamily = 4 + IANAAddressFamilyBBN1822 IANAAddressFamily = 5 + IANAAddressFamily802 IANAAddressFamily = 6 + IANAAddressFamilyE163 IANAAddressFamily = 7 + IANAAddressFamilyE164 IANAAddressFamily = 8 + IANAAddressFamilyF69 IANAAddressFamily = 9 + IANAAddressFamilyX121 IANAAddressFamily = 10 + IANAAddressFamilyIPX IANAAddressFamily = 11 + IANAAddressFamilyAtalk IANAAddressFamily = 12 + IANAAddressFamilyDecnet IANAAddressFamily = 13 + IANAAddressFamilyBanyan IANAAddressFamily = 14 + IANAAddressFamilyE164NSAP IANAAddressFamily = 15 + IANAAddressFamilyDNS IANAAddressFamily = 16 + IANAAddressFamilyDistname IANAAddressFamily = 17 + IANAAddressFamilyASNumber IANAAddressFamily = 18 + IANAAddressFamilyXTPIPV4 IANAAddressFamily = 19 + IANAAddressFamilyXTPIPV6 IANAAddressFamily = 20 + IANAAddressFamilyXTP IANAAddressFamily = 21 + IANAAddressFamilyFcWWPN IANAAddressFamily = 22 + IANAAddressFamilyFcWWNN IANAAddressFamily = 23 + IANAAddressFamilyGWID IANAAddressFamily = 24 + IANAAddressFamilyL2VPN IANAAddressFamily = 25 +) + +type LLDPInterfaceSubtype byte + +// LLDP Interface Subtypes +const ( + LLDPInterfaceSubtypeUnknown LLDPInterfaceSubtype = 1 + LLDPInterfaceSubtypeifIndex LLDPInterfaceSubtype = 2 + LLDPInterfaceSubtypeSysPort LLDPInterfaceSubtype = 3 +) + +type LLDPMgmtAddress struct { + Subtype IANAAddressFamily + Address []byte + InterfaceSubtype LLDPInterfaceSubtype + InterfaceNumber uint32 + OID string +} + +// LinkLayerDiscoveryInfo represents the decoded details for a set of LinkLayerDiscoveryValues +// Organisation-specific TLV's can be decoded using the various Decode() methods +type LinkLayerDiscoveryInfo struct { + BaseLayer + PortDescription string + SysName string + SysDescription string + SysCapabilities LLDPSysCapabilities + MgmtAddress LLDPMgmtAddress + OrgTLVs []LLDPOrgSpecificTLV // Private TLVs + Unknown []LinkLayerDiscoveryValue // undecoded TLVs +} + +// / IEEE 802.1 TLV Subtypes +const ( + LLDP8021SubtypePortVLANID uint8 = 1 + LLDP8021SubtypeProtocolVLANID uint8 = 2 + LLDP8021SubtypeVLANName uint8 = 3 + LLDP8021SubtypeProtocolIdentity uint8 = 4 + LLDP8021SubtypeVDIUsageDigest uint8 = 5 + LLDP8021SubtypeManagementVID uint8 = 6 + LLDP8021SubtypeLinkAggregation uint8 = 7 +) + +// VLAN Port Protocol ID options +const ( + LLDPProtocolVLANIDCapability byte = 1 << 1 + LLDPProtocolVLANIDStatus byte = 1 << 2 +) + +type PortProtocolVLANID struct { + Supported bool + Enabled bool + ID uint16 +} + +type VLANName struct { + ID uint16 + Name string +} + +type ProtocolIdentity []byte + +// LACP options +const ( + LLDPAggregationCapability byte = 1 << 0 + LLDPAggregationStatus byte = 1 << 1 +) + +// IEEE 802 Link Aggregation parameters +type LLDPLinkAggregation struct { + Supported bool + Enabled bool + PortID uint32 +} + +// LLDPInfo8021 represents the information carried in 802.1 Org-specific TLVs +type LLDPInfo8021 struct { + PVID uint16 + PPVIDs []PortProtocolVLANID + VLANNames []VLANName + ProtocolIdentities []ProtocolIdentity + VIDUsageDigest uint32 + ManagementVID uint16 + LinkAggregation LLDPLinkAggregation +} + +// IEEE 802.3 TLV Subtypes +const ( + LLDP8023SubtypeMACPHY uint8 = 1 + LLDP8023SubtypeMDIPower uint8 = 2 + LLDP8023SubtypeLinkAggregation uint8 = 3 + LLDP8023SubtypeMTU uint8 = 4 +) + +// MACPHY options +const ( + LLDPMACPHYCapability byte = 1 << 0 + LLDPMACPHYStatus byte = 1 << 1 +) + +// From IANA-MAU-MIB (introduced by RFC 4836) - dot3MauType +const ( + LLDPMAUTypeUnknown uint16 = 0 + LLDPMAUTypeAUI uint16 = 1 + LLDPMAUType10Base5 uint16 = 2 + LLDPMAUTypeFOIRL uint16 = 3 + LLDPMAUType10Base2 uint16 = 4 + LLDPMAUType10BaseT uint16 = 5 + LLDPMAUType10BaseFP uint16 = 6 + LLDPMAUType10BaseFB uint16 = 7 + LLDPMAUType10BaseFL uint16 = 8 + LLDPMAUType10BROAD36 uint16 = 9 + LLDPMAUType10BaseT_HD uint16 = 10 + LLDPMAUType10BaseT_FD uint16 = 11 + LLDPMAUType10BaseFL_HD uint16 = 12 + LLDPMAUType10BaseFL_FD uint16 = 13 + LLDPMAUType100BaseT4 uint16 = 14 + LLDPMAUType100BaseTX_HD uint16 = 15 + LLDPMAUType100BaseTX_FD uint16 = 16 + LLDPMAUType100BaseFX_HD uint16 = 17 + LLDPMAUType100BaseFX_FD uint16 = 18 + LLDPMAUType100BaseT2_HD uint16 = 19 + LLDPMAUType100BaseT2_FD uint16 = 20 + LLDPMAUType1000BaseX_HD uint16 = 21 + LLDPMAUType1000BaseX_FD uint16 = 22 + LLDPMAUType1000BaseLX_HD uint16 = 23 + LLDPMAUType1000BaseLX_FD uint16 = 24 + LLDPMAUType1000BaseSX_HD uint16 = 25 + LLDPMAUType1000BaseSX_FD uint16 = 26 + LLDPMAUType1000BaseCX_HD uint16 = 27 + LLDPMAUType1000BaseCX_FD uint16 = 28 + LLDPMAUType1000BaseT_HD uint16 = 29 + LLDPMAUType1000BaseT_FD uint16 = 30 + LLDPMAUType10GBaseX uint16 = 31 + LLDPMAUType10GBaseLX4 uint16 = 32 + LLDPMAUType10GBaseR uint16 = 33 + LLDPMAUType10GBaseER uint16 = 34 + LLDPMAUType10GBaseLR uint16 = 35 + LLDPMAUType10GBaseSR uint16 = 36 + LLDPMAUType10GBaseW uint16 = 37 + LLDPMAUType10GBaseEW uint16 = 38 + LLDPMAUType10GBaseLW uint16 = 39 + LLDPMAUType10GBaseSW uint16 = 40 + LLDPMAUType10GBaseCX4 uint16 = 41 + LLDPMAUType2BaseTL uint16 = 42 + LLDPMAUType10PASS_TS uint16 = 43 + LLDPMAUType100BaseBX10D uint16 = 44 + LLDPMAUType100BaseBX10U uint16 = 45 + LLDPMAUType100BaseLX10 uint16 = 46 + LLDPMAUType1000BaseBX10D uint16 = 47 + LLDPMAUType1000BaseBX10U uint16 = 48 + LLDPMAUType1000BaseLX10 uint16 = 49 + LLDPMAUType1000BasePX10D uint16 = 50 + LLDPMAUType1000BasePX10U uint16 = 51 + LLDPMAUType1000BasePX20D uint16 = 52 + LLDPMAUType1000BasePX20U uint16 = 53 + LLDPMAUType10GBaseT uint16 = 54 + LLDPMAUType10GBaseLRM uint16 = 55 + LLDPMAUType1000BaseKX uint16 = 56 + LLDPMAUType10GBaseKX4 uint16 = 57 + LLDPMAUType10GBaseKR uint16 = 58 + LLDPMAUType10_1GBasePRX_D1 uint16 = 59 + LLDPMAUType10_1GBasePRX_D2 uint16 = 60 + LLDPMAUType10_1GBasePRX_D3 uint16 = 61 + LLDPMAUType10_1GBasePRX_U1 uint16 = 62 + LLDPMAUType10_1GBasePRX_U2 uint16 = 63 + LLDPMAUType10_1GBasePRX_U3 uint16 = 64 + LLDPMAUType10GBasePR_D1 uint16 = 65 + LLDPMAUType10GBasePR_D2 uint16 = 66 + LLDPMAUType10GBasePR_D3 uint16 = 67 + LLDPMAUType10GBasePR_U1 uint16 = 68 + LLDPMAUType10GBasePR_U3 uint16 = 69 +) + +// From RFC 3636 - ifMauAutoNegCapAdvertisedBits +const ( + LLDPMAUPMDOther uint16 = 1 << 15 + LLDPMAUPMD10BaseT uint16 = 1 << 14 + LLDPMAUPMD10BaseT_FD uint16 = 1 << 13 + LLDPMAUPMD100BaseT4 uint16 = 1 << 12 + LLDPMAUPMD100BaseTX uint16 = 1 << 11 + LLDPMAUPMD100BaseTX_FD uint16 = 1 << 10 + LLDPMAUPMD100BaseT2 uint16 = 1 << 9 + LLDPMAUPMD100BaseT2_FD uint16 = 1 << 8 + LLDPMAUPMDFDXPAUSE uint16 = 1 << 7 + LLDPMAUPMDFDXAPAUSE uint16 = 1 << 6 + LLDPMAUPMDFDXSPAUSE uint16 = 1 << 5 + LLDPMAUPMDFDXBPAUSE uint16 = 1 << 4 + LLDPMAUPMD1000BaseX uint16 = 1 << 3 + LLDPMAUPMD1000BaseX_FD uint16 = 1 << 2 + LLDPMAUPMD1000BaseT uint16 = 1 << 1 + LLDPMAUPMD1000BaseT_FD uint16 = 1 << 0 +) + +// Inverted ifMauAutoNegCapAdvertisedBits if required +// (Some manufacturers misinterpreted the spec - +// see https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1455) +const ( + LLDPMAUPMDOtherInv uint16 = 1 << 0 + LLDPMAUPMD10BaseTInv uint16 = 1 << 1 + LLDPMAUPMD10BaseT_FDInv uint16 = 1 << 2 + LLDPMAUPMD100BaseT4Inv uint16 = 1 << 3 + LLDPMAUPMD100BaseTXInv uint16 = 1 << 4 + LLDPMAUPMD100BaseTX_FDInv uint16 = 1 << 5 + LLDPMAUPMD100BaseT2Inv uint16 = 1 << 6 + LLDPMAUPMD100BaseT2_FDInv uint16 = 1 << 7 + LLDPMAUPMDFDXPAUSEInv uint16 = 1 << 8 + LLDPMAUPMDFDXAPAUSEInv uint16 = 1 << 9 + LLDPMAUPMDFDXSPAUSEInv uint16 = 1 << 10 + LLDPMAUPMDFDXBPAUSEInv uint16 = 1 << 11 + LLDPMAUPMD1000BaseXInv uint16 = 1 << 12 + LLDPMAUPMD1000BaseX_FDInv uint16 = 1 << 13 + LLDPMAUPMD1000BaseTInv uint16 = 1 << 14 + LLDPMAUPMD1000BaseT_FDInv uint16 = 1 << 15 +) + +type LLDPMACPHYConfigStatus struct { + AutoNegSupported bool + AutoNegEnabled bool + AutoNegCapability uint16 + MAUType uint16 +} + +// MDI Power options +const ( + LLDPMDIPowerPortClass byte = 1 << 0 + LLDPMDIPowerCapability byte = 1 << 1 + LLDPMDIPowerStatus byte = 1 << 2 + LLDPMDIPowerPairsAbility byte = 1 << 3 +) + +type LLDPPowerType byte + +type LLDPPowerSource byte + +type LLDPPowerPriority byte + +const ( + LLDPPowerPriorityUnknown LLDPPowerPriority = 0 + LLDPPowerPriorityMedium LLDPPowerPriority = 1 + LLDPPowerPriorityHigh LLDPPowerPriority = 2 + LLDPPowerPriorityLow LLDPPowerPriority = 3 +) + +type LLDPPowerViaMDI8023 struct { + PortClassPSE bool // false = PD + PSESupported bool + PSEEnabled bool + PSEPairsAbility bool + PSEPowerPair uint8 + PSEClass uint8 + Type LLDPPowerType + Source LLDPPowerSource + Priority LLDPPowerPriority + Requested uint16 // 1-510 Watts + Allocated uint16 // 1-510 Watts +} + +// LLDPInfo8023 represents the information carried in 802.3 Org-specific TLVs +type LLDPInfo8023 struct { + MACPHYConfigStatus LLDPMACPHYConfigStatus + PowerViaMDI LLDPPowerViaMDI8023 + LinkAggregation LLDPLinkAggregation + MTU uint16 +} + +// IEEE 802.1Qbg TLV Subtypes +const ( + LLDP8021QbgEVB uint8 = 0 + LLDP8021QbgCDCP uint8 = 1 + LLDP8021QbgVDP uint8 = 2 + LLDP8021QbgEVB22 uint8 = 13 +) + +// LLDPEVBCapabilities Types +const ( + LLDPEVBCapsSTD uint16 = 1 << 7 + LLDPEVBCapsRR uint16 = 1 << 6 + LLDPEVBCapsRTE uint16 = 1 << 2 + LLDPEVBCapsECP uint16 = 1 << 1 + LLDPEVBCapsVDP uint16 = 1 << 0 +) + +// LLDPEVBCapabilities represents the EVB capabilities of a device +type LLDPEVBCapabilities struct { + StandardBridging bool + ReflectiveRelay bool + RetransmissionTimerExponent bool + EdgeControlProtocol bool + VSIDiscoveryProtocol bool +} + +type LLDPEVBSettings struct { + Supported LLDPEVBCapabilities + Enabled LLDPEVBCapabilities + SupportedVSIs uint16 + ConfiguredVSIs uint16 + RTEExponent uint8 +} + +// LLDPInfo8021Qbg represents the information carried in 802.1Qbg Org-specific TLVs +type LLDPInfo8021Qbg struct { + EVBSettings LLDPEVBSettings +} + +type LLDPMediaSubtype uint8 + +// Media TLV Subtypes +const ( + LLDPMediaTypeCapabilities LLDPMediaSubtype = 1 + LLDPMediaTypeNetwork LLDPMediaSubtype = 2 + LLDPMediaTypeLocation LLDPMediaSubtype = 3 + LLDPMediaTypePower LLDPMediaSubtype = 4 + LLDPMediaTypeHardware LLDPMediaSubtype = 5 + LLDPMediaTypeFirmware LLDPMediaSubtype = 6 + LLDPMediaTypeSoftware LLDPMediaSubtype = 7 + LLDPMediaTypeSerial LLDPMediaSubtype = 8 + LLDPMediaTypeManufacturer LLDPMediaSubtype = 9 + LLDPMediaTypeModel LLDPMediaSubtype = 10 + LLDPMediaTypeAssetID LLDPMediaSubtype = 11 +) + +type LLDPMediaClass uint8 + +// Media Class Values +const ( + LLDPMediaClassUndefined LLDPMediaClass = 0 + LLDPMediaClassEndpointI LLDPMediaClass = 1 + LLDPMediaClassEndpointII LLDPMediaClass = 2 + LLDPMediaClassEndpointIII LLDPMediaClass = 3 + LLDPMediaClassNetwork LLDPMediaClass = 4 +) + +// LLDPMediaCapabilities Types +const ( + LLDPMediaCapsLLDP uint16 = 1 << 0 + LLDPMediaCapsNetwork uint16 = 1 << 1 + LLDPMediaCapsLocation uint16 = 1 << 2 + LLDPMediaCapsPowerPSE uint16 = 1 << 3 + LLDPMediaCapsPowerPD uint16 = 1 << 4 + LLDPMediaCapsInventory uint16 = 1 << 5 +) + +// LLDPMediaCapabilities represents the LLDP Media capabilities of a device +type LLDPMediaCapabilities struct { + Capabilities bool + NetworkPolicy bool + Location bool + PowerPSE bool + PowerPD bool + Inventory bool + Class LLDPMediaClass +} + +type LLDPApplicationType uint8 + +const ( + LLDPAppTypeReserved LLDPApplicationType = 0 + LLDPAppTypeVoice LLDPApplicationType = 1 + LLDPappTypeVoiceSignaling LLDPApplicationType = 2 + LLDPappTypeGuestVoice LLDPApplicationType = 3 + LLDPappTypeGuestVoiceSignaling LLDPApplicationType = 4 + LLDPappTypeSoftphoneVoice LLDPApplicationType = 5 + LLDPappTypeVideoConferencing LLDPApplicationType = 6 + LLDPappTypeStreamingVideo LLDPApplicationType = 7 + LLDPappTypeVideoSignaling LLDPApplicationType = 8 +) + +type LLDPNetworkPolicy struct { + ApplicationType LLDPApplicationType + Defined bool + Tagged bool + VLANId uint16 + L2Priority uint16 + DSCPValue uint8 +} + +type LLDPLocationFormat uint8 + +const ( + LLDPLocationFormatInvalid LLDPLocationFormat = 0 + LLDPLocationFormatCoordinate LLDPLocationFormat = 1 + LLDPLocationFormatAddress LLDPLocationFormat = 2 + LLDPLocationFormatECS LLDPLocationFormat = 3 +) + +type LLDPLocationAddressWhat uint8 + +const ( + LLDPLocationAddressWhatDHCP LLDPLocationAddressWhat = 0 + LLDPLocationAddressWhatNetwork LLDPLocationAddressWhat = 1 + LLDPLocationAddressWhatClient LLDPLocationAddressWhat = 2 +) + +type LLDPLocationAddressType uint8 + +const ( + LLDPLocationAddressTypeLanguage LLDPLocationAddressType = 0 + LLDPLocationAddressTypeNational LLDPLocationAddressType = 1 + LLDPLocationAddressTypeCounty LLDPLocationAddressType = 2 + LLDPLocationAddressTypeCity LLDPLocationAddressType = 3 + LLDPLocationAddressTypeCityDivision LLDPLocationAddressType = 4 + LLDPLocationAddressTypeNeighborhood LLDPLocationAddressType = 5 + LLDPLocationAddressTypeStreet LLDPLocationAddressType = 6 + LLDPLocationAddressTypeLeadingStreet LLDPLocationAddressType = 16 + LLDPLocationAddressTypeTrailingStreet LLDPLocationAddressType = 17 + LLDPLocationAddressTypeStreetSuffix LLDPLocationAddressType = 18 + LLDPLocationAddressTypeHouseNum LLDPLocationAddressType = 19 + LLDPLocationAddressTypeHouseSuffix LLDPLocationAddressType = 20 + LLDPLocationAddressTypeLandmark LLDPLocationAddressType = 21 + LLDPLocationAddressTypeAdditional LLDPLocationAddressType = 22 + LLDPLocationAddressTypeName LLDPLocationAddressType = 23 + LLDPLocationAddressTypePostal LLDPLocationAddressType = 24 + LLDPLocationAddressTypeBuilding LLDPLocationAddressType = 25 + LLDPLocationAddressTypeUnit LLDPLocationAddressType = 26 + LLDPLocationAddressTypeFloor LLDPLocationAddressType = 27 + LLDPLocationAddressTypeRoom LLDPLocationAddressType = 28 + LLDPLocationAddressTypePlace LLDPLocationAddressType = 29 + LLDPLocationAddressTypeScript LLDPLocationAddressType = 128 +) + +type LLDPLocationCoordinate struct { + LatitudeResolution uint8 + Latitude uint64 + LongitudeResolution uint8 + Longitude uint64 + AltitudeType uint8 + AltitudeResolution uint16 + Altitude uint32 + Datum uint8 +} + +type LLDPLocationAddressLine struct { + Type LLDPLocationAddressType + Value string +} + +type LLDPLocationAddress struct { + What LLDPLocationAddressWhat + CountryCode string + AddressLines []LLDPLocationAddressLine +} + +type LLDPLocationECS struct { + ELIN string +} + +// LLDP represents a physical location. +// Only one of the embedded types will contain values, depending on Format. +type LLDPLocation struct { + Format LLDPLocationFormat + Coordinate LLDPLocationCoordinate + Address LLDPLocationAddress + ECS LLDPLocationECS +} + +type LLDPPowerViaMDI struct { + Type LLDPPowerType + Source LLDPPowerSource + Priority LLDPPowerPriority + Value uint16 +} + +// LLDPInfoMedia represents the information carried in TR-41 Org-specific TLVs +type LLDPInfoMedia struct { + MediaCapabilities LLDPMediaCapabilities + NetworkPolicy LLDPNetworkPolicy + Location LLDPLocation + PowerViaMDI LLDPPowerViaMDI + HardwareRevision string + FirmwareRevision string + SoftwareRevision string + SerialNumber string + Manufacturer string + Model string + AssetID string +} + +type LLDPCisco2Subtype uint8 + +// Cisco2 TLV Subtypes +const ( + LLDPCisco2PowerViaMDI LLDPCisco2Subtype = 1 +) + +const ( + LLDPCiscoPSESupport uint8 = 1 << 0 + LLDPCiscoArchShared uint8 = 1 << 1 + LLDPCiscoPDSparePair uint8 = 1 << 2 + LLDPCiscoPSESparePair uint8 = 1 << 3 +) + +// LLDPInfoCisco2 represents the information carried in Cisco Org-specific TLVs +type LLDPInfoCisco2 struct { + PSEFourWirePoESupported bool + PDSparePairArchitectureShared bool + PDRequestSparePairPoEOn bool + PSESparePairPoEOn bool +} + +// Profinet Subtypes +type LLDPProfinetSubtype uint8 + +const ( + LLDPProfinetPNIODelay LLDPProfinetSubtype = 1 + LLDPProfinetPNIOPortStatus LLDPProfinetSubtype = 2 + LLDPProfinetPNIOMRPPortStatus LLDPProfinetSubtype = 4 + LLDPProfinetPNIOChassisMAC LLDPProfinetSubtype = 5 + LLDPProfinetPNIOPTCPStatus LLDPProfinetSubtype = 6 +) + +type LLDPPNIODelay struct { + RXLocal uint32 + RXRemote uint32 + TXLocal uint32 + TXRemote uint32 + CableLocal uint32 +} + +type LLDPPNIOPortStatus struct { + Class2 uint16 + Class3 uint16 +} + +type LLDPPNIOMRPPortStatus struct { + UUID []byte + Status uint16 +} + +type LLDPPNIOPTCPStatus struct { + MasterAddress []byte + SubdomainUUID []byte + IRDataUUID []byte + PeriodValid bool + PeriodLength uint32 + RedPeriodValid bool + RedPeriodBegin uint32 + OrangePeriodValid bool + OrangePeriodBegin uint32 + GreenPeriodValid bool + GreenPeriodBegin uint32 +} + +// LLDPInfoProfinet represents the information carried in Profinet Org-specific TLVs +type LLDPInfoProfinet struct { + PNIODelay LLDPPNIODelay + PNIOPortStatus LLDPPNIOPortStatus + PNIOMRPPortStatus LLDPPNIOMRPPortStatus + ChassisMAC []byte + PNIOPTCPStatus LLDPPNIOPTCPStatus +} + +// LayerType returns gopacket.LayerTypeLinkLayerDiscovery. +func (c *LinkLayerDiscovery) LayerType() gopacket.LayerType { + return LayerTypeLinkLayerDiscovery +} + +// SerializeTo serializes LLDP packet to bytes and writes on SerializeBuffer. +func (c *LinkLayerDiscovery) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + chassIDLen := c.ChassisID.serializedLen() + portIDLen := c.PortID.serializedLen() + vb, err := b.AppendBytes(chassIDLen + portIDLen + 4) // +4 for TTL + if err != nil { + return err + } + copy(vb[:chassIDLen], c.ChassisID.serialize()) + copy(vb[chassIDLen:], c.PortID.serialize()) + ttlIDLen := uint16(LLDPTLVTTL)<<9 | uint16(2) + binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen:], ttlIDLen) + binary.BigEndian.PutUint16(vb[chassIDLen+portIDLen+2:], c.TTL) + + for _, v := range c.Values { + vb, err := b.AppendBytes(int(v.Length) + 2) // +2 for TLV type and length; 1 byte for subtype is included in v.Value + if err != nil { + return err + } + idLen := ((uint16(v.Type) << 9) | v.Length) + binary.BigEndian.PutUint16(vb[0:2], idLen) + copy(vb[2:], v.Value) + } + + vb, err = b.AppendBytes(2) // End Tlv, 2 bytes + if err != nil { + return err + } + binary.BigEndian.PutUint16(vb[len(vb)-2:], uint16(0)) //End tlv, 2 bytes, all zero + return nil + +} + +func decodeLinkLayerDiscovery(data []byte, p gopacket.PacketBuilder) error { + var vals []LinkLayerDiscoveryValue + vData := data[0:] + for len(vData) > 0 { + if len(vData) < 2 { + p.SetTruncated() + return errors.New("LLDP vdata < 2 bytes") + } + nbit := vData[0] & 0x01 + t := LLDPTLVType(vData[0] >> 1) + val := LinkLayerDiscoveryValue{Type: t, Length: uint16(nbit)<<8 + uint16(vData[1])} + if val.Length > 0 { + if len(vData) < int(val.Length+2) { + p.SetTruncated() + return fmt.Errorf("LLDP VData < %d bytes", val.Length+2) + } + val.Value = vData[2 : val.Length+2] + } + vals = append(vals, val) + if t == LLDPTLVEnd { + break + } + if len(vData) < int(2+val.Length) { + return errors.New("Malformed LinkLayerDiscovery Header") + } + vData = vData[2+val.Length:] + } + if len(vals) < 4 { + return errors.New("Missing mandatory LinkLayerDiscovery TLV") + } + c := &LinkLayerDiscovery{} + gotEnd := false + for _, v := range vals { + switch v.Type { + case LLDPTLVEnd: + gotEnd = true + case LLDPTLVChassisID: + if len(v.Value) < 2 { + return errors.New("Malformed LinkLayerDiscovery ChassisID TLV") + } + c.ChassisID.Subtype = LLDPChassisIDSubType(v.Value[0]) + c.ChassisID.ID = v.Value[1:] + case LLDPTLVPortID: + if len(v.Value) < 2 { + return errors.New("Malformed LinkLayerDiscovery PortID TLV") + } + c.PortID.Subtype = LLDPPortIDSubType(v.Value[0]) + c.PortID.ID = v.Value[1:] + case LLDPTLVTTL: + if len(v.Value) < 2 { + return errors.New("Malformed LinkLayerDiscovery TTL TLV") + } + c.TTL = binary.BigEndian.Uint16(v.Value[0:2]) + default: + c.Values = append(c.Values, v) + } + } + if c.ChassisID.Subtype == 0 || c.PortID.Subtype == 0 || !gotEnd { + return errors.New("Missing mandatory LinkLayerDiscovery TLV") + } + c.Contents = data + p.AddLayer(c) + + info := &LinkLayerDiscoveryInfo{} + p.AddLayer(info) + for _, v := range c.Values { + switch v.Type { + case LLDPTLVPortDescription: + info.PortDescription = string(v.Value) + case LLDPTLVSysName: + info.SysName = string(v.Value) + case LLDPTLVSysDescription: + info.SysDescription = string(v.Value) + case LLDPTLVSysCapabilities: + if err := checkLLDPTLVLen(v, 4); err != nil { + return err + } + info.SysCapabilities.SystemCap = getCapabilities(binary.BigEndian.Uint16(v.Value[0:2])) + info.SysCapabilities.EnabledCap = getCapabilities(binary.BigEndian.Uint16(v.Value[2:4])) + case LLDPTLVMgmtAddress: + if err := checkLLDPTLVLen(v, 9); err != nil { + return err + } + mlen := v.Value[0] + if err := checkLLDPTLVLen(v, int(mlen+7)); err != nil { + return err + } + info.MgmtAddress.Subtype = IANAAddressFamily(v.Value[1]) + info.MgmtAddress.Address = v.Value[2 : mlen+1] + info.MgmtAddress.InterfaceSubtype = LLDPInterfaceSubtype(v.Value[mlen+1]) + info.MgmtAddress.InterfaceNumber = binary.BigEndian.Uint32(v.Value[mlen+2 : mlen+6]) + olen := v.Value[mlen+6] + if err := checkLLDPTLVLen(v, int(mlen+7+olen)); err != nil { + return err + } + info.MgmtAddress.OID = string(v.Value[mlen+7 : mlen+7+olen]) + case LLDPTLVOrgSpecific: + if err := checkLLDPTLVLen(v, 4); err != nil { + return err + } + info.OrgTLVs = append(info.OrgTLVs, LLDPOrgSpecificTLV{IEEEOUI(binary.BigEndian.Uint32(append([]byte{byte(0)}, v.Value[0:3]...))), uint8(v.Value[3]), v.Value[4:]}) + } + } + return nil +} + +func (l *LinkLayerDiscoveryInfo) Decode8021() (info LLDPInfo8021, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUI8021 { + continue + } + switch o.SubType { + case LLDP8021SubtypePortVLANID: + if err = checkLLDPOrgSpecificLen(o, 2); err != nil { + return + } + info.PVID = binary.BigEndian.Uint16(o.Info[0:2]) + case LLDP8021SubtypeProtocolVLANID: + if err = checkLLDPOrgSpecificLen(o, 3); err != nil { + return + } + sup := (o.Info[0]&LLDPProtocolVLANIDCapability > 0) + en := (o.Info[0]&LLDPProtocolVLANIDStatus > 0) + id := binary.BigEndian.Uint16(o.Info[1:3]) + info.PPVIDs = append(info.PPVIDs, PortProtocolVLANID{sup, en, id}) + case LLDP8021SubtypeVLANName: + if err = checkLLDPOrgSpecificLen(o, 2); err != nil { + return + } + id := binary.BigEndian.Uint16(o.Info[0:2]) + info.VLANNames = append(info.VLANNames, VLANName{id, string(o.Info[3:])}) + case LLDP8021SubtypeProtocolIdentity: + if err = checkLLDPOrgSpecificLen(o, 1); err != nil { + return + } + l := int(o.Info[0]) + if l > 0 { + info.ProtocolIdentities = append(info.ProtocolIdentities, o.Info[1:1+l]) + } + case LLDP8021SubtypeVDIUsageDigest: + if err = checkLLDPOrgSpecificLen(o, 4); err != nil { + return + } + info.VIDUsageDigest = binary.BigEndian.Uint32(o.Info[0:4]) + case LLDP8021SubtypeManagementVID: + if err = checkLLDPOrgSpecificLen(o, 2); err != nil { + return + } + info.ManagementVID = binary.BigEndian.Uint16(o.Info[0:2]) + case LLDP8021SubtypeLinkAggregation: + if err = checkLLDPOrgSpecificLen(o, 5); err != nil { + return + } + sup := (o.Info[0]&LLDPAggregationCapability > 0) + en := (o.Info[0]&LLDPAggregationStatus > 0) + info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])} + } + } + return +} + +func (l *LinkLayerDiscoveryInfo) Decode8023() (info LLDPInfo8023, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUI8023 { + continue + } + switch o.SubType { + case LLDP8023SubtypeMACPHY: + if err = checkLLDPOrgSpecificLen(o, 5); err != nil { + return + } + sup := (o.Info[0]&LLDPMACPHYCapability > 0) + en := (o.Info[0]&LLDPMACPHYStatus > 0) + ca := binary.BigEndian.Uint16(o.Info[1:3]) + mau := binary.BigEndian.Uint16(o.Info[3:5]) + info.MACPHYConfigStatus = LLDPMACPHYConfigStatus{sup, en, ca, mau} + case LLDP8023SubtypeMDIPower: + if err = checkLLDPOrgSpecificLen(o, 3); err != nil { + return + } + info.PowerViaMDI.PortClassPSE = (o.Info[0]&LLDPMDIPowerPortClass > 0) + info.PowerViaMDI.PSESupported = (o.Info[0]&LLDPMDIPowerCapability > 0) + info.PowerViaMDI.PSEEnabled = (o.Info[0]&LLDPMDIPowerStatus > 0) + info.PowerViaMDI.PSEPairsAbility = (o.Info[0]&LLDPMDIPowerPairsAbility > 0) + info.PowerViaMDI.PSEPowerPair = uint8(o.Info[1]) + info.PowerViaMDI.PSEClass = uint8(o.Info[2]) + if len(o.Info) >= 7 { + info.PowerViaMDI.Type = LLDPPowerType((o.Info[3] & 0xc0) >> 6) + info.PowerViaMDI.Source = LLDPPowerSource((o.Info[3] & 0x30) >> 4) + if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 { + info.PowerViaMDI.Source += 128 // For Stringify purposes + } + info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[3] & 0x0f) + info.PowerViaMDI.Requested = binary.BigEndian.Uint16(o.Info[4:6]) + info.PowerViaMDI.Allocated = binary.BigEndian.Uint16(o.Info[6:8]) + } + case LLDP8023SubtypeLinkAggregation: + if err = checkLLDPOrgSpecificLen(o, 5); err != nil { + return + } + sup := (o.Info[0]&LLDPAggregationCapability > 0) + en := (o.Info[0]&LLDPAggregationStatus > 0) + info.LinkAggregation = LLDPLinkAggregation{sup, en, binary.BigEndian.Uint32(o.Info[1:5])} + case LLDP8023SubtypeMTU: + if err = checkLLDPOrgSpecificLen(o, 2); err != nil { + return + } + info.MTU = binary.BigEndian.Uint16(o.Info[0:2]) + } + } + return +} + +func (l *LinkLayerDiscoveryInfo) Decode8021Qbg() (info LLDPInfo8021Qbg, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUI8021Qbg { + continue + } + switch o.SubType { + case LLDP8021QbgEVB: + if err = checkLLDPOrgSpecificLen(o, 9); err != nil { + return + } + info.EVBSettings.Supported = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[0:2])) + info.EVBSettings.Enabled = getEVBCapabilities(binary.BigEndian.Uint16(o.Info[2:4])) + info.EVBSettings.SupportedVSIs = binary.BigEndian.Uint16(o.Info[4:6]) + info.EVBSettings.ConfiguredVSIs = binary.BigEndian.Uint16(o.Info[6:8]) + info.EVBSettings.RTEExponent = uint8(o.Info[8]) + } + } + return +} + +func (l *LinkLayerDiscoveryInfo) DecodeMedia() (info LLDPInfoMedia, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUIMedia { + continue + } + switch LLDPMediaSubtype(o.SubType) { + case LLDPMediaTypeCapabilities: + if err = checkLLDPOrgSpecificLen(o, 3); err != nil { + return + } + b := binary.BigEndian.Uint16(o.Info[0:2]) + info.MediaCapabilities.Capabilities = (b & LLDPMediaCapsLLDP) > 0 + info.MediaCapabilities.NetworkPolicy = (b & LLDPMediaCapsNetwork) > 0 + info.MediaCapabilities.Location = (b & LLDPMediaCapsLocation) > 0 + info.MediaCapabilities.PowerPSE = (b & LLDPMediaCapsPowerPSE) > 0 + info.MediaCapabilities.PowerPD = (b & LLDPMediaCapsPowerPD) > 0 + info.MediaCapabilities.Inventory = (b & LLDPMediaCapsInventory) > 0 + info.MediaCapabilities.Class = LLDPMediaClass(o.Info[2]) + case LLDPMediaTypeNetwork: + if err = checkLLDPOrgSpecificLen(o, 4); err != nil { + return + } + info.NetworkPolicy.ApplicationType = LLDPApplicationType(o.Info[0]) + b := binary.BigEndian.Uint16(o.Info[1:3]) + info.NetworkPolicy.Defined = (b & 0x8000) == 0 + info.NetworkPolicy.Tagged = (b & 0x4000) > 0 + info.NetworkPolicy.VLANId = (b & 0x1ffe) >> 1 + b = binary.BigEndian.Uint16(o.Info[2:4]) + info.NetworkPolicy.L2Priority = (b & 0x01c0) >> 6 + info.NetworkPolicy.DSCPValue = uint8(o.Info[3] & 0x3f) + case LLDPMediaTypeLocation: + if err = checkLLDPOrgSpecificLen(o, 1); err != nil { + return + } + info.Location.Format = LLDPLocationFormat(o.Info[0]) + o.Info = o.Info[1:] + switch info.Location.Format { + case LLDPLocationFormatCoordinate: + if err = checkLLDPOrgSpecificLen(o, 16); err != nil { + return + } + info.Location.Coordinate.LatitudeResolution = uint8(o.Info[0]&0xfc) >> 2 + b := binary.BigEndian.Uint64(o.Info[0:8]) + info.Location.Coordinate.Latitude = (b & 0x03ffffffff000000) >> 24 + info.Location.Coordinate.LongitudeResolution = uint8(o.Info[5]&0xfc) >> 2 + b = binary.BigEndian.Uint64(o.Info[5:13]) + info.Location.Coordinate.Longitude = (b & 0x03ffffffff000000) >> 24 + info.Location.Coordinate.AltitudeType = uint8((o.Info[10] & 0x30) >> 4) + b1 := binary.BigEndian.Uint16(o.Info[10:12]) + info.Location.Coordinate.AltitudeResolution = (b1 & 0xfc0) >> 6 + b2 := binary.BigEndian.Uint32(o.Info[11:15]) + info.Location.Coordinate.Altitude = b2 & 0x3fffffff + info.Location.Coordinate.Datum = uint8(o.Info[15]) + case LLDPLocationFormatAddress: + if err = checkLLDPOrgSpecificLen(o, 3); err != nil { + return + } + //ll := uint8(o.Info[0]) + info.Location.Address.What = LLDPLocationAddressWhat(o.Info[1]) + info.Location.Address.CountryCode = string(o.Info[2:4]) + data := o.Info[4:] + for len(data) > 1 { + aType := LLDPLocationAddressType(data[0]) + aLen := int(data[1]) + if len(data) >= aLen+2 { + info.Location.Address.AddressLines = append(info.Location.Address.AddressLines, LLDPLocationAddressLine{aType, string(data[2 : aLen+2])}) + data = data[aLen+2:] + } else { + break + } + } + case LLDPLocationFormatECS: + info.Location.ECS.ELIN = string(o.Info) + } + case LLDPMediaTypePower: + if err = checkLLDPOrgSpecificLen(o, 3); err != nil { + return + } + info.PowerViaMDI.Type = LLDPPowerType((o.Info[0] & 0xc0) >> 6) + info.PowerViaMDI.Source = LLDPPowerSource((o.Info[0] & 0x30) >> 4) + if info.PowerViaMDI.Type == 1 || info.PowerViaMDI.Type == 3 { + info.PowerViaMDI.Source += 128 // For Stringify purposes + } + info.PowerViaMDI.Priority = LLDPPowerPriority(o.Info[0] & 0x0f) + info.PowerViaMDI.Value = binary.BigEndian.Uint16(o.Info[1:3]) * 100 // 0 to 102.3 w, 0.1W increments + case LLDPMediaTypeHardware: + info.HardwareRevision = string(o.Info) + case LLDPMediaTypeFirmware: + info.FirmwareRevision = string(o.Info) + case LLDPMediaTypeSoftware: + info.SoftwareRevision = string(o.Info) + case LLDPMediaTypeSerial: + info.SerialNumber = string(o.Info) + case LLDPMediaTypeManufacturer: + info.Manufacturer = string(o.Info) + case LLDPMediaTypeModel: + info.Model = string(o.Info) + case LLDPMediaTypeAssetID: + info.AssetID = string(o.Info) + } + } + return +} + +func (l *LinkLayerDiscoveryInfo) DecodeCisco2() (info LLDPInfoCisco2, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUICisco2 { + continue + } + switch LLDPCisco2Subtype(o.SubType) { + case LLDPCisco2PowerViaMDI: + if err = checkLLDPOrgSpecificLen(o, 1); err != nil { + return + } + info.PSEFourWirePoESupported = (o.Info[0] & LLDPCiscoPSESupport) > 0 + info.PDSparePairArchitectureShared = (o.Info[0] & LLDPCiscoArchShared) > 0 + info.PDRequestSparePairPoEOn = (o.Info[0] & LLDPCiscoPDSparePair) > 0 + info.PSESparePairPoEOn = (o.Info[0] & LLDPCiscoPSESparePair) > 0 + } + } + return +} + +func (l *LinkLayerDiscoveryInfo) DecodeProfinet() (info LLDPInfoProfinet, err error) { + for _, o := range l.OrgTLVs { + if o.OUI != IEEEOUIProfinet { + continue + } + switch LLDPProfinetSubtype(o.SubType) { + case LLDPProfinetPNIODelay: + if err = checkLLDPOrgSpecificLen(o, 20); err != nil { + return + } + info.PNIODelay.RXLocal = binary.BigEndian.Uint32(o.Info[0:4]) + info.PNIODelay.RXRemote = binary.BigEndian.Uint32(o.Info[4:8]) + info.PNIODelay.TXLocal = binary.BigEndian.Uint32(o.Info[8:12]) + info.PNIODelay.TXRemote = binary.BigEndian.Uint32(o.Info[12:16]) + info.PNIODelay.CableLocal = binary.BigEndian.Uint32(o.Info[16:20]) + case LLDPProfinetPNIOPortStatus: + if err = checkLLDPOrgSpecificLen(o, 4); err != nil { + return + } + info.PNIOPortStatus.Class2 = binary.BigEndian.Uint16(o.Info[0:2]) + info.PNIOPortStatus.Class3 = binary.BigEndian.Uint16(o.Info[2:4]) + case LLDPProfinetPNIOMRPPortStatus: + if err = checkLLDPOrgSpecificLen(o, 18); err != nil { + return + } + info.PNIOMRPPortStatus.UUID = o.Info[0:16] + info.PNIOMRPPortStatus.Status = binary.BigEndian.Uint16(o.Info[16:18]) + case LLDPProfinetPNIOChassisMAC: + if err = checkLLDPOrgSpecificLen(o, 6); err != nil { + return + } + info.ChassisMAC = o.Info[0:6] + case LLDPProfinetPNIOPTCPStatus: + if err = checkLLDPOrgSpecificLen(o, 54); err != nil { + return + } + info.PNIOPTCPStatus.MasterAddress = o.Info[0:6] + info.PNIOPTCPStatus.SubdomainUUID = o.Info[6:22] + info.PNIOPTCPStatus.IRDataUUID = o.Info[22:38] + b := binary.BigEndian.Uint32(o.Info[38:42]) + info.PNIOPTCPStatus.PeriodValid = (b & 0x80000000) > 0 + info.PNIOPTCPStatus.PeriodLength = b & 0x7fffffff + b = binary.BigEndian.Uint32(o.Info[42:46]) + info.PNIOPTCPStatus.RedPeriodValid = (b & 0x80000000) > 0 + info.PNIOPTCPStatus.RedPeriodBegin = b & 0x7fffffff + b = binary.BigEndian.Uint32(o.Info[46:50]) + info.PNIOPTCPStatus.OrangePeriodValid = (b & 0x80000000) > 0 + info.PNIOPTCPStatus.OrangePeriodBegin = b & 0x7fffffff + b = binary.BigEndian.Uint32(o.Info[50:54]) + info.PNIOPTCPStatus.GreenPeriodValid = (b & 0x80000000) > 0 + info.PNIOPTCPStatus.GreenPeriodBegin = b & 0x7fffffff + } + } + return +} + +// LayerType returns gopacket.LayerTypeLinkLayerDiscoveryInfo. +func (c *LinkLayerDiscoveryInfo) LayerType() gopacket.LayerType { + return LayerTypeLinkLayerDiscoveryInfo +} + +func getCapabilities(v uint16) (c LLDPCapabilities) { + c.Other = (v&LLDPCapsOther > 0) + c.Repeater = (v&LLDPCapsRepeater > 0) + c.Bridge = (v&LLDPCapsBridge > 0) + c.WLANAP = (v&LLDPCapsWLANAP > 0) + c.Router = (v&LLDPCapsRouter > 0) + c.Phone = (v&LLDPCapsPhone > 0) + c.DocSis = (v&LLDPCapsDocSis > 0) + c.StationOnly = (v&LLDPCapsStationOnly > 0) + c.CVLAN = (v&LLDPCapsCVLAN > 0) + c.SVLAN = (v&LLDPCapsSVLAN > 0) + c.TMPR = (v&LLDPCapsTmpr > 0) + return +} + +func getEVBCapabilities(v uint16) (c LLDPEVBCapabilities) { + c.StandardBridging = (v & LLDPEVBCapsSTD) > 0 + c.StandardBridging = (v & LLDPEVBCapsSTD) > 0 + c.ReflectiveRelay = (v & LLDPEVBCapsRR) > 0 + c.RetransmissionTimerExponent = (v & LLDPEVBCapsRTE) > 0 + c.EdgeControlProtocol = (v & LLDPEVBCapsECP) > 0 + c.VSIDiscoveryProtocol = (v & LLDPEVBCapsVDP) > 0 + return +} + +func (t LLDPTLVType) String() (s string) { + switch t { + case LLDPTLVEnd: + s = "TLV End" + case LLDPTLVChassisID: + s = "Chassis ID" + case LLDPTLVPortID: + s = "Port ID" + case LLDPTLVTTL: + s = "TTL" + case LLDPTLVPortDescription: + s = "Port Description" + case LLDPTLVSysName: + s = "System Name" + case LLDPTLVSysDescription: + s = "System Description" + case LLDPTLVSysCapabilities: + s = "System Capabilities" + case LLDPTLVMgmtAddress: + s = "Management Address" + case LLDPTLVOrgSpecific: + s = "Organisation Specific" + default: + s = "Unknown" + } + return +} + +func (t LLDPChassisIDSubType) String() (s string) { + switch t { + case LLDPChassisIDSubTypeReserved: + s = "Reserved" + case LLDPChassisIDSubTypeChassisComp: + s = "Chassis Component" + case LLDPChassisIDSubtypeIfaceAlias: + s = "Interface Alias" + case LLDPChassisIDSubTypePortComp: + s = "Port Component" + case LLDPChassisIDSubTypeMACAddr: + s = "MAC Address" + case LLDPChassisIDSubTypeNetworkAddr: + s = "Network Address" + case LLDPChassisIDSubtypeIfaceName: + s = "Interface Name" + case LLDPChassisIDSubTypeLocal: + s = "Local" + default: + s = "Unknown" + } + return +} + +func (t LLDPPortIDSubType) String() (s string) { + switch t { + case LLDPPortIDSubtypeReserved: + s = "Reserved" + case LLDPPortIDSubtypeIfaceAlias: + s = "Interface Alias" + case LLDPPortIDSubtypePortComp: + s = "Port Component" + case LLDPPortIDSubtypeMACAddr: + s = "MAC Address" + case LLDPPortIDSubtypeNetworkAddr: + s = "Network Address" + case LLDPPortIDSubtypeIfaceName: + s = "Interface Name" + case LLDPPortIDSubtypeAgentCircuitID: + s = "Agent Circuit ID" + case LLDPPortIDSubtypeLocal: + s = "Local" + default: + s = "Unknown" + } + return +} + +func (t IANAAddressFamily) String() (s string) { + switch t { + case IANAAddressFamilyReserved: + s = "Reserved" + case IANAAddressFamilyIPV4: + s = "IPv4" + case IANAAddressFamilyIPV6: + s = "IPv6" + case IANAAddressFamilyNSAP: + s = "NSAP" + case IANAAddressFamilyHDLC: + s = "HDLC" + case IANAAddressFamilyBBN1822: + s = "BBN 1822" + case IANAAddressFamily802: + s = "802 media plus Ethernet 'canonical format'" + case IANAAddressFamilyE163: + s = "E.163" + case IANAAddressFamilyE164: + s = "E.164 (SMDS, Frame Relay, ATM)" + case IANAAddressFamilyF69: + s = "F.69 (Telex)" + case IANAAddressFamilyX121: + s = "X.121, X.25, Frame Relay" + case IANAAddressFamilyIPX: + s = "IPX" + case IANAAddressFamilyAtalk: + s = "Appletalk" + case IANAAddressFamilyDecnet: + s = "Decnet IV" + case IANAAddressFamilyBanyan: + s = "Banyan Vines" + case IANAAddressFamilyE164NSAP: + s = "E.164 with NSAP format subaddress" + case IANAAddressFamilyDNS: + s = "DNS" + case IANAAddressFamilyDistname: + s = "Distinguished Name" + case IANAAddressFamilyASNumber: + s = "AS Number" + case IANAAddressFamilyXTPIPV4: + s = "XTP over IP version 4" + case IANAAddressFamilyXTPIPV6: + s = "XTP over IP version 6" + case IANAAddressFamilyXTP: + s = "XTP native mode XTP" + case IANAAddressFamilyFcWWPN: + s = "Fibre Channel World-Wide Port Name" + case IANAAddressFamilyFcWWNN: + s = "Fibre Channel World-Wide Node Name" + case IANAAddressFamilyGWID: + s = "GWID" + case IANAAddressFamilyL2VPN: + s = "AFI for Layer 2 VPN" + default: + s = "Unknown" + } + return +} + +func (t LLDPInterfaceSubtype) String() (s string) { + switch t { + case LLDPInterfaceSubtypeUnknown: + s = "Unknown" + case LLDPInterfaceSubtypeifIndex: + s = "IfIndex" + case LLDPInterfaceSubtypeSysPort: + s = "System Port Number" + default: + s = "Unknown" + } + return +} + +func (t LLDPPowerType) String() (s string) { + switch t { + case 0: + s = "Type 2 PSE Device" + case 1: + s = "Type 2 PD Device" + case 2: + s = "Type 1 PSE Device" + case 3: + s = "Type 1 PD Device" + default: + s = "Unknown" + } + return +} + +func (t LLDPPowerSource) String() (s string) { + switch t { + // PD Device + case 0: + s = "Unknown" + case 1: + s = "PSE" + case 2: + s = "Local" + case 3: + s = "PSE and Local" + // PSE Device (Actual value + 128) + case 128: + s = "Unknown" + case 129: + s = "Primary Power Source" + case 130: + s = "Backup Power Source" + default: + s = "Unknown" + } + return +} + +func (t LLDPPowerPriority) String() (s string) { + switch t { + case 0: + s = "Unknown" + case 1: + s = "Critical" + case 2: + s = "High" + case 3: + s = "Low" + default: + s = "Unknown" + } + return +} + +func (t LLDPMediaSubtype) String() (s string) { + switch t { + case LLDPMediaTypeCapabilities: + s = "Media Capabilities" + case LLDPMediaTypeNetwork: + s = "Network Policy" + case LLDPMediaTypeLocation: + s = "Location Identification" + case LLDPMediaTypePower: + s = "Extended Power-via-MDI" + case LLDPMediaTypeHardware: + s = "Hardware Revision" + case LLDPMediaTypeFirmware: + s = "Firmware Revision" + case LLDPMediaTypeSoftware: + s = "Software Revision" + case LLDPMediaTypeSerial: + s = "Serial Number" + case LLDPMediaTypeManufacturer: + s = "Manufacturer" + case LLDPMediaTypeModel: + s = "Model" + case LLDPMediaTypeAssetID: + s = "Asset ID" + default: + s = "Unknown" + } + return +} + +func (t LLDPMediaClass) String() (s string) { + switch t { + case LLDPMediaClassUndefined: + s = "Undefined" + case LLDPMediaClassEndpointI: + s = "Endpoint Class I" + case LLDPMediaClassEndpointII: + s = "Endpoint Class II" + case LLDPMediaClassEndpointIII: + s = "Endpoint Class III" + case LLDPMediaClassNetwork: + s = "Network Connectivity" + default: + s = "Unknown" + } + return +} + +func (t LLDPApplicationType) String() (s string) { + switch t { + case LLDPAppTypeReserved: + s = "Reserved" + case LLDPAppTypeVoice: + s = "Voice" + case LLDPappTypeVoiceSignaling: + s = "Voice Signaling" + case LLDPappTypeGuestVoice: + s = "Guest Voice" + case LLDPappTypeGuestVoiceSignaling: + s = "Guest Voice Signaling" + case LLDPappTypeSoftphoneVoice: + s = "Softphone Voice" + case LLDPappTypeVideoConferencing: + s = "Video Conferencing" + case LLDPappTypeStreamingVideo: + s = "Streaming Video" + case LLDPappTypeVideoSignaling: + s = "Video Signaling" + default: + s = "Unknown" + } + return +} + +func (t LLDPLocationFormat) String() (s string) { + switch t { + case LLDPLocationFormatInvalid: + s = "Invalid" + case LLDPLocationFormatCoordinate: + s = "Coordinate-based LCI" + case LLDPLocationFormatAddress: + s = "Address-based LCO" + case LLDPLocationFormatECS: + s = "ECS ELIN" + default: + s = "Unknown" + } + return +} + +func (t LLDPLocationAddressType) String() (s string) { + switch t { + case LLDPLocationAddressTypeLanguage: + s = "Language" + case LLDPLocationAddressTypeNational: + s = "National subdivisions (province, state, etc)" + case LLDPLocationAddressTypeCounty: + s = "County, parish, district" + case LLDPLocationAddressTypeCity: + s = "City, township" + case LLDPLocationAddressTypeCityDivision: + s = "City division, borough, ward" + case LLDPLocationAddressTypeNeighborhood: + s = "Neighborhood, block" + case LLDPLocationAddressTypeStreet: + s = "Street" + case LLDPLocationAddressTypeLeadingStreet: + s = "Leading street direction" + case LLDPLocationAddressTypeTrailingStreet: + s = "Trailing street suffix" + case LLDPLocationAddressTypeStreetSuffix: + s = "Street suffix" + case LLDPLocationAddressTypeHouseNum: + s = "House number" + case LLDPLocationAddressTypeHouseSuffix: + s = "House number suffix" + case LLDPLocationAddressTypeLandmark: + s = "Landmark or vanity address" + case LLDPLocationAddressTypeAdditional: + s = "Additional location information" + case LLDPLocationAddressTypeName: + s = "Name" + case LLDPLocationAddressTypePostal: + s = "Postal/ZIP code" + case LLDPLocationAddressTypeBuilding: + s = "Building" + case LLDPLocationAddressTypeUnit: + s = "Unit" + case LLDPLocationAddressTypeFloor: + s = "Floor" + case LLDPLocationAddressTypeRoom: + s = "Room number" + case LLDPLocationAddressTypePlace: + s = "Place type" + case LLDPLocationAddressTypeScript: + s = "Script" + default: + s = "Unknown" + } + return +} + +func checkLLDPTLVLen(v LinkLayerDiscoveryValue, l int) (err error) { + if len(v.Value) < l { + err = fmt.Errorf("Invalid TLV %v length %d (wanted mimimum %v", v.Type, len(v.Value), l) + } + return +} + +func checkLLDPOrgSpecificLen(o LLDPOrgSpecificTLV, l int) (err error) { + if len(o.Info) < l { + err = fmt.Errorf("Invalid Org Specific TLV %v length %d (wanted minimum %v)", o.SubType, len(o.Info), l) + } + return +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/loopback.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/loopback.go new file mode 100644 index 0000000000..03f48e3914 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/loopback.go @@ -0,0 +1,80 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// Loopback contains the header for loopback encapsulation. This header is +// used by both BSD and OpenBSD style loopback decoding (pcap's DLT_NULL +// and DLT_LOOP, respectively). +type Loopback struct { + BaseLayer + Family ProtocolFamily +} + +// LayerType returns LayerTypeLoopback. +func (l *Loopback) LayerType() gopacket.LayerType { return LayerTypeLoopback } + +// DecodeFromBytes decodes the given bytes into this layer. +func (l *Loopback) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + return errors.New("Loopback packet too small") + } + + // The protocol could be either big-endian or little-endian, we're + // not sure. But we're PRETTY sure that the value is less than + // 256, so we can check the first two bytes. + var prot uint32 + if data[0] == 0 && data[1] == 0 { + prot = binary.BigEndian.Uint32(data[:4]) + } else { + prot = binary.LittleEndian.Uint32(data[:4]) + } + if prot > 0xFF { + return fmt.Errorf("Invalid loopback protocol %q", data[:4]) + } + + l.Family = ProtocolFamily(prot) + l.BaseLayer = BaseLayer{data[:4], data[4:]} + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (l *Loopback) CanDecode() gopacket.LayerClass { + return LayerTypeLoopback +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (l *Loopback) NextLayerType() gopacket.LayerType { + return l.Family.LayerType() +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +func (l *Loopback) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + binary.LittleEndian.PutUint32(bytes, uint32(l.Family)) + return nil +} + +func decodeLoopback(data []byte, p gopacket.PacketBuilder) error { + l := Loopback{} + if err := l.DecodeFromBytes(data, gopacket.NilDecodeFeedback); err != nil { + return err + } + p.AddLayer(&l) + return p.NextDecoder(l.Family) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mdp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mdp.go new file mode 100644 index 0000000000..a3e3bd5dad --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mdp.go @@ -0,0 +1,162 @@ +// Copyright 2024 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 layers + +import ( + "fmt" + "net" + "strconv" + + "github.com/gopacket/gopacket" +) + +const ( + MdpTlvType uint8 = iota + MdpTlvLength + MdpTlvDeviceInfo + MdpTlvNetworkInfo + MdpTlvLongitude + MdpTlvLatitude + MdpTlvType6 + MdpTlvType7 + MdpTlvIP = 11 + MdpTlvUnknownBool = 13 + MdpTlvEnd = 255 +) + +// MDP defines a MDP over LLC layer. +type MDP struct { + BaseLayer + PreambleData []byte + DeviceInfo string + NetworkInfo string + Longitude float64 + Latitude float64 + Type6UUID string + Type7UUID string + IPAddress net.IP + Type13Bool bool + + Type EthernetType + Length int +} + +// LayerType returns LayerTypeMDP. +func (m *MDP) LayerType() gopacket.LayerType { return LayerTypeMDP } + +// DecodeFromBytes decodes the given bytes into this layer. +func (m *MDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + var length int + if len(data) < 28 { + df.SetTruncated() + return fmt.Errorf("MDP length %d too short", len(data)) + } + m.Type = EthernetTypeMerakiDiscoveryProtocol + m.Length = len(data) + offset := 28 + m.PreambleData = data[:offset] + + for { + if offset >= m.Length { + break + } + t := data[offset] + switch t { + case MdpTlvDeviceInfo: + offset += 2 + length = int(data[offset-1]) + m.Contents = append(m.Contents, data[offset-2:offset+length]...) + m.DeviceInfo = string(data[offset : offset+length]) + offset += length + break + case MdpTlvNetworkInfo: + offset += 2 + length = int(data[offset-1]) + m.NetworkInfo = string(data[offset : offset+length]) + offset += length + break + case MdpTlvLongitude: + offset += 2 + length = int(data[offset-1]) + m.Longitude, _ = strconv.ParseFloat(string(data[offset:offset+length]), 64) + offset += length + break + case MdpTlvLatitude: + offset += 2 + length = int(data[offset-1]) + m.Latitude, _ = strconv.ParseFloat(string(data[offset:offset+length]), 64) + offset += length + break + case MdpTlvType6: + offset += 2 + length = int(data[offset-1]) + m.Type6UUID = string(data[offset : offset+length]) + offset += length + break + case MdpTlvType7: + offset += 2 + length = int(data[offset-1]) + m.Type7UUID = string(data[offset : offset+length]) + offset += length + break + case MdpTlvIP: + offset += 2 + length = int(data[offset-1]) + m.IPAddress = net.ParseIP(string(data[offset : offset+length])) + offset += length + break + case MdpTlvUnknownBool: + offset += 2 + length = int(data[offset-1]) + m.Type13Bool, _ = strconv.ParseBool(string(data[offset : offset+length])) + offset += length + break + case MdpTlvEnd: + offset = m.Length + break + default: + // Skip over unknown junk + offset += 2 + length = int(data[offset-1]) + offset += length + break + + } + } + m.BaseLayer = BaseLayer{Contents: data, Payload: nil} + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer +func (m *MDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + // bytes, _ := b.PrependBytes(4) + // bytes[0] = m.Version + // bytes[1] = byte(m.Type) + // binary.BigEndian.PutUint16(bytes[2:], m.Length) + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (m *MDP) CanDecode() gopacket.LayerClass { + return LayerTypeMDP +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (m *MDP) NextLayerType() gopacket.LayerType { + return m.Type.LayerType() +} + +func decodeMDP(data []byte, p gopacket.PacketBuilder) error { + m := &MDP{} + err := m.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(m) + return p.NextDecoder(m.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv1.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv1.go new file mode 100644 index 0000000000..aef6e83822 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv1.go @@ -0,0 +1,182 @@ +// Copyright 2018 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. + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + "math" + "net" + "time" + + "github.com/gopacket/gopacket" +) + +// MLDv1Message represents the common structure of all MLDv1 messages +type MLDv1Message struct { + BaseLayer + // 3.4. Maximum Response Delay + MaximumResponseDelay time.Duration + // 3.6. Multicast Address + // Zero in general query + // Specific IPv6 multicast address otherwise + MulticastAddress net.IP +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (m *MLDv1Message) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + df.SetTruncated() + return errors.New("ICMP layer less than 20 bytes for Multicast Listener Query Message V1") + } + + m.MaximumResponseDelay = time.Duration(binary.BigEndian.Uint16(data[0:2])) * time.Millisecond + // data[2:4] is reserved and not used in mldv1 + m.MulticastAddress = data[4:20] + + return nil +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (*MLDv1Message) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (m *MLDv1Message) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf, err := b.PrependBytes(20) + if err != nil { + return err + } + + if m.MaximumResponseDelay < 0 { + return errors.New("maximum response delay must not be negative") + } + dms := m.MaximumResponseDelay / time.Millisecond + if dms > math.MaxUint16 { + return fmt.Errorf("maximum response delay %dms is more than the allowed 65535ms", dms) + } + binary.BigEndian.PutUint16(buf[0:2], uint16(dms)) + + copy(buf[2:4], []byte{0x0, 0x0}) + + ma16 := m.MulticastAddress.To16() + if ma16 == nil { + return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) + } + copy(buf[4:20], ma16) + + return nil +} + +// Sums this layer up nicely formatted +func (m *MLDv1Message) String() string { + return fmt.Sprintf( + "Maximum Response Delay: %dms, Multicast Address: %s", + m.MaximumResponseDelay/time.Millisecond, + m.MulticastAddress) +} + +// MLDv1MulticastListenerQueryMessage are sent by the router to determine +// whether there are multicast listeners on the link. +// https://tools.ietf.org/html/rfc2710 Page 5 +type MLDv1MulticastListenerQueryMessage struct { + MLDv1Message +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (m *MLDv1MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + err := m.MLDv1Message.DecodeFromBytes(data, df) + if err != nil { + return err + } + + if len(data) > 20 { + m.Payload = data[20:] + } + + return nil +} + +// LayerType returns LayerTypeMLDv1MulticastListenerQuery. +func (*MLDv1MulticastListenerQueryMessage) LayerType() gopacket.LayerType { + return LayerTypeMLDv1MulticastListenerQuery +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (*MLDv1MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { + return LayerTypeMLDv1MulticastListenerQuery +} + +// IsGeneralQuery is true when this is a general query. +// In a Query message, the Multicast Address field is set to zero when +// sending a General Query. +// https://tools.ietf.org/html/rfc2710#section-3.6 +func (m *MLDv1MulticastListenerQueryMessage) IsGeneralQuery() bool { + return net.IPv6zero.Equal(m.MulticastAddress) +} + +// IsSpecificQuery is true when this is not a general query. +// In a Query message, the Multicast Address field is set to a specific +// IPv6 multicast address when sending a Multicast-Address-Specific Query. +// https://tools.ietf.org/html/rfc2710#section-3.6 +func (m *MLDv1MulticastListenerQueryMessage) IsSpecificQuery() bool { + return !m.IsGeneralQuery() +} + +// MLDv1MulticastListenerReportMessage is sent by a client listening on +// a specific multicast address to indicate that it is (still) listening +// on the specific multicast address. +// https://tools.ietf.org/html/rfc2710 Page 6 +type MLDv1MulticastListenerReportMessage struct { + MLDv1Message +} + +// LayerType returns LayerTypeMLDv1MulticastListenerReport. +func (*MLDv1MulticastListenerReportMessage) LayerType() gopacket.LayerType { + return LayerTypeMLDv1MulticastListenerReport +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (*MLDv1MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { + return LayerTypeMLDv1MulticastListenerReport +} + +// MLDv1MulticastListenerDoneMessage should be sent by a client when it ceases +// to listen to a multicast address on an interface. +// https://tools.ietf.org/html/rfc2710 Page 7 +type MLDv1MulticastListenerDoneMessage struct { + MLDv1Message +} + +// LayerType returns LayerTypeMLDv1MulticastListenerDone. +func (*MLDv1MulticastListenerDoneMessage) LayerType() gopacket.LayerType { + return LayerTypeMLDv1MulticastListenerDone +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (*MLDv1MulticastListenerDoneMessage) CanDecode() gopacket.LayerClass { + return LayerTypeMLDv1MulticastListenerDone +} + +func decodeMLDv1MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { + m := &MLDv1MulticastListenerReportMessage{} + return decodingLayerDecoder(m, data, p) +} + +func decodeMLDv1MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { + m := &MLDv1MulticastListenerQueryMessage{} + return decodingLayerDecoder(m, data, p) +} + +func decodeMLDv1MulticastListenerDone(data []byte, p gopacket.PacketBuilder) error { + m := &MLDv1MulticastListenerDoneMessage{} + return decodingLayerDecoder(m, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv2.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv2.go new file mode 100644 index 0000000000..ebcab88e05 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mldv2.go @@ -0,0 +1,619 @@ +// Copyright 2018 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. + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + "math" + "net" + "time" + + "github.com/gopacket/gopacket" +) + +const ( + // S Flag bit is 1 + mldv2STrue uint8 = 0x8 + + // S Flag value mask + // mldv2STrue & mldv2SMask == mldv2STrue // true + // 0x1 & mldv2SMask == mldv2STrue // true + // 0x0 & mldv2SMask == mldv2STrue // false + mldv2SMask uint8 = 0x8 + + // QRV value mask + mldv2QRVMask uint8 = 0x7 +) + +// MLDv2MulticastListenerQueryMessage are sent by multicast routers to query the +// multicast listening state of neighboring interfaces. +// https://tools.ietf.org/html/rfc3810#section-5.1 +// +// Some information, like Maximum Response Code and Multicast Address are in the +// previous layer LayerTypeMLDv1MulticastListenerQuery +type MLDv2MulticastListenerQueryMessage struct { + BaseLayer + // 5.1.3. Maximum Response Delay COde + MaximumResponseCode uint16 + // 5.1.5. Multicast Address + // Zero in general query + // Specific IPv6 multicast address otherwise + MulticastAddress net.IP + // 5.1.7. S Flag (Suppress Router-Side Processing) + SuppressRoutersideProcessing bool + // 5.1.8. QRV (Querier's Robustness Variable) + QueriersRobustnessVariable uint8 + // 5.1.9. QQIC (Querier's Query Interval Code) + QueriersQueryIntervalCode uint8 + // 5.1.10. Number of Sources (N) + NumberOfSources uint16 + // 5.1.11 Source Address [i] + SourceAddresses []net.IP +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (m *MLDv2MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 24 { + df.SetTruncated() + return errors.New("ICMP layer less than 24 bytes for Multicast Listener Query Message V2") + } + + m.MaximumResponseCode = binary.BigEndian.Uint16(data[0:2]) + // ignore data[2:4] as per https://tools.ietf.org/html/rfc3810#section-5.1.4 + m.MulticastAddress = data[4:20] + m.SuppressRoutersideProcessing = (data[20] & mldv2SMask) == mldv2STrue + m.QueriersRobustnessVariable = data[20] & mldv2QRVMask + m.QueriersQueryIntervalCode = data[21] + + m.NumberOfSources = binary.BigEndian.Uint16(data[22:24]) + + var end int + for i := uint16(0); i < m.NumberOfSources; i++ { + begin := 24 + (int(i) * 16) + end = begin + 16 + + if end > len(data) { + df.SetTruncated() + return fmt.Errorf("ICMP layer less than %d bytes for Multicast Listener Query Message V2", end) + } + + m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) + } + + return nil +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (*MLDv2MulticastListenerQueryMessage) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (m *MLDv2MulticastListenerQueryMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := m.serializeSourceAddressesTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(24) + if err != nil { + return err + } + + binary.BigEndian.PutUint16(buf[0:2], m.MaximumResponseCode) + copy(buf[2:4], []byte{0x00, 0x00}) // set reserved bytes to zero + + ma16 := m.MulticastAddress.To16() + if ma16 == nil { + return fmt.Errorf("invalid MulticastAddress '%s'", m.MulticastAddress) + } + copy(buf[4:20], ma16) + + byte20 := m.QueriersRobustnessVariable & mldv2QRVMask + if m.SuppressRoutersideProcessing { + byte20 |= mldv2STrue + } else { + byte20 &= ^mldv2STrue // the complement of mldv2STrue + } + byte20 &= 0x0F // set reserved bits to zero + buf[20] = byte20 + + binary.BigEndian.PutUint16(buf[22:24], m.NumberOfSources) + buf[21] = m.QueriersQueryIntervalCode + + return nil +} + +// writes each source address to the buffer preserving the order +func (m *MLDv2MulticastListenerQueryMessage) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + numberOfSourceAddresses := len(m.SourceAddresses) + if numberOfSourceAddresses > math.MaxUint16 { + return fmt.Errorf( + "there are more than %d source addresses, but 65535 is the maximum number of supported addresses", + numberOfSourceAddresses) + } + + if opts.FixLengths { + m.NumberOfSources = uint16(numberOfSourceAddresses) + } + + lastSAIdx := numberOfSourceAddresses - 1 + for k := range m.SourceAddresses { + i := lastSAIdx - k // reverse order + + buf, err := b.PrependBytes(16) + if err != nil { + return err + } + + sa16 := m.SourceAddresses[i].To16() + if sa16 == nil { + return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) + } + copy(buf[0:16], sa16) + } + + return nil +} + +// String sums this layer up nicely formatted +func (m *MLDv2MulticastListenerQueryMessage) String() string { + return fmt.Sprintf( + "Maximum Response Code: %#x (%dms), Multicast Address: %s, Suppress Routerside Processing: %t, QRV: %#x, QQIC: %#x (%ds), Number of Source Address: %d (actual: %d), Source Addresses: %s", + m.MaximumResponseCode, + m.MaximumResponseDelay(), + m.MulticastAddress, + m.SuppressRoutersideProcessing, + m.QueriersRobustnessVariable, + m.QueriersQueryIntervalCode, + m.QQI()/time.Second, + m.NumberOfSources, + len(m.SourceAddresses), + m.SourceAddresses) +} + +// LayerType returns LayerTypeMLDv2MulticastListenerQuery. +func (*MLDv2MulticastListenerQueryMessage) LayerType() gopacket.LayerType { + return LayerTypeMLDv2MulticastListenerQuery +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (*MLDv2MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { + return LayerTypeMLDv2MulticastListenerQuery +} + +// QQI calculates the Querier's Query Interval based on the QQIC +// according to https://tools.ietf.org/html/rfc3810#section-5.1.9 +func (m *MLDv2MulticastListenerQueryMessage) QQI() time.Duration { + data := m.QueriersQueryIntervalCode + if data < 128 { + return time.Second * time.Duration(data) + } + + exp := uint16(data) & 0x70 >> 4 + mant := uint16(data) & 0x0F + return time.Second * time.Duration(mant|0x1000<<(exp+3)) +} + +// SetQQI calculates and updates the Querier's Query Interval Code (QQIC) +// according to https://tools.ietf.org/html/rfc3810#section-5.1.9 +func (m *MLDv2MulticastListenerQueryMessage) SetQQI(d time.Duration) error { + if d < 0 { + m.QueriersQueryIntervalCode = 0 + return errors.New("QQI duration is negative") + } + + if d == 0 { + m.QueriersQueryIntervalCode = 0 + return nil + } + + dms := d / time.Second + if dms < 128 { + m.QueriersQueryIntervalCode = uint8(dms) + } + + if dms > 31744 { // mant=0xF, exp=0x7 + m.QueriersQueryIntervalCode = 0xFF + return fmt.Errorf("QQI duration %ds is, maximum allowed is 31744s", dms) + } + + value := uint16(dms) // ok, because 31744 < math.MaxUint16 + exp := uint8(7) + for mask := uint16(0x4000); exp > 0; exp-- { + if mask&value != 0 { + break + } + + mask >>= 1 + } + + mant := uint8(0x000F & (value >> (exp + 3))) + sig := uint8(0x10) + m.QueriersQueryIntervalCode = sig | exp<<4 | mant + + return nil +} + +// MaximumResponseDelay returns the Maximum Response Delay based on the +// Maximum Response Code according to +// https://tools.ietf.org/html/rfc3810#section-5.1.3 +func (m *MLDv2MulticastListenerQueryMessage) MaximumResponseDelay() time.Duration { + if m.MaximumResponseCode < 0x8000 { + return time.Duration(m.MaximumResponseCode) + } + + exp := m.MaximumResponseCode & 0x7000 >> 12 + mant := m.MaximumResponseCode & 0x0FFF + + return time.Millisecond * time.Duration(mant|0x1000<<(exp+3)) +} + +// SetMLDv2MaximumResponseDelay updates the Maximum Response Code according to +// https://tools.ietf.org/html/rfc3810#section-5.1.3 +func (m *MLDv2MulticastListenerQueryMessage) SetMLDv2MaximumResponseDelay(d time.Duration) error { + if d == 0 { + m.MaximumResponseCode = 0 + return nil + } + + if d < 0 { + return errors.New("maximum response delay must not be negative") + } + + dms := d / time.Millisecond + + if dms < 32768 { + m.MaximumResponseCode = uint16(dms) + } + + if dms > 4193280 { // mant=0xFFF, exp=0x7 + return fmt.Errorf("maximum response delay %dms is bigger the than maximum of 4193280ms", dms) + } + + value := uint32(dms) // ok, because 4193280 < math.MaxUint32 + exp := uint8(7) + for mask := uint32(0x40000000); exp > 0; exp-- { + if mask&value != 0 { + break + } + + mask >>= 1 + } + + mant := uint16(0x00000FFF & (value >> (exp + 3))) + sig := uint16(0x1000) + m.MaximumResponseCode = sig | uint16(exp)<<12 | mant + return nil +} + +// MLDv2MulticastListenerReportMessage is sent by an IP node to report the +// current multicast listening state, or changes therein. +// https://tools.ietf.org/html/rfc3810#section-5.2 +type MLDv2MulticastListenerReportMessage struct { + BaseLayer + // 5.2.3. Nr of Mcast Address Records + NumberOfMulticastAddressRecords uint16 + // 5.2.4. Multicast Address Record [i] + MulticastAddressRecords []MLDv2MulticastAddressRecord +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (m *MLDv2MulticastListenerReportMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return errors.New("ICMP layer less than 4 bytes for Multicast Listener Report Message V2") + } + + // ignore data[0:2] as per RFC + // https://tools.ietf.org/html/rfc3810#section-5.2.1 + m.NumberOfMulticastAddressRecords = binary.BigEndian.Uint16(data[2:4]) + + begin := 4 + for i := uint16(0); i < m.NumberOfMulticastAddressRecords; i++ { + mar := MLDv2MulticastAddressRecord{} + read, err := mar.decode(data[begin:], df) + if err != nil { + return err + } + + m.MulticastAddressRecords = append(m.MulticastAddressRecords, mar) + + begin += read + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (m *MLDv2MulticastListenerReportMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + lastItemIdx := len(m.MulticastAddressRecords) - 1 + for k := range m.MulticastAddressRecords { + i := lastItemIdx - k // reverse order + + err := m.MulticastAddressRecords[i].serializeTo(b, opts) + if err != nil { + return err + } + } + + if opts.FixLengths { + numberOfMAR := len(m.MulticastAddressRecords) + if numberOfMAR > math.MaxUint16 { + return fmt.Errorf( + "%d multicast address records added, but the maximum is 65535", + numberOfMAR) + } + + m.NumberOfMulticastAddressRecords = uint16(numberOfMAR) + } + + buf, err := b.PrependBytes(4) + if err != nil { + return err + } + + copy(buf[0:2], []byte{0x0, 0x0}) + binary.BigEndian.PutUint16(buf[2:4], m.NumberOfMulticastAddressRecords) + return nil +} + +// Sums this layer up nicely formatted +func (m *MLDv2MulticastListenerReportMessage) String() string { + return fmt.Sprintf( + "Number of Mcast Addr Records: %d (actual %d), Multicast Address Records: %+v", + m.NumberOfMulticastAddressRecords, + len(m.MulticastAddressRecords), + m.MulticastAddressRecords) +} + +// LayerType returns LayerTypeMLDv2MulticastListenerQuery. +func (*MLDv2MulticastListenerReportMessage) LayerType() gopacket.LayerType { + return LayerTypeMLDv2MulticastListenerReport +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (*MLDv2MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { + return LayerTypeMLDv2MulticastListenerReport +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (*MLDv2MulticastListenerReportMessage) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// MLDv2MulticastAddressRecordType holds the type of a +// Multicast Address Record, according to +// https://tools.ietf.org/html/rfc3810#section-5.2.5 and +// https://tools.ietf.org/html/rfc3810#section-5.2.12 +type MLDv2MulticastAddressRecordType uint8 + +const ( + // MLDv2MulticastAddressRecordTypeModeIsIncluded stands for + // MODE_IS_INCLUDE - indicates that the interface has a filter + // mode of INCLUDE for the specified multicast address. + MLDv2MulticastAddressRecordTypeModeIsIncluded MLDv2MulticastAddressRecordType = 1 + // MLDv2MulticastAddressRecordTypeModeIsExcluded stands for + // MODE_IS_EXCLUDE - indicates that the interface has a filter + // mode of EXCLUDE for the specified multicast address. + MLDv2MulticastAddressRecordTypeModeIsExcluded MLDv2MulticastAddressRecordType = 2 + // MLDv2MulticastAddressRecordTypeChangeToIncludeMode stands for + // CHANGE_TO_INCLUDE_MODE - indicates that the interface has + // changed to INCLUDE filter mode for the specified multicast + // address. + MLDv2MulticastAddressRecordTypeChangeToIncludeMode MLDv2MulticastAddressRecordType = 3 + // MLDv2MulticastAddressRecordTypeChangeToExcludeMode stands for + // CHANGE_TO_EXCLUDE_MODE - indicates that the interface has + // changed to EXCLUDE filter mode for the specified multicast + // address + MLDv2MulticastAddressRecordTypeChangeToExcludeMode MLDv2MulticastAddressRecordType = 4 + // MLDv2MulticastAddressRecordTypeAllowNewSources stands for + // ALLOW_NEW_SOURCES - indicates that the Source Address [i] + // fields in this Multicast Address Record contain a list of + // the additional sources that the node wishes to listen to, + // for packets sent to the specified multicast address. + MLDv2MulticastAddressRecordTypeAllowNewSources MLDv2MulticastAddressRecordType = 5 + // MLDv2MulticastAddressRecordTypeBlockOldSources stands for + // BLOCK_OLD_SOURCES - indicates that the Source Address [i] + // fields in this Multicast Address Record contain a list of + // the sources that the node no longer wishes to listen to, + // for packets sent to the specified multicast address. + MLDv2MulticastAddressRecordTypeBlockOldSources MLDv2MulticastAddressRecordType = 6 +) + +// Human readable record types +// Naming follows https://tools.ietf.org/html/rfc3810#section-5.2.12 +func (m MLDv2MulticastAddressRecordType) String() string { + switch m { + case MLDv2MulticastAddressRecordTypeModeIsIncluded: + return "MODE_IS_INCLUDE" + case MLDv2MulticastAddressRecordTypeModeIsExcluded: + return "MODE_IS_EXCLUDE" + case MLDv2MulticastAddressRecordTypeChangeToIncludeMode: + return "CHANGE_TO_INCLUDE_MODE" + case MLDv2MulticastAddressRecordTypeChangeToExcludeMode: + return "CHANGE_TO_EXCLUDE_MODE" + case MLDv2MulticastAddressRecordTypeAllowNewSources: + return "ALLOW_NEW_SOURCES" + case MLDv2MulticastAddressRecordTypeBlockOldSources: + return "BLOCK_OLD_SOURCES" + default: + return fmt.Sprintf("UNKNOWN(%d)", m) + } +} + +// MLDv2MulticastAddressRecord contains information on the sender listening to a +// single multicast address on the interface the report is sent. +// https://tools.ietf.org/html/rfc3810#section-5.2.4 +type MLDv2MulticastAddressRecord struct { + // 5.2.5. Record Type + RecordType MLDv2MulticastAddressRecordType + // 5.2.6. Auxiliary Data Length (number of 32-bit words) + AuxDataLen uint8 + // 5.2.7. Number Of Sources (N) + N uint16 + // 5.2.8. Multicast Address + MulticastAddress net.IP + // 5.2.9 Source Address [i] + SourceAddresses []net.IP + // 5.2.10 Auxiliary Data + AuxiliaryData []byte +} + +// decodes a multicast address record from bytes +func (m *MLDv2MulticastAddressRecord) decode(data []byte, df gopacket.DecodeFeedback) (int, error) { + if len(data) < 20 { + df.SetTruncated() + return 0, errors.New( + "Multicast Listener Report Message V2 layer less than 4 bytes for Multicast Address Record") + } + + m.RecordType = MLDv2MulticastAddressRecordType(data[0]) + m.AuxDataLen = data[1] + m.N = binary.BigEndian.Uint16(data[2:4]) + m.MulticastAddress = data[4:20] + + for i := uint16(0); i < m.N; i++ { + begin := 20 + (int(i) * 16) + end := begin + 16 + + if len(data) < end { + df.SetTruncated() + return begin, fmt.Errorf( + "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", end) + } + + m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) + } + + expectedLengthWithouAuxData := 20 + (int(m.N) * 16) + expectedTotalLength := (int(m.AuxDataLen) * 4) + expectedLengthWithouAuxData // *4 because AuxDataLen are 32bit words + if len(data) < expectedTotalLength { + return expectedLengthWithouAuxData, fmt.Errorf( + "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", + expectedLengthWithouAuxData) + } + + m.AuxiliaryData = data[expectedLengthWithouAuxData:expectedTotalLength] + + return expectedTotalLength, nil +} + +// String sums this layer up nicely formatted +func (m *MLDv2MulticastAddressRecord) String() string { + return fmt.Sprintf( + "RecordType: %d (%s), AuxDataLen: %d [32-bit words], N: %d, Multicast Address: %s, SourceAddresses: %s, Auxiliary Data: %#x", + m.RecordType, + m.RecordType.String(), + m.AuxDataLen, + m.N, + m.MulticastAddress.To16(), + m.SourceAddresses, + m.AuxiliaryData) +} + +// serializes a multicast address record +func (m *MLDv2MulticastAddressRecord) serializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if err := m.serializeAuxiliaryDataTo(b, opts); err != nil { + return err + } + + if err := m.serializeSourceAddressesTo(b, opts); err != nil { + return err + } + + buf, err := b.PrependBytes(20) + if err != nil { + return err + } + + buf[0] = uint8(m.RecordType) + buf[1] = m.AuxDataLen + binary.BigEndian.PutUint16(buf[2:4], m.N) + + ma16 := m.MulticastAddress.To16() + if ma16 == nil { + return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) + } + copy(buf[4:20], ma16) + + return nil +} + +// serializes the auxiliary data of a multicast address record +func (m *MLDv2MulticastAddressRecord) serializeAuxiliaryDataTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if remainder := len(m.AuxiliaryData) % 4; remainder != 0 { + zeroWord := []byte{0x0, 0x0, 0x0, 0x0} + m.AuxiliaryData = append(m.AuxiliaryData, zeroWord[:remainder]...) + } + + if opts.FixLengths { + auxDataLen := len(m.AuxiliaryData) / 4 + + if auxDataLen > math.MaxUint8 { + return fmt.Errorf("auxilary data is %d 32-bit words, but the maximum is 255 32-bit words", auxDataLen) + } + + m.AuxDataLen = uint8(auxDataLen) + } + + buf, err := b.PrependBytes(len(m.AuxiliaryData)) + if err != nil { + return err + } + + copy(buf, m.AuxiliaryData) + return nil +} + +// serializes the source addresses of a multicast address record preserving the order +func (m *MLDv2MulticastAddressRecord) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if opts.FixLengths { + numberOfSourceAddresses := len(m.SourceAddresses) + + if numberOfSourceAddresses > math.MaxUint16 { + return fmt.Errorf( + "%d source addresses added, but the maximum is 65535", + numberOfSourceAddresses) + } + + m.N = uint16(numberOfSourceAddresses) + } + + lastItemIdx := len(m.SourceAddresses) - 1 + for k := range m.SourceAddresses { + i := lastItemIdx - k // reverse order + + buf, err := b.PrependBytes(16) + if err != nil { + return err + } + + sa16 := m.SourceAddresses[i].To16() + if sa16 == nil { + return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) + } + copy(buf, sa16) + } + + return nil +} + +func decodeMLDv2MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { + m := &MLDv2MulticastListenerReportMessage{} + return decodingLayerDecoder(m, data, p) +} + +func decodeMLDv2MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { + m := &MLDv2MulticastListenerQueryMessage{} + return decodingLayerDecoder(m, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/modbustcp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/modbustcp.go new file mode 100644 index 0000000000..09d5e32613 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/modbustcp.go @@ -0,0 +1,155 @@ +// Copyright 2018, 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. +// +//****************************************************************************** + +package layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +//****************************************************************************** +// +// ModbusTCP Decoding Layer +// ------------------------------------------ +// This file provides a GoPacket decoding layer for ModbusTCP. +// +//****************************************************************************** + +const mbapRecordSizeInBytes int = 7 +const modbusPDUMinimumRecordSizeInBytes int = 2 +const modbusPDUMaximumRecordSizeInBytes int = 253 + +// ModbusProtocol type +type ModbusProtocol uint16 + +// ModbusProtocol known values. +const ( + ModbusProtocolModbus ModbusProtocol = 0 +) + +func (mp ModbusProtocol) String() string { + switch mp { + default: + return "Unknown" + case ModbusProtocolModbus: + return "Modbus" + } +} + +//****************************************************************************** + +// ModbusTCP Type +// -------- +// Type ModbusTCP implements the DecodingLayer interface. Each ModbusTCP object +// represents in a structured form the MODBUS Application Protocol header (MBAP) record present as the TCP +// payload in an ModbusTCP TCP packet. +type ModbusTCP struct { + BaseLayer // Stores the packet bytes and payload (Modbus PDU) bytes . + + TransactionIdentifier uint16 // Identification of a MODBUS Request/Response transaction + ProtocolIdentifier ModbusProtocol // It is used for intra-system multiplexing + Length uint16 // Number of following bytes (includes 1 byte for UnitIdentifier + Modbus data length + UnitIdentifier uint8 // Identification of a remote slave connected on a serial line or on other buses +} + +//****************************************************************************** + +// LayerType returns the layer type of the ModbusTCP object, which is LayerTypeModbusTCP. +func (d *ModbusTCP) LayerType() gopacket.LayerType { + return LayerTypeModbusTCP +} + +//****************************************************************************** + +// decodeModbusTCP analyses a byte slice and attempts to decode it as an ModbusTCP +// record of a TCP packet. +// +// If it succeeds, it loads p with information about the packet and returns nil. +// If it fails, it returns an error (non nil). +// +// This function is employed in layertypes.go to register the ModbusTCP layer. +func decodeModbusTCP(data []byte, p gopacket.PacketBuilder) error { + + // Attempt to decode the byte slice. + d := &ModbusTCP{} + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + // If the decoding worked, add the layer to the packet and set it + // as the application layer too, if there isn't already one. + p.AddLayer(d) + p.SetApplicationLayer(d) + + return p.NextDecoder(d.NextLayerType()) + +} + +//****************************************************************************** + +// DecodeFromBytes analyses a byte slice and attempts to decode it as an ModbusTCP +// record of a TCP packet. +// +// Upon succeeds, it loads the ModbusTCP object with information about the packet +// and returns nil. +// Upon failure, it returns an error (non nil). +func (d *ModbusTCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + + // If the data block is too short to be a MBAP record, then return an error. + if len(data) < mbapRecordSizeInBytes+modbusPDUMinimumRecordSizeInBytes { + df.SetTruncated() + return errors.New("ModbusTCP packet too short") + } + + if len(data) > mbapRecordSizeInBytes+modbusPDUMaximumRecordSizeInBytes { + df.SetTruncated() + return errors.New("ModbusTCP packet too long") + } + + // ModbusTCP type embeds type BaseLayer which contains two fields: + // Contents is supposed to contain the bytes of the data at this level (MPBA). + // Payload is supposed to contain the payload of this level (PDU). + d.BaseLayer = BaseLayer{Contents: data[:mbapRecordSizeInBytes], Payload: data[mbapRecordSizeInBytes:len(data)]} + + // Extract the fields from the block of bytes. + // The fields can just be copied in big endian order. + d.TransactionIdentifier = binary.BigEndian.Uint16(data[:2]) + d.ProtocolIdentifier = ModbusProtocol(binary.BigEndian.Uint16(data[2:4])) + d.Length = binary.BigEndian.Uint16(data[4:6]) + + // Length should have the size of the payload plus one byte (size of UnitIdentifier) + if d.Length != uint16(len(d.BaseLayer.Payload)+1) { + df.SetTruncated() + return errors.New("ModbusTCP packet with wrong field value (Length)") + } + d.UnitIdentifier = uint8(data[6]) + + return nil +} + +//****************************************************************************** + +// NextLayerType returns the layer type of the ModbusTCP payload, which is LayerTypePayload. +func (d *ModbusTCP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +//****************************************************************************** + +// Payload returns Modbus Protocol Data Unit (PDU) composed by Function Code and Data, it is carried within ModbusTCP packets +func (d *ModbusTCP) Payload() []byte { + return d.BaseLayer.Payload +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode +func (s *ModbusTCP) CanDecode() gopacket.LayerClass { + return LayerTypeModbusTCP +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mpls.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mpls.go new file mode 100644 index 0000000000..e8e3eefd83 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/mpls.go @@ -0,0 +1,90 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// MPLS is the MPLS packet header. +type MPLS struct { + BaseLayer + Label uint32 + TrafficClass uint8 + StackBottom bool + TTL uint8 +} + +// LayerType returns gopacket.LayerTypeMPLS. +func (m *MPLS) LayerType() gopacket.LayerType { return LayerTypeMPLS } + +// ProtocolGuessingDecoder attempts to guess the protocol of the bytes it's +// given, then decode the packet accordingly. Its algorithm for guessing is: +// +// If the packet starts with byte 0x45-0x4F: IPv4 +// If the packet starts with byte 0x60-0x6F: IPv6 +// Otherwise: Error +// +// See draft-hsmit-isis-aal5mux-00.txt for more detail on this approach. +type ProtocolGuessingDecoder struct{} + +func (ProtocolGuessingDecoder) Decode(data []byte, p gopacket.PacketBuilder) error { + switch data[0] { + // 0x40 | header_len, where header_len is at least 5. + case 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f: + return decodeIPv4(data, p) + // IPv6 can start with any byte whose first 4 bits are 0x6. + case 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f: + return decodeIPv6(data, p) + } + return errors.New("Unable to guess protocol of packet data") +} + +// MPLSPayloadDecoder is the decoder used to data encapsulated by each MPLS +// layer. MPLS contains no type information, so we have to explicitly decide +// which decoder to use. This is initially set to ProtocolGuessingDecoder, our +// simple attempt at guessing protocols based on the first few bytes of data +// available to us. However, if you know that in your environment MPLS always +// encapsulates a specific protocol, you may reset this. +var MPLSPayloadDecoder gopacket.Decoder = ProtocolGuessingDecoder{} + +func decodeMPLS(data []byte, p gopacket.PacketBuilder) error { + decoded := binary.BigEndian.Uint32(data[:4]) + mpls := &MPLS{ + Label: decoded >> 12, + TrafficClass: uint8(decoded>>9) & 0x7, + StackBottom: decoded&0x100 != 0, + TTL: uint8(decoded), + BaseLayer: BaseLayer{data[:4], data[4:]}, + } + p.AddLayer(mpls) + if mpls.StackBottom { + return p.NextDecoder(MPLSPayloadDecoder) + } + return p.NextDecoder(gopacket.DecodeFunc(decodeMPLS)) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (m *MPLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + encoded := m.Label << 12 + encoded |= uint32(m.TrafficClass) << 9 + encoded |= uint32(m.TTL) + if m.StackBottom { + encoded |= 0x100 + } + binary.BigEndian.PutUint32(bytes, encoded) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/multipathtcp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/multipathtcp.go new file mode 100644 index 0000000000..313cb86c90 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/multipathtcp.go @@ -0,0 +1,161 @@ +// 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 layers + +import ( + "fmt" + "net" +) + +// MPTCPSubtype represents an MPTCP subtype code. +type MPTCPSubtype uint8 + +// MPTCP Subtypes constonts from https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xml#mptcp-option-subtypes +const ( + MPTCPSubtypeMPCAPABLE = 0x0 + MPTCPSubtypeMPJOIN = 0x1 + MPTCPSubtypeDSS = 0x2 + MPTCPSubtypeADDADDR = 0x3 + MPTCPSubtypeREMOVEADDR = 0x4 + MPTCPSubtypeMPPRIO = 0x5 + MPTCPSubtypeMPFAIL = 0x6 + MPTCPSubtypeMPFASTCLOSE = 0x7 + MPTCPSubtypeMPTCPRST = 0x8 +) + +func (k MPTCPSubtype) String() string { + switch k { + case MPTCPSubtypeMPCAPABLE: + return "MP_CAPABLE" + case MPTCPSubtypeMPJOIN: + return "MP_JOIN" + case MPTCPSubtypeDSS: + return "DSS" + case MPTCPSubtypeADDADDR: + return "ADD_ADDR" + case MPTCPSubtypeREMOVEADDR: + return "REMOVE_ADDR" + case MPTCPSubtypeMPPRIO: + return "MP_PRIO" + case MPTCPSubtypeMPFAIL: + return "MP_FAIL" + case MPTCPSubtypeMPFASTCLOSE: + return "MP_FASTCLOSE" + case MPTCPSubtypeMPTCPRST: + return "MP_TCPRST" + default: + return fmt.Sprintf("Unknown(%d)", k) + } +} + +const ( + MptcpVersion0 = 0 + MptcpVersion1 = 1 +) + +const ( + OptionLenMpCapableSyn = 4 + OptionLenMpCapableSynAck = 12 + OptionLenMpCapableAck = 20 + OptionLenMpCapableAckData = 22 + OptionLenMpCapableAckDataCSum = 24 + OptionLenMpJoinSyn = 12 + OptionLenMpJoinSynAck = 16 + OptionLenMpJoinAck = 24 + OptionLenDssAck = 4 + OptionLenDssAck64 = 8 + OptionLenDssDSN = 4 + OptionLenDssDSN64 = 8 + OptionLenDssSSN = 4 + OptionLenDssDataLen = 2 + OptionLenDssCSum = 2 + OptionLenAddAddrv4 = 8 + OptionLenAddAddrv6 = 20 + OptionLenAddAddrPort = 2 + OptionLenAddAddrHmac = 8 + OptionLenRemAddr = 4 + OptionLenMpPrio = 3 + OptionLenMpPrioAddr = 4 + OptionLenMpFail = 12 + OptionLenMpFClose = 12 + OptionLenMpTcpRst = 4 +) + +// MPCapable contains the fields from the MP_CAPABLE MPTCP Option +type MPCapable struct { + BaseLayer + Version uint8 + A, B, C, D, E, F, G, H bool + SendKey []byte + ReceivKey []byte + DataLength uint16 + Checksum uint16 +} + +// MPJoin contains the fields from the MP_JOIN MPTCP Option +type MPJoin struct { + BaseLayer + Backup bool + AddrID uint8 + ReceivToken uint32 + SendRandNum uint32 + SendHMAC []byte +} + +// Dss contains the fields from the DSS MPTCP Option +type Dss struct { + BaseLayer + F, m, M, a, A bool + DataAck []byte + DSN []byte + SSN uint32 + DataLength uint16 + Checksum uint16 +} + +// AddAddr contains the fields from the ADD_ADDR MPTCP Option +type AddAddr struct { + BaseLayer + IPVer uint8 + E bool + AddrID uint8 + Address net.IP + Port uint16 + SendHMAC []byte +} + +// RemAddr contains the fields from the REMOVE_ADDR MPTCP Option +type RemAddr struct { + BaseLayer + AddrIDs []uint8 +} + +// MPPrio contains the fields from the MP_PRIO MPTCP Option +type MPPrio struct { + BaseLayer + Backup bool + AddrID uint8 +} + +// MPFail contains the fields from the MP_FAIL MPTCP Option +type MPFail struct { + BaseLayer + DSN uint64 +} + +// MPFClose contains the fields from the MP_FASTCLOSE MPTCP Option +type MPFClose struct { + BaseLayer + ReceivKey []byte +} + +// MPTcpRst contains the fields from the MP_TCPRST MPTCP Option +type MPTcpRst struct { + BaseLayer + U, V, W, T bool + Reason uint8 +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ndp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ndp.go new file mode 100644 index 0000000000..e7593f4b1e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ndp.go @@ -0,0 +1,612 @@ +// 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. + +// Enum types courtesy of... +// http://anonsvn.wireshark.org/wireshark/trunk/epan/dissectors/packet-ndp.c + +package layers + +import ( + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +type NDPChassisType uint8 + +// Nortel Chassis Types +const ( + NDPChassisother NDPChassisType = 1 + NDPChassis3000 NDPChassisType = 2 + NDPChassis3030 NDPChassisType = 3 + NDPChassis2310 NDPChassisType = 4 + NDPChassis2810 NDPChassisType = 5 + NDPChassis2912 NDPChassisType = 6 + NDPChassis2914 NDPChassisType = 7 + NDPChassis271x NDPChassisType = 8 + NDPChassis2813 NDPChassisType = 9 + NDPChassis2814 NDPChassisType = 10 + NDPChassis2915 NDPChassisType = 11 + NDPChassis5000 NDPChassisType = 12 + NDPChassis2813SA NDPChassisType = 13 + NDPChassis2814SA NDPChassisType = 14 + NDPChassis810M NDPChassisType = 15 + NDPChassisEthercell NDPChassisType = 16 + NDPChassis5005 NDPChassisType = 17 + NDPChassisAlcatelEWC NDPChassisType = 18 + NDPChassis2715SA NDPChassisType = 20 + NDPChassis2486 NDPChassisType = 21 + NDPChassis28000series NDPChassisType = 22 + NDPChassis23000series NDPChassisType = 23 + NDPChassis5DN00xseries NDPChassisType = 24 + NDPChassisBayStackEthernet NDPChassisType = 25 + NDPChassis23100series NDPChassisType = 26 + NDPChassis100BaseTHub NDPChassisType = 27 + NDPChassis3000FastEthernet NDPChassisType = 28 + NDPChassisOrionSwitch NDPChassisType = 29 + NDPChassisDDS NDPChassisType = 31 + NDPChassisCentillion6slot NDPChassisType = 32 + NDPChassisCentillion12slot NDPChassisType = 33 + NDPChassisCentillion1slot NDPChassisType = 34 + NDPChassisBayStack301 NDPChassisType = 35 + NDPChassisBayStackTokenRingHub NDPChassisType = 36 + NDPChassisFVCMultimediaSwitch NDPChassisType = 37 + NDPChassisSwitchNode NDPChassisType = 38 + NDPChassisBayStack302Switch NDPChassisType = 39 + NDPChassisBayStack350Switch NDPChassisType = 40 + NDPChassisBayStack150EthernetHub NDPChassisType = 41 + NDPChassisCentillion50NSwitch NDPChassisType = 42 + NDPChassisCentillion50TSwitch NDPChassisType = 43 + NDPChassisBayStack303304Switches NDPChassisType = 44 + NDPChassisBayStack200EthernetHub NDPChassisType = 45 + NDPChassisBayStack25010100EthernetHub NDPChassisType = 46 + NDPChassisBayStack450101001000Switches NDPChassisType = 48 + NDPChassisBayStack41010100Switches NDPChassisType = 49 + NDPChassisPassport1200L3Switch NDPChassisType = 50 + NDPChassisPassport1250L3Switch NDPChassisType = 51 + NDPChassisPassport1100L3Switch NDPChassisType = 52 + NDPChassisPassport1150L3Switch NDPChassisType = 53 + NDPChassisPassport1050L3Switch NDPChassisType = 54 + NDPChassisPassport1051L3Switch NDPChassisType = 55 + NDPChassisPassport8610L3Switch NDPChassisType = 56 + NDPChassisPassport8606L3Switch NDPChassisType = 57 + NDPChassisPassport8010 NDPChassisType = 58 + NDPChassisPassport8006 NDPChassisType = 59 + NDPChassisBayStack670wirelessaccesspoint NDPChassisType = 60 + NDPChassisPassport740 NDPChassisType = 61 + NDPChassisPassport750 NDPChassisType = 62 + NDPChassisPassport790 NDPChassisType = 63 + NDPChassisBusinessPolicySwitch200010100Switches NDPChassisType = 64 + NDPChassisPassport8110L2Switch NDPChassisType = 65 + NDPChassisPassport8106L2Switch NDPChassisType = 66 + NDPChassisBayStack3580GigSwitch NDPChassisType = 67 + NDPChassisBayStack10PowerSupplyUnit NDPChassisType = 68 + NDPChassisBayStack42010100Switch NDPChassisType = 69 + NDPChassisOPTeraMetro1200EthernetServiceModule NDPChassisType = 70 + NDPChassisOPTera8010co NDPChassisType = 71 + NDPChassisOPTera8610coL3Switch NDPChassisType = 72 + NDPChassisOPTera8110coL2Switch NDPChassisType = 73 + NDPChassisOPTera8003 NDPChassisType = 74 + NDPChassisOPTera8603L3Switch NDPChassisType = 75 + NDPChassisOPTera8103L2Switch NDPChassisType = 76 + NDPChassisBayStack380101001000Switch NDPChassisType = 77 + NDPChassisEthernetSwitch47048T NDPChassisType = 78 + NDPChassisOPTeraMetro1450EthernetServiceModule NDPChassisType = 79 + NDPChassisOPTeraMetro1400EthernetServiceModule NDPChassisType = 80 + NDPChassisAlteonSwitchFamily NDPChassisType = 81 + NDPChassisEthernetSwitch46024TPWR NDPChassisType = 82 + NDPChassisOPTeraMetro8010OPML2Switch NDPChassisType = 83 + NDPChassisOPTeraMetro8010coOPML2Switch NDPChassisType = 84 + NDPChassisOPTeraMetro8006OPML2Switch NDPChassisType = 85 + NDPChassisOPTeraMetro8003OPML2Switch NDPChassisType = 86 + NDPChassisAlteon180e NDPChassisType = 87 + NDPChassisAlteonAD3 NDPChassisType = 88 + NDPChassisAlteon184 NDPChassisType = 89 + NDPChassisAlteonAD4 NDPChassisType = 90 + NDPChassisPassport1424L3Switch NDPChassisType = 91 + NDPChassisPassport1648L3Switch NDPChassisType = 92 + NDPChassisPassport1612L3Switch NDPChassisType = 93 + NDPChassisPassport1624L3Switch NDPChassisType = 94 + NDPChassisBayStack38024FFiber1000Switch NDPChassisType = 95 + NDPChassisEthernetRoutingSwitch551024T NDPChassisType = 96 + NDPChassisEthernetRoutingSwitch551048T NDPChassisType = 97 + NDPChassisEthernetSwitch47024T NDPChassisType = 98 + NDPChassisNortelNetworksWirelessLANAccessPoint2220 NDPChassisType = 99 + NDPChassisPassportRBS2402L3Switch NDPChassisType = 100 + NDPChassisAlteonApplicationSwitch2424 NDPChassisType = 101 + NDPChassisAlteonApplicationSwitch2224 NDPChassisType = 102 + NDPChassisAlteonApplicationSwitch2208 NDPChassisType = 103 + NDPChassisAlteonApplicationSwitch2216 NDPChassisType = 104 + NDPChassisAlteonApplicationSwitch3408 NDPChassisType = 105 + NDPChassisAlteonApplicationSwitch3416 NDPChassisType = 106 + NDPChassisNortelNetworksWirelessLANSecuritySwitch2250 NDPChassisType = 107 + NDPChassisEthernetSwitch42548T NDPChassisType = 108 + NDPChassisEthernetSwitch42524T NDPChassisType = 109 + NDPChassisNortelNetworksWirelessLANAccessPoint2221 NDPChassisType = 110 + NDPChassisNortelMetroEthernetServiceUnit24TSPFswitch NDPChassisType = 111 + NDPChassisNortelMetroEthernetServiceUnit24TLXDCswitch NDPChassisType = 112 + NDPChassisPassport830010slotchassis NDPChassisType = 113 + NDPChassisPassport83006slotchassis NDPChassisType = 114 + NDPChassisEthernetRoutingSwitch552024TPWR NDPChassisType = 115 + NDPChassisEthernetRoutingSwitch552048TPWR NDPChassisType = 116 + NDPChassisNortelNetworksVPNGateway3050 NDPChassisType = 117 + NDPChassisAlteonSSL31010100 NDPChassisType = 118 + NDPChassisAlteonSSL31010100Fiber NDPChassisType = 119 + NDPChassisAlteonSSL31010100FIPS NDPChassisType = 120 + NDPChassisAlteonSSL410101001000 NDPChassisType = 121 + NDPChassisAlteonSSL410101001000Fiber NDPChassisType = 122 + NDPChassisAlteonApplicationSwitch2424SSL NDPChassisType = 123 + NDPChassisEthernetSwitch32524T NDPChassisType = 124 + NDPChassisEthernetSwitch32524G NDPChassisType = 125 + NDPChassisNortelNetworksWirelessLANAccessPoint2225 NDPChassisType = 126 + NDPChassisNortelNetworksWirelessLANSecuritySwitch2270 NDPChassisType = 127 + NDPChassis24portEthernetSwitch47024TPWR NDPChassisType = 128 + NDPChassis48portEthernetSwitch47048TPWR NDPChassisType = 129 + NDPChassisEthernetRoutingSwitch553024TFD NDPChassisType = 130 + NDPChassisEthernetSwitch351024T NDPChassisType = 131 + NDPChassisNortelMetroEthernetServiceUnit12GACL3Switch NDPChassisType = 132 + NDPChassisNortelMetroEthernetServiceUnit12GDCL3Switch NDPChassisType = 133 + NDPChassisNortelSecureAccessSwitch NDPChassisType = 134 + NDPChassisNortelNetworksVPNGateway3070 NDPChassisType = 135 + NDPChassisOPTeraMetro3500 NDPChassisType = 136 + NDPChassisSMBBES101024T NDPChassisType = 137 + NDPChassisSMBBES101048T NDPChassisType = 138 + NDPChassisSMBBES102024TPWR NDPChassisType = 139 + NDPChassisSMBBES102048TPWR NDPChassisType = 140 + NDPChassisSMBBES201024T NDPChassisType = 141 + NDPChassisSMBBES201048T NDPChassisType = 142 + NDPChassisSMBBES202024TPWR NDPChassisType = 143 + NDPChassisSMBBES202048TPWR NDPChassisType = 144 + NDPChassisSMBBES11024T NDPChassisType = 145 + NDPChassisSMBBES11048T NDPChassisType = 146 + NDPChassisSMBBES12024TPWR NDPChassisType = 147 + NDPChassisSMBBES12048TPWR NDPChassisType = 148 + NDPChassisSMBBES21024T NDPChassisType = 149 + NDPChassisSMBBES21048T NDPChassisType = 150 + NDPChassisSMBBES22024TPWR NDPChassisType = 151 + NDPChassisSMBBES22048TPWR NDPChassisType = 152 + NDPChassisOME6500 NDPChassisType = 153 + NDPChassisEthernetRoutingSwitch4548GT NDPChassisType = 154 + NDPChassisEthernetRoutingSwitch4548GTPWR NDPChassisType = 155 + NDPChassisEthernetRoutingSwitch4550T NDPChassisType = 156 + NDPChassisEthernetRoutingSwitch4550TPWR NDPChassisType = 157 + NDPChassisEthernetRoutingSwitch4526FX NDPChassisType = 158 + NDPChassisEthernetRoutingSwitch250026T NDPChassisType = 159 + NDPChassisEthernetRoutingSwitch250026TPWR NDPChassisType = 160 + NDPChassisEthernetRoutingSwitch250050T NDPChassisType = 161 + NDPChassisEthernetRoutingSwitch250050TPWR NDPChassisType = 162 +) + +type NDPBackplaneType uint8 + +// Nortel Backplane Types +const ( + NDPBackplaneOther NDPBackplaneType = 1 + NDPBackplaneEthernet NDPBackplaneType = 2 + NDPBackplaneEthernetTokenring NDPBackplaneType = 3 + NDPBackplaneEthernetFDDI NDPBackplaneType = 4 + NDPBackplaneEthernetTokenringFDDI NDPBackplaneType = 5 + NDPBackplaneEthernetTokenringRedundantPower NDPBackplaneType = 6 + NDPBackplaneEthernetTokenringFDDIRedundantPower NDPBackplaneType = 7 + NDPBackplaneTokenRing NDPBackplaneType = 8 + NDPBackplaneEthernetTokenringFastEthernet NDPBackplaneType = 9 + NDPBackplaneEthernetFastEthernet NDPBackplaneType = 10 + NDPBackplaneEthernetTokenringFastEthernetRedundantPower NDPBackplaneType = 11 + NDPBackplaneEthernetFastEthernetGigabitEthernet NDPBackplaneType = 12 +) + +type NDPState uint8 + +// Device State +const ( + NDPStateTopology NDPState = 1 + NDPStateHeartbeat NDPState = 2 + NDPStateNew NDPState = 3 +) + +// NortelDiscovery is a packet layer containing the Nortel Discovery Protocol. +type NortelDiscovery struct { + BaseLayer + IPAddress net.IP + SegmentID []byte + Chassis NDPChassisType + Backplane NDPBackplaneType + State NDPState + NumLinks uint8 +} + +// LayerType returns gopacket.LayerTypeNortelDiscovery. +func (c *NortelDiscovery) LayerType() gopacket.LayerType { + return LayerTypeNortelDiscovery +} + +func decodeNortelDiscovery(data []byte, p gopacket.PacketBuilder) error { + c := &NortelDiscovery{} + if len(data) < 11 { + return fmt.Errorf("Invalid NortelDiscovery packet length %d", len(data)) + } + c.IPAddress = data[0:4] + c.SegmentID = data[4:7] + c.Chassis = NDPChassisType(data[7]) + c.Backplane = NDPBackplaneType(data[8]) + c.State = NDPState(data[9]) + c.NumLinks = uint8(data[10]) + p.AddLayer(c) + return nil +} + +func (t NDPChassisType) String() (s string) { + switch t { + case NDPChassisother: + s = "other" + case NDPChassis3000: + s = "3000" + case NDPChassis3030: + s = "3030" + case NDPChassis2310: + s = "2310" + case NDPChassis2810: + s = "2810" + case NDPChassis2912: + s = "2912" + case NDPChassis2914: + s = "2914" + case NDPChassis271x: + s = "271x" + case NDPChassis2813: + s = "2813" + case NDPChassis2814: + s = "2814" + case NDPChassis2915: + s = "2915" + case NDPChassis5000: + s = "5000" + case NDPChassis2813SA: + s = "2813SA" + case NDPChassis2814SA: + s = "2814SA" + case NDPChassis810M: + s = "810M" + case NDPChassisEthercell: + s = "Ethercell" + case NDPChassis5005: + s = "5005" + case NDPChassisAlcatelEWC: + s = "Alcatel Ethernet workgroup conc." + case NDPChassis2715SA: + s = "2715SA" + case NDPChassis2486: + s = "2486" + case NDPChassis28000series: + s = "28000 series" + case NDPChassis23000series: + s = "23000 series" + case NDPChassis5DN00xseries: + s = "5DN00x series" + case NDPChassisBayStackEthernet: + s = "BayStack Ethernet" + case NDPChassis23100series: + s = "23100 series" + case NDPChassis100BaseTHub: + s = "100Base-T Hub" + case NDPChassis3000FastEthernet: + s = "3000 Fast Ethernet" + case NDPChassisOrionSwitch: + s = "Orion switch" + case NDPChassisDDS: + s = "DDS" + case NDPChassisCentillion6slot: + s = "Centillion (6 slot)" + case NDPChassisCentillion12slot: + s = "Centillion (12 slot)" + case NDPChassisCentillion1slot: + s = "Centillion (1 slot)" + case NDPChassisBayStack301: + s = "BayStack 301" + case NDPChassisBayStackTokenRingHub: + s = "BayStack TokenRing Hub" + case NDPChassisFVCMultimediaSwitch: + s = "FVC Multimedia Switch" + case NDPChassisSwitchNode: + s = "Switch Node" + case NDPChassisBayStack302Switch: + s = "BayStack 302 Switch" + case NDPChassisBayStack350Switch: + s = "BayStack 350 Switch" + case NDPChassisBayStack150EthernetHub: + s = "BayStack 150 Ethernet Hub" + case NDPChassisCentillion50NSwitch: + s = "Centillion 50N switch" + case NDPChassisCentillion50TSwitch: + s = "Centillion 50T switch" + case NDPChassisBayStack303304Switches: + s = "BayStack 303 and 304 Switches" + case NDPChassisBayStack200EthernetHub: + s = "BayStack 200 Ethernet Hub" + case NDPChassisBayStack25010100EthernetHub: + s = "BayStack 250 10/100 Ethernet Hub" + case NDPChassisBayStack450101001000Switches: + s = "BayStack 450 10/100/1000 Switches" + case NDPChassisBayStack41010100Switches: + s = "BayStack 410 10/100 Switches" + case NDPChassisPassport1200L3Switch: + s = "Passport 1200 L3 Switch" + case NDPChassisPassport1250L3Switch: + s = "Passport 1250 L3 Switch" + case NDPChassisPassport1100L3Switch: + s = "Passport 1100 L3 Switch" + case NDPChassisPassport1150L3Switch: + s = "Passport 1150 L3 Switch" + case NDPChassisPassport1050L3Switch: + s = "Passport 1050 L3 Switch" + case NDPChassisPassport1051L3Switch: + s = "Passport 1051 L3 Switch" + case NDPChassisPassport8610L3Switch: + s = "Passport 8610 L3 Switch" + case NDPChassisPassport8606L3Switch: + s = "Passport 8606 L3 Switch" + case NDPChassisPassport8010: + s = "Passport 8010" + case NDPChassisPassport8006: + s = "Passport 8006" + case NDPChassisBayStack670wirelessaccesspoint: + s = "BayStack 670 wireless access point" + case NDPChassisPassport740: + s = "Passport 740" + case NDPChassisPassport750: + s = "Passport 750" + case NDPChassisPassport790: + s = "Passport 790" + case NDPChassisBusinessPolicySwitch200010100Switches: + s = "Business Policy Switch 2000 10/100 Switches" + case NDPChassisPassport8110L2Switch: + s = "Passport 8110 L2 Switch" + case NDPChassisPassport8106L2Switch: + s = "Passport 8106 L2 Switch" + case NDPChassisBayStack3580GigSwitch: + s = "BayStack 3580 Gig Switch" + case NDPChassisBayStack10PowerSupplyUnit: + s = "BayStack 10 Power Supply Unit" + case NDPChassisBayStack42010100Switch: + s = "BayStack 420 10/100 Switch" + case NDPChassisOPTeraMetro1200EthernetServiceModule: + s = "OPTera Metro 1200 Ethernet Service Module" + case NDPChassisOPTera8010co: + s = "OPTera 8010co" + case NDPChassisOPTera8610coL3Switch: + s = "OPTera 8610co L3 switch" + case NDPChassisOPTera8110coL2Switch: + s = "OPTera 8110co L2 switch" + case NDPChassisOPTera8003: + s = "OPTera 8003" + case NDPChassisOPTera8603L3Switch: + s = "OPTera 8603 L3 switch" + case NDPChassisOPTera8103L2Switch: + s = "OPTera 8103 L2 switch" + case NDPChassisBayStack380101001000Switch: + s = "BayStack 380 10/100/1000 Switch" + case NDPChassisEthernetSwitch47048T: + s = "Ethernet Switch 470-48T" + case NDPChassisOPTeraMetro1450EthernetServiceModule: + s = "OPTera Metro 1450 Ethernet Service Module" + case NDPChassisOPTeraMetro1400EthernetServiceModule: + s = "OPTera Metro 1400 Ethernet Service Module" + case NDPChassisAlteonSwitchFamily: + s = "Alteon Switch Family" + case NDPChassisEthernetSwitch46024TPWR: + s = "Ethernet Switch 460-24T-PWR" + case NDPChassisOPTeraMetro8010OPML2Switch: + s = "OPTera Metro 8010 OPM L2 Switch" + case NDPChassisOPTeraMetro8010coOPML2Switch: + s = "OPTera Metro 8010co OPM L2 Switch" + case NDPChassisOPTeraMetro8006OPML2Switch: + s = "OPTera Metro 8006 OPM L2 Switch" + case NDPChassisOPTeraMetro8003OPML2Switch: + s = "OPTera Metro 8003 OPM L2 Switch" + case NDPChassisAlteon180e: + s = "Alteon 180e" + case NDPChassisAlteonAD3: + s = "Alteon AD3" + case NDPChassisAlteon184: + s = "Alteon 184" + case NDPChassisAlteonAD4: + s = "Alteon AD4" + case NDPChassisPassport1424L3Switch: + s = "Passport 1424 L3 switch" + case NDPChassisPassport1648L3Switch: + s = "Passport 1648 L3 switch" + case NDPChassisPassport1612L3Switch: + s = "Passport 1612 L3 switch" + case NDPChassisPassport1624L3Switch: + s = "Passport 1624 L3 switch" + case NDPChassisBayStack38024FFiber1000Switch: + s = "BayStack 380-24F Fiber 1000 Switch" + case NDPChassisEthernetRoutingSwitch551024T: + s = "Ethernet Routing Switch 5510-24T" + case NDPChassisEthernetRoutingSwitch551048T: + s = "Ethernet Routing Switch 5510-48T" + case NDPChassisEthernetSwitch47024T: + s = "Ethernet Switch 470-24T" + case NDPChassisNortelNetworksWirelessLANAccessPoint2220: + s = "Nortel Networks Wireless LAN Access Point 2220" + case NDPChassisPassportRBS2402L3Switch: + s = "Passport RBS 2402 L3 switch" + case NDPChassisAlteonApplicationSwitch2424: + s = "Alteon Application Switch 2424" + case NDPChassisAlteonApplicationSwitch2224: + s = "Alteon Application Switch 2224" + case NDPChassisAlteonApplicationSwitch2208: + s = "Alteon Application Switch 2208" + case NDPChassisAlteonApplicationSwitch2216: + s = "Alteon Application Switch 2216" + case NDPChassisAlteonApplicationSwitch3408: + s = "Alteon Application Switch 3408" + case NDPChassisAlteonApplicationSwitch3416: + s = "Alteon Application Switch 3416" + case NDPChassisNortelNetworksWirelessLANSecuritySwitch2250: + s = "Nortel Networks Wireless LAN SecuritySwitch 2250" + case NDPChassisEthernetSwitch42548T: + s = "Ethernet Switch 425-48T" + case NDPChassisEthernetSwitch42524T: + s = "Ethernet Switch 425-24T" + case NDPChassisNortelNetworksWirelessLANAccessPoint2221: + s = "Nortel Networks Wireless LAN Access Point 2221" + case NDPChassisNortelMetroEthernetServiceUnit24TSPFswitch: + s = "Nortel Metro Ethernet Service Unit 24-T SPF switch" + case NDPChassisNortelMetroEthernetServiceUnit24TLXDCswitch: + s = " Nortel Metro Ethernet Service Unit 24-T LX DC switch" + case NDPChassisPassport830010slotchassis: + s = "Passport 8300 10-slot chassis" + case NDPChassisPassport83006slotchassis: + s = "Passport 8300 6-slot chassis" + case NDPChassisEthernetRoutingSwitch552024TPWR: + s = "Ethernet Routing Switch 5520-24T-PWR" + case NDPChassisEthernetRoutingSwitch552048TPWR: + s = "Ethernet Routing Switch 5520-48T-PWR" + case NDPChassisNortelNetworksVPNGateway3050: + s = "Nortel Networks VPN Gateway 3050" + case NDPChassisAlteonSSL31010100: + s = "Alteon SSL 310 10/100" + case NDPChassisAlteonSSL31010100Fiber: + s = "Alteon SSL 310 10/100 Fiber" + case NDPChassisAlteonSSL31010100FIPS: + s = "Alteon SSL 310 10/100 FIPS" + case NDPChassisAlteonSSL410101001000: + s = "Alteon SSL 410 10/100/1000" + case NDPChassisAlteonSSL410101001000Fiber: + s = "Alteon SSL 410 10/100/1000 Fiber" + case NDPChassisAlteonApplicationSwitch2424SSL: + s = "Alteon Application Switch 2424-SSL" + case NDPChassisEthernetSwitch32524T: + s = "Ethernet Switch 325-24T" + case NDPChassisEthernetSwitch32524G: + s = "Ethernet Switch 325-24G" + case NDPChassisNortelNetworksWirelessLANAccessPoint2225: + s = "Nortel Networks Wireless LAN Access Point 2225" + case NDPChassisNortelNetworksWirelessLANSecuritySwitch2270: + s = "Nortel Networks Wireless LAN SecuritySwitch 2270" + case NDPChassis24portEthernetSwitch47024TPWR: + s = "24-port Ethernet Switch 470-24T-PWR" + case NDPChassis48portEthernetSwitch47048TPWR: + s = "48-port Ethernet Switch 470-48T-PWR" + case NDPChassisEthernetRoutingSwitch553024TFD: + s = "Ethernet Routing Switch 5530-24TFD" + case NDPChassisEthernetSwitch351024T: + s = "Ethernet Switch 3510-24T" + case NDPChassisNortelMetroEthernetServiceUnit12GACL3Switch: + s = "Nortel Metro Ethernet Service Unit 12G AC L3 switch" + case NDPChassisNortelMetroEthernetServiceUnit12GDCL3Switch: + s = "Nortel Metro Ethernet Service Unit 12G DC L3 switch" + case NDPChassisNortelSecureAccessSwitch: + s = "Nortel Secure Access Switch" + case NDPChassisNortelNetworksVPNGateway3070: + s = "Nortel Networks VPN Gateway 3070" + case NDPChassisOPTeraMetro3500: + s = "OPTera Metro 3500" + case NDPChassisSMBBES101024T: + s = "SMB BES 1010 24T" + case NDPChassisSMBBES101048T: + s = "SMB BES 1010 48T" + case NDPChassisSMBBES102024TPWR: + s = "SMB BES 1020 24T PWR" + case NDPChassisSMBBES102048TPWR: + s = "SMB BES 1020 48T PWR" + case NDPChassisSMBBES201024T: + s = "SMB BES 2010 24T" + case NDPChassisSMBBES201048T: + s = "SMB BES 2010 48T" + case NDPChassisSMBBES202024TPWR: + s = "SMB BES 2020 24T PWR" + case NDPChassisSMBBES202048TPWR: + s = "SMB BES 2020 48T PWR" + case NDPChassisSMBBES11024T: + s = "SMB BES 110 24T" + case NDPChassisSMBBES11048T: + s = "SMB BES 110 48T" + case NDPChassisSMBBES12024TPWR: + s = "SMB BES 120 24T PWR" + case NDPChassisSMBBES12048TPWR: + s = "SMB BES 120 48T PWR" + case NDPChassisSMBBES21024T: + s = "SMB BES 210 24T" + case NDPChassisSMBBES21048T: + s = "SMB BES 210 48T" + case NDPChassisSMBBES22024TPWR: + s = "SMB BES 220 24T PWR" + case NDPChassisSMBBES22048TPWR: + s = "SMB BES 220 48T PWR" + case NDPChassisOME6500: + s = "OME 6500" + case NDPChassisEthernetRoutingSwitch4548GT: + s = "Ethernet Routing Switch 4548GT" + case NDPChassisEthernetRoutingSwitch4548GTPWR: + s = "Ethernet Routing Switch 4548GT-PWR" + case NDPChassisEthernetRoutingSwitch4550T: + s = "Ethernet Routing Switch 4550T" + case NDPChassisEthernetRoutingSwitch4550TPWR: + s = "Ethernet Routing Switch 4550T-PWR" + case NDPChassisEthernetRoutingSwitch4526FX: + s = "Ethernet Routing Switch 4526FX" + case NDPChassisEthernetRoutingSwitch250026T: + s = "Ethernet Routing Switch 2500-26T" + case NDPChassisEthernetRoutingSwitch250026TPWR: + s = "Ethernet Routing Switch 2500-26T-PWR" + case NDPChassisEthernetRoutingSwitch250050T: + s = "Ethernet Routing Switch 2500-50T" + case NDPChassisEthernetRoutingSwitch250050TPWR: + s = "Ethernet Routing Switch 2500-50T-PWR" + default: + s = "Unknown" + } + return +} + +func (t NDPBackplaneType) String() (s string) { + switch t { + case NDPBackplaneOther: + s = "Other" + case NDPBackplaneEthernet: + s = "Ethernet" + case NDPBackplaneEthernetTokenring: + s = "Ethernet and Tokenring" + case NDPBackplaneEthernetFDDI: + s = "Ethernet and FDDI" + case NDPBackplaneEthernetTokenringFDDI: + s = "Ethernet, Tokenring and FDDI" + case NDPBackplaneEthernetTokenringRedundantPower: + s = "Ethernet and Tokenring with redundant power" + case NDPBackplaneEthernetTokenringFDDIRedundantPower: + s = "Ethernet, Tokenring, FDDI with redundant power" + case NDPBackplaneTokenRing: + s = "Token Ring" + case NDPBackplaneEthernetTokenringFastEthernet: + s = "Ethernet, Tokenring and Fast Ethernet" + case NDPBackplaneEthernetFastEthernet: + s = "Ethernet and Fast Ethernet" + case NDPBackplaneEthernetTokenringFastEthernetRedundantPower: + s = "Ethernet, Tokenring, Fast Ethernet with redundant power" + case NDPBackplaneEthernetFastEthernetGigabitEthernet: + s = "Ethernet, Fast Ethernet and Gigabit Ethernet" + default: + s = "Unknown" + } + return +} + +func (t NDPState) String() (s string) { + switch t { + case NDPStateTopology: + s = "Topology Change" + case NDPStateHeartbeat: + s = "Heartbeat" + case NDPStateNew: + s = "New" + default: + s = "Unknown" + } + return +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ntp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ntp.go new file mode 100644 index 0000000000..26bb083a1b --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ntp.go @@ -0,0 +1,415 @@ +// Copyright 2016 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +//****************************************************************************** +// +// Network Time Protocol (NTP) Decoding Layer +// ------------------------------------------ +// This file provides a GoPacket decoding layer for NTP. +// +//****************************************************************************** +// +// About The Network Time Protocol (NTP) +// ------------------------------------- +// NTP is a protocol that enables computers on the internet to set their +// clocks to the correct time (or to a time that is acceptably close to the +// correct time). NTP runs on top of UDP. +// +// There have been a series of versions of the NTP protocol. The latest +// version is V4 and is specified in RFC 5905: +// http://www.ietf.org/rfc/rfc5905.txt +// +//****************************************************************************** +// +// References +// ---------- +// +// Wikipedia's NTP entry: +// https://en.wikipedia.org/wiki/Network_Time_Protocol +// This is the best place to get an overview of NTP. +// +// Network Time Protocol Home Website: +// http://www.ntp.org/ +// This appears to be the official website of NTP. +// +// List of current NTP Protocol RFCs: +// http://www.ntp.org/rfc.html +// +// RFC 958: "Network Time Protocol (NTP)" (1985) +// https://tools.ietf.org/html/rfc958 +// This is the original NTP specification. +// +// RFC 1305: "Network Time Protocol (Version 3) Specification, Implementation and Analysis" (1992) +// https://tools.ietf.org/html/rfc1305 +// The protocol was updated in 1992 yielding NTP V3. +// +// RFC 5905: "Network Time Protocol Version 4: Protocol and Algorithms Specification" (2010) +// https://www.ietf.org/rfc/rfc5905.txt +// The protocol was updated in 2010 yielding NTP V4. +// V4 is backwards compatible with all previous versions of NTP. +// +// RFC 5906: "Network Time Protocol Version 4: Autokey Specification" +// https://tools.ietf.org/html/rfc5906 +// This document addresses the security of the NTP protocol +// and is probably not relevant to this package. +// +// RFC 5907: "Definitions of Managed Objects for Network Time Protocol Version 4 (NTPv4)" +// https://tools.ietf.org/html/rfc5907 +// This document addresses the management of NTP servers and +// is probably not relevant to this package. +// +// RFC 5908: "Network Time Protocol (NTP) Server Option for DHCPv6" +// https://tools.ietf.org/html/rfc5908 +// This document addresses the use of NTP in DHCPv6 and is +// probably not relevant to this package. +// +// "Let's make a NTP Client in C" +// https://lettier.github.io/posts/2016-04-26-lets-make-a-ntp-client-in-c.html +// This web page contains useful information about the details of NTP, +// including an NTP record struture in C, and C code. +// +// "NTP Packet Header (NTP Reference Implementation) (Computer Network Time Synchronization)" +// http://what-when-how.com/computer-network-time-synchronization/ +// ntp-packet-header-ntp-reference-implementation-computer-network-time-synchronization/ +// This web page contains useful information on the details of NTP. +// +// "Technical information - NTP Data Packet" +// https://www.meinbergglobal.com/english/info/ntp-packet.htm +// This page has a helpful diagram of an NTP V4 packet. +// +//****************************************************************************** +// +// Obsolete References +// ------------------- +// +// RFC 1119: "RFC-1119 "Network Time Protocol (Version 2) Specification and Implementation" (1989) +// https://tools.ietf.org/html/rfc1119 +// Version 2 was drafted in 1989. +// It is unclear whether V2 was ever implememented or whether the +// ideas ended up in V3 (which was implemented in 1992). +// +// RFC 1361: "Simple Network Time Protocol (SNTP)" +// https://tools.ietf.org/html/rfc1361 +// This document is obsoleted by RFC 1769 and is included only for completeness. +// +// RFC 1769: "Simple Network Time Protocol (SNTP)" +// https://tools.ietf.org/html/rfc1769 +// This document is obsoleted by RFC 2030 and RFC 4330 and is included only for completeness. +// +// RFC 2030: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI" +// https://tools.ietf.org/html/rfc2030 +// This document is obsoleted by RFC 4330 and is included only for completeness. +// +// RFC 4330: "Simple Network Time Protocol (SNTP) Version 4 for IPv4, IPv6 and OSI" +// https://tools.ietf.org/html/rfc4330 +// This document is obsoleted by RFC 5905 and is included only for completeness. +// +//****************************************************************************** +// +// Endian And Bit Numbering Issues +// ------------------------------- +// +// Endian and bit numbering issues can be confusing. Here is some +// clarification: +// +// ENDIAN: Values are sent big endian. +// https://en.wikipedia.org/wiki/Endianness +// +// BIT NUMBERING: Bits are numbered 0 upwards from the most significant +// bit to the least significant bit. This means that if there is a 32-bit +// value, the most significant bit is called bit 0 and the least +// significant bit is called bit 31. +// +// See RFC 791 Appendix B for more discussion. +// +//****************************************************************************** +// +// NTP V3 and V4 Packet Format +// --------------------------- +// NTP packets are UDP packets whose payload contains an NTP record. +// +// The NTP RFC defines the format of the NTP record. +// +// There have been four versions of the protocol: +// +// V1 in 1985 +// V2 in 1989 +// V3 in 1992 +// V4 in 2010 +// +// It is clear that V1 and V2 are obsolete, and there is no need to +// cater for these formats. +// +// V3 and V4 essentially use the same format, with V4 adding some optional +// fields on the end. So this package supports the V3 and V4 formats. +// +// The current version of NTP (NTP V4)'s RFC (V4 - RFC 5905) contains +// the following diagram for the NTP record format: + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |LI | VN |Mode | Stratum | Poll | Precision | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Root Delay | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Root Dispersion | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Reference ID | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + Reference Timestamp (64) + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + Origin Timestamp (64) + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + Receive Timestamp (64) + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + Transmit Timestamp (64) + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . . +// . Extension Field 1 (variable) . +// . . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . . +// . Extension Field 2 (variable) . +// . . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Key Identifier | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// | dgst (128) | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// From http://www.ietf.org/rfc/rfc5905.txt +// +// The fields "Extension Field 1 (variable)" and later are optional fields, +// and so we can set a minimum NTP record size of 48 bytes. +const ntpMinimumRecordSizeInBytes int = 48 + +//****************************************************************************** + +// NTP Type +// -------- +// Type NTP implements the DecodingLayer interface. Each NTP object +// represents in a structured form the NTP record present as the UDP +// payload in an NTP UDP packet. +// + +type NTPLeapIndicator uint8 +type NTPVersion uint8 +type NTPMode uint8 +type NTPStratum uint8 +type NTPLog2Seconds int8 +type NTPFixed16Seconds uint32 +type NTPReferenceID uint32 +type NTPTimestamp uint64 + +type NTP struct { + BaseLayer // Stores the packet bytes and payload bytes. + + LeapIndicator NTPLeapIndicator // [0,3]. Indicates whether leap second(s) is to be added. + Version NTPVersion // [0,7]. Version of the NTP protocol. + Mode NTPMode // [0,7]. Mode. + Stratum NTPStratum // [0,255]. Stratum of time server in the server tree. + Poll NTPLog2Seconds // [-128,127]. The maximum interval between successive messages, in log2 seconds. + Precision NTPLog2Seconds // [-128,127]. The precision of the system clock, in log2 seconds. + RootDelay NTPFixed16Seconds // [0,2^32-1]. Total round trip delay to the reference clock in seconds times 2^16. + RootDispersion NTPFixed16Seconds // [0,2^32-1]. Total dispersion to the reference clock, in seconds times 2^16. + ReferenceID NTPReferenceID // ID code of reference clock [0,2^32-1]. + ReferenceTimestamp NTPTimestamp // Most recent timestamp from the reference clock. + OriginTimestamp NTPTimestamp // Local time when request was sent from local host. + ReceiveTimestamp NTPTimestamp // Local time (on server) that request arrived at server host. + TransmitTimestamp NTPTimestamp // Local time (on server) that request departed server host. + + // FIX: This package should analyse the extension fields and represent the extension fields too. + ExtensionBytes []byte // Just put extensions in a byte slice. +} + +//****************************************************************************** + +// LayerType returns the layer type of the NTP object, which is LayerTypeNTP. +func (d *NTP) LayerType() gopacket.LayerType { + return LayerTypeNTP +} + +//****************************************************************************** + +// decodeNTP analyses a byte slice and attempts to decode it as an NTP +// record of a UDP packet. +// +// If it succeeds, it loads p with information about the packet and returns nil. +// If it fails, it returns an error (non nil). +// +// This function is employed in layertypes.go to register the NTP layer. +func decodeNTP(data []byte, p gopacket.PacketBuilder) error { + + // Attempt to decode the byte slice. + d := &NTP{} + err := d.DecodeFromBytes(data, p) + if err != nil { + return err + } + + // If the decoding worked, add the layer to the packet and set it + // as the application layer too, if there isn't already one. + p.AddLayer(d) + p.SetApplicationLayer(d) + + return nil +} + +//****************************************************************************** + +// DecodeFromBytes analyses a byte slice and attempts to decode it as an NTP +// record of a UDP packet. +// +// Upon succeeds, it loads the NTP object with information about the packet +// and returns nil. +// Upon failure, it returns an error (non nil). +func (d *NTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + + // If the data block is too short to be a NTP record, then return an error. + if len(data) < ntpMinimumRecordSizeInBytes { + df.SetTruncated() + return errors.New("NTP packet too short") + } + + // RFC 5905 does not appear to define a maximum NTP record length. + // The protocol allows "extension fields" to be included in the record, + // and states about these fields:" + // + // "While the minimum field length containing required fields is + // four words (16 octets), a maximum field length remains to be + // established." + // + // For this reason, the packet length is not checked here for being too long. + + // NTP type embeds type BaseLayer which contains two fields: + // Contents is supposed to contain the bytes of the data at this level. + // Payload is supposed to contain the payload of this level. + // Here we set the baselayer to be the bytes of the NTP record. + d.BaseLayer = BaseLayer{Contents: data[:len(data)]} + + // Extract the fields from the block of bytes. + // To make sense of this, refer to the packet diagram + // above and the section on endian conventions. + + // The first few fields are all packed into the first 32 bits. Unpack them. + f := data[0] + d.LeapIndicator = NTPLeapIndicator((f & 0xC0) >> 6) + d.Version = NTPVersion((f & 0x38) >> 3) + d.Mode = NTPMode(f & 0x07) + d.Stratum = NTPStratum(data[1]) + d.Poll = NTPLog2Seconds(data[2]) + d.Precision = NTPLog2Seconds(data[3]) + + // The remaining fields can just be copied in big endian order. + d.RootDelay = NTPFixed16Seconds(binary.BigEndian.Uint32(data[4:8])) + d.RootDispersion = NTPFixed16Seconds(binary.BigEndian.Uint32(data[8:12])) + d.ReferenceID = NTPReferenceID(binary.BigEndian.Uint32(data[12:16])) + d.ReferenceTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[16:24])) + d.OriginTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[24:32])) + d.ReceiveTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[32:40])) + d.TransmitTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[40:48])) + + // This layer does not attempt to analyse the extension bytes. + // But if there are any, we'd like the user to know. So we just + // place them all in an ExtensionBytes field. + d.ExtensionBytes = data[48:] + + // Return no error. + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (d *NTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + data, err := b.PrependBytes(ntpMinimumRecordSizeInBytes) + if err != nil { + return err + } + + // Pack the first few fields into the first 32 bits. + h := uint8(0) + h |= (uint8(d.LeapIndicator) << 6) & 0xC0 + h |= (uint8(d.Version) << 3) & 0x38 + h |= (uint8(d.Mode)) & 0x07 + data[0] = byte(h) + data[1] = byte(d.Stratum) + data[2] = byte(d.Poll) + data[3] = byte(d.Precision) + + // The remaining fields can just be copied in big endian order. + binary.BigEndian.PutUint32(data[4:8], uint32(d.RootDelay)) + binary.BigEndian.PutUint32(data[8:12], uint32(d.RootDispersion)) + binary.BigEndian.PutUint32(data[12:16], uint32(d.ReferenceID)) + binary.BigEndian.PutUint64(data[16:24], uint64(d.ReferenceTimestamp)) + binary.BigEndian.PutUint64(data[24:32], uint64(d.OriginTimestamp)) + binary.BigEndian.PutUint64(data[32:40], uint64(d.ReceiveTimestamp)) + binary.BigEndian.PutUint64(data[40:48], uint64(d.TransmitTimestamp)) + + ex, err := b.AppendBytes(len(d.ExtensionBytes)) + if err != nil { + return err + } + copy(ex, d.ExtensionBytes) + + return nil +} + +//****************************************************************************** + +// CanDecode returns a set of layers that NTP objects can decode. +// As NTP objects can only decide the NTP layer, we can return just that layer. +// Apparently a single layer type implements LayerClass. +func (d *NTP) CanDecode() gopacket.LayerClass { + return LayerTypeNTP +} + +//****************************************************************************** + +// NextLayerType specifies the next layer that GoPacket should attempt to +// analyse after this (NTP) layer. As NTP packets do not contain any payload +// bytes, there are no further layers to analyse. +func (d *NTP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +//****************************************************************************** + +// NTP packets do not carry any data payload, so the empty byte slice is retured. +// In Go, a nil slice is functionally identical to an empty slice, so we +// return nil to avoid a heap allocation. +func (d *NTP) Payload() []byte { + return nil +} + +//****************************************************************************** +//* End Of NTP File * +//****************************************************************************** diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ospf.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ospf.go new file mode 100644 index 0000000000..ca2ac6e653 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ospf.go @@ -0,0 +1,716 @@ +// Copyright 2017 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// OSPFType denotes what kind of OSPF type it is +type OSPFType uint8 + +// Potential values for OSPF.Type. +const ( + OSPFHello OSPFType = 1 + OSPFDatabaseDescription OSPFType = 2 + OSPFLinkStateRequest OSPFType = 3 + OSPFLinkStateUpdate OSPFType = 4 + OSPFLinkStateAcknowledgment OSPFType = 5 +) + +// LSA Function Codes for LSAheader.LSType +const ( + RouterLSAtypeV2 = 0x1 + RouterLSAtype = 0x2001 + NetworkLSAtypeV2 = 0x2 + NetworkLSAtype = 0x2002 + SummaryLSANetworktypeV2 = 0x3 + InterAreaPrefixLSAtype = 0x2003 + SummaryLSAASBRtypeV2 = 0x4 + InterAreaRouterLSAtype = 0x2004 + ASExternalLSAtypeV2 = 0x5 + ASExternalLSAtype = 0x4005 + NSSALSAtype = 0x2007 + NSSALSAtypeV2 = 0x7 + LinkLSAtype = 0x0008 + IntraAreaPrefixLSAtype = 0x2009 +) + +// String conversions for OSPFType +func (i OSPFType) String() string { + switch i { + case OSPFHello: + return "Hello" + case OSPFDatabaseDescription: + return "Database Description" + case OSPFLinkStateRequest: + return "Link State Request" + case OSPFLinkStateUpdate: + return "Link State Update" + case OSPFLinkStateAcknowledgment: + return "Link State Acknowledgment" + default: + return "" + } +} + +// Prefix extends IntraAreaPrefixLSA +type Prefix struct { + PrefixLength uint8 + PrefixOptions uint8 + Metric uint16 + AddressPrefix []byte +} + +// IntraAreaPrefixLSA is the struct from RFC 5340 A.4.10. +type IntraAreaPrefixLSA struct { + NumOfPrefixes uint16 + RefLSType uint16 + RefLinkStateID uint32 + RefAdvRouter uint32 + Prefixes []Prefix +} + +// LinkLSA is the struct from RFC 5340 A.4.9. +type LinkLSA struct { + RtrPriority uint8 + Options uint32 + LinkLocalAddress []byte + NumOfPrefixes uint32 + Prefixes []Prefix +} + +// ASExternalLSAV2 is the struct from RFC 2328 A.4.5. +type ASExternalLSAV2 struct { + NetworkMask uint32 + ExternalBit uint8 + Metric uint32 + ForwardingAddress uint32 + ExternalRouteTag uint32 +} + +// ASExternalLSA is the struct from RFC 5340 A.4.7. +type ASExternalLSA struct { + Flags uint8 + Metric uint32 + PrefixLength uint8 + PrefixOptions uint8 + RefLSType uint16 + AddressPrefix []byte + ForwardingAddress []byte + ExternalRouteTag uint32 + RefLinkStateID uint32 +} + +// InterAreaRouterLSA is the struct from RFC 5340 A.4.6. +type InterAreaRouterLSA struct { + Options uint32 + Metric uint32 + DestinationRouterID uint32 +} + +// InterAreaPrefixLSA is the struct from RFC 5340 A.4.5. +type InterAreaPrefixLSA struct { + Metric uint32 + PrefixLength uint8 + PrefixOptions uint8 + AddressPrefix []byte +} + +// NetworkLSA is the struct from RFC 5340 A.4.4. +type NetworkLSA struct { + Options uint32 + AttachedRouter []uint32 +} + +// NetworkLSAV2 is the struct from RFC 2328 A.4.3. +type NetworkLSAV2 struct { + NetworkMask uint32 + AttachedRouter []uint32 +} + +// RouterV2 extends RouterLSAV2 +type RouterV2 struct { + Type uint8 + LinkID uint32 + LinkData uint32 + Metric uint16 +} + +// RouterLSAV2 is the struct from RFC 2328 A.4.2. +type RouterLSAV2 struct { + Flags uint8 + Links uint16 + Routers []RouterV2 +} + +// Router extends RouterLSA +type Router struct { + Type uint8 + Metric uint16 + InterfaceID uint32 + NeighborInterfaceID uint32 + NeighborRouterID uint32 +} + +// RouterLSA is the struct from RFC 5340 A.4.3. +type RouterLSA struct { + Flags uint8 + Options uint32 + Routers []Router +} + +// LSAheader is the struct from RFC 5340 A.4.2 and RFC 2328 A.4.1. +type LSAheader struct { + LSAge uint16 + LSType uint16 + LinkStateID uint32 + AdvRouter uint32 + LSSeqNumber uint32 + LSChecksum uint16 + Length uint16 + LSOptions uint8 +} + +// LSA links LSAheader with the structs from RFC 5340 A.4. +type LSA struct { + LSAheader + Content interface{} +} + +// LSUpdate is the struct from RFC 5340 A.3.5. +type LSUpdate struct { + NumOfLSAs uint32 + LSAs []LSA +} + +// LSReq is the struct from RFC 5340 A.3.4. +type LSReq struct { + LSType uint16 + LSID uint32 + AdvRouter uint32 +} + +// DbDescPkg is the struct from RFC 5340 A.3.3. +type DbDescPkg struct { + Options uint32 + InterfaceMTU uint16 + Flags uint16 + DDSeqNumber uint32 + LSAinfo []LSAheader +} + +// HelloPkg is the struct from RFC 5340 A.3.2. +type HelloPkg struct { + InterfaceID uint32 + RtrPriority uint8 + Options uint32 + HelloInterval uint16 + RouterDeadInterval uint32 + DesignatedRouterID uint32 + BackupDesignatedRouterID uint32 + NeighborID []uint32 +} + +// HelloPkgV2 extends the HelloPkg struct with OSPFv2 information +type HelloPkgV2 struct { + HelloPkg + NetworkMask uint32 +} + +// OSPF is a basic OSPF packet header with common fields of Version 2 and Version 3. +type OSPF struct { + Version uint8 + Type OSPFType + PacketLength uint16 + RouterID uint32 + AreaID uint32 + Checksum uint16 + Content interface{} +} + +// OSPFv2 extend the OSPF head with version 2 specific fields +type OSPFv2 struct { + BaseLayer + OSPF + AuType uint16 + Authentication uint64 +} + +// OSPFv3 extend the OSPF head with version 3 specific fields +type OSPFv3 struct { + BaseLayer + OSPF + Instance uint8 + Reserved uint8 +} + +// getLSAsv2 parses the LSA information from the packet for OSPFv2 +func getLSAsv2(num uint32, data []byte) ([]LSA, error) { + var lsas []LSA + var i uint32 = 0 + var offset uint32 = 0 + for ; i < num; i++ { + lstype := uint16(data[offset+3]) + lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20]) + content, err := extractLSAInformation(lstype, lsalength, data[offset:]) + if err != nil { + return nil, fmt.Errorf("Could not extract Link State type.") + } + lsa := LSA{ + LSAheader: LSAheader{ + LSAge: binary.BigEndian.Uint16(data[offset : offset+2]), + LSOptions: data[offset+2], + LSType: lstype, + LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]), + AdvRouter: binary.BigEndian.Uint32(data[offset+8 : offset+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]), + LSChecksum: binary.BigEndian.Uint16(data[offset+16 : offset+18]), + Length: lsalength, + }, + Content: content, + } + lsas = append(lsas, lsa) + offset += uint32(lsalength) + } + return lsas, nil +} + +// extractLSAInformation extracts all the LSA information +func extractLSAInformation(lstype, lsalength uint16, data []byte) (interface{}, error) { + if lsalength < 20 { + return nil, fmt.Errorf("Link State header length %v too short, %v required", lsalength, 20) + } + if len(data) < int(lsalength) { + return nil, fmt.Errorf("Link State header length %v too short, %v required", len(data), lsalength) + } + var content interface{} + switch lstype { + case RouterLSAtypeV2: + var routers []RouterV2 + var j uint32 + for j = 24; j < uint32(lsalength); j += 12 { + if len(data) < int(j+12) { + return nil, errors.New("LSAtypeV2 too small") + } + router := RouterV2{ + LinkID: binary.BigEndian.Uint32(data[j : j+4]), + LinkData: binary.BigEndian.Uint32(data[j+4 : j+8]), + Type: uint8(data[j+8]), + Metric: binary.BigEndian.Uint16(data[j+10 : j+12]), + } + routers = append(routers, router) + } + if len(data) < 24 { + return nil, errors.New("LSAtypeV2 too small") + } + links := binary.BigEndian.Uint16(data[22:24]) + content = RouterLSAV2{ + Flags: data[20], + Links: links, + Routers: routers, + } + case NSSALSAtypeV2: + fallthrough + case ASExternalLSAtypeV2: + content = ASExternalLSAV2{ + NetworkMask: binary.BigEndian.Uint32(data[20:24]), + ExternalBit: data[24] & 0x80, + Metric: binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF, + ForwardingAddress: binary.BigEndian.Uint32(data[28:32]), + ExternalRouteTag: binary.BigEndian.Uint32(data[32:36]), + } + case NetworkLSAtypeV2: + var routers []uint32 + var j uint32 + for j = 24; j < uint32(lsalength); j += 4 { + routers = append(routers, binary.BigEndian.Uint32(data[j:j+4])) + } + content = NetworkLSAV2{ + NetworkMask: binary.BigEndian.Uint32(data[20:24]), + AttachedRouter: routers, + } + case RouterLSAtype: + var routers []Router + var j uint32 + for j = 24; j < uint32(lsalength); j += 16 { + router := Router{ + Type: uint8(data[j]), + Metric: binary.BigEndian.Uint16(data[j+2 : j+4]), + InterfaceID: binary.BigEndian.Uint32(data[j+4 : j+8]), + NeighborInterfaceID: binary.BigEndian.Uint32(data[j+8 : j+12]), + NeighborRouterID: binary.BigEndian.Uint32(data[j+12 : j+16]), + } + routers = append(routers, router) + } + content = RouterLSA{ + Flags: uint8(data[20]), + Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + Routers: routers, + } + case NetworkLSAtype: + var routers []uint32 + var j uint32 + for j = 24; j < uint32(lsalength); j += 4 { + routers = append(routers, binary.BigEndian.Uint32(data[j:j+4])) + } + content = NetworkLSA{ + Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + AttachedRouter: routers, + } + case InterAreaPrefixLSAtype: + content = InterAreaPrefixLSA{ + Metric: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + PrefixLength: uint8(data[24]), + PrefixOptions: uint8(data[25]), + AddressPrefix: data[28:uint32(lsalength)], + } + case InterAreaRouterLSAtype: + content = InterAreaRouterLSA{ + Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + Metric: binary.BigEndian.Uint32(data[24:28]) & 0x00FFFFFF, + DestinationRouterID: binary.BigEndian.Uint32(data[28:32]), + } + case ASExternalLSAtype: + fallthrough + case NSSALSAtype: + flags := uint8(data[20]) + prefixLen := uint8(data[24]) / 8 + var forwardingAddress []byte + if (flags & 0x02) == 0x02 { + forwardingAddress = data[28+uint32(prefixLen) : 28+uint32(prefixLen)+16] + } + content = ASExternalLSA{ + Flags: flags, + Metric: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + PrefixLength: prefixLen, + PrefixOptions: uint8(data[25]), + RefLSType: binary.BigEndian.Uint16(data[26:28]), + AddressPrefix: data[28 : 28+uint32(prefixLen)], + ForwardingAddress: forwardingAddress, + } + case LinkLSAtype: + var prefixes []Prefix + var prefixOffset uint32 = 44 + var j uint32 + numOfPrefixes := binary.BigEndian.Uint32(data[40:44]) + for j = 0; j < numOfPrefixes; j++ { + prefixLen := uint8(data[prefixOffset]) + prefix := Prefix{ + PrefixLength: prefixLen, + PrefixOptions: uint8(data[prefixOffset+1]), + AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8], + } + prefixes = append(prefixes, prefix) + prefixOffset = prefixOffset + 4 + uint32(prefixLen)/8 + } + content = LinkLSA{ + RtrPriority: uint8(data[20]), + Options: binary.BigEndian.Uint32(data[20:24]) & 0x00FFFFFF, + LinkLocalAddress: data[24:40], + NumOfPrefixes: numOfPrefixes, + Prefixes: prefixes, + } + case IntraAreaPrefixLSAtype: + var prefixes []Prefix + var prefixOffset uint32 = 32 + var j uint16 + numOfPrefixes := binary.BigEndian.Uint16(data[20:22]) + for j = 0; j < numOfPrefixes; j++ { + prefixLen := uint8(data[prefixOffset]) + prefix := Prefix{ + PrefixLength: prefixLen, + PrefixOptions: uint8(data[prefixOffset+1]), + Metric: binary.BigEndian.Uint16(data[prefixOffset+2 : prefixOffset+4]), + AddressPrefix: data[prefixOffset+4 : prefixOffset+4+uint32(prefixLen)/8], + } + prefixes = append(prefixes, prefix) + prefixOffset = prefixOffset + 4 + uint32(prefixLen) + } + content = IntraAreaPrefixLSA{ + NumOfPrefixes: numOfPrefixes, + RefLSType: binary.BigEndian.Uint16(data[22:24]), + RefLinkStateID: binary.BigEndian.Uint32(data[24:28]), + RefAdvRouter: binary.BigEndian.Uint32(data[28:32]), + Prefixes: prefixes, + } + default: + return nil, fmt.Errorf("Unknown Link State type.") + } + return content, nil +} + +// getLSAs parses the LSA information from the packet for OSPFv3 +func getLSAs(num uint32, data []byte) ([]LSA, error) { + var lsas []LSA + var i uint32 = 0 + var offset uint32 = 0 + for ; i < num; i++ { + var content interface{} + lstype := binary.BigEndian.Uint16(data[offset+2 : offset+4]) + lsalength := binary.BigEndian.Uint16(data[offset+18 : offset+20]) + + content, err := extractLSAInformation(lstype, lsalength, data[offset:]) + if err != nil { + return nil, fmt.Errorf("Could not extract Link State type.") + } + lsa := LSA{ + LSAheader: LSAheader{ + LSAge: binary.BigEndian.Uint16(data[offset : offset+2]), + LSType: lstype, + LinkStateID: binary.BigEndian.Uint32(data[offset+4 : offset+8]), + AdvRouter: binary.BigEndian.Uint32(data[offset+8 : offset+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[offset+12 : offset+16]), + LSChecksum: binary.BigEndian.Uint16(data[offset+16 : offset+18]), + Length: lsalength, + }, + Content: content, + } + lsas = append(lsas, lsa) + offset += uint32(lsalength) + } + return lsas, nil +} + +// DecodeFromBytes decodes the given bytes into the OSPF layer. +func (ospf *OSPFv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 24 { + return fmt.Errorf("Packet too smal for OSPF Version 2") + } + + ospf.Version = uint8(data[0]) + ospf.Type = OSPFType(data[1]) + ospf.PacketLength = binary.BigEndian.Uint16(data[2:4]) + ospf.RouterID = binary.BigEndian.Uint32(data[4:8]) + ospf.AreaID = binary.BigEndian.Uint32(data[8:12]) + ospf.Checksum = binary.BigEndian.Uint16(data[12:14]) + ospf.AuType = binary.BigEndian.Uint16(data[14:16]) + ospf.Authentication = binary.BigEndian.Uint64(data[16:24]) + + switch ospf.Type { + case OSPFHello: + var neighbors []uint32 + for i := 44; uint16(i+4) <= ospf.PacketLength; i += 4 { + neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4])) + } + ospf.Content = HelloPkgV2{ + NetworkMask: binary.BigEndian.Uint32(data[24:28]), + HelloPkg: HelloPkg{ + HelloInterval: binary.BigEndian.Uint16(data[28:30]), + Options: uint32(data[30]), + RtrPriority: uint8(data[31]), + RouterDeadInterval: binary.BigEndian.Uint32(data[32:36]), + DesignatedRouterID: binary.BigEndian.Uint32(data[36:40]), + BackupDesignatedRouterID: binary.BigEndian.Uint32(data[40:44]), + NeighborID: neighbors, + }, + } + case OSPFDatabaseDescription: + var lsas []LSAheader + for i := 32; uint16(i+20) <= ospf.PacketLength; i += 20 { + lsa := LSAheader{ + LSAge: binary.BigEndian.Uint16(data[i : i+2]), + LSOptions: data[i+2], + LSType: uint16(data[i+3]), + LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]), + LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]), + Length: binary.BigEndian.Uint16(data[i+18 : i+20]), + } + lsas = append(lsas, lsa) + } + ospf.Content = DbDescPkg{ + InterfaceMTU: binary.BigEndian.Uint16(data[24:26]), + Options: uint32(data[26]), + Flags: uint16(data[27]), + DDSeqNumber: binary.BigEndian.Uint32(data[28:32]), + LSAinfo: lsas, + } + case OSPFLinkStateRequest: + var lsrs []LSReq + for i := 24; uint16(i+12) <= ospf.PacketLength; i += 12 { + lsr := LSReq{ + LSType: binary.BigEndian.Uint16(data[i+2 : i+4]), + LSID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + } + lsrs = append(lsrs, lsr) + } + ospf.Content = lsrs + case OSPFLinkStateUpdate: + num := binary.BigEndian.Uint32(data[24:28]) + + lsas, err := getLSAsv2(num, data[28:]) + if err != nil { + return fmt.Errorf("Cannot parse Link State Update packet: %v", err) + } + ospf.Content = LSUpdate{ + NumOfLSAs: num, + LSAs: lsas, + } + case OSPFLinkStateAcknowledgment: + var lsas []LSAheader + for i := 24; uint16(i+20) <= ospf.PacketLength; i += 20 { + lsa := LSAheader{ + LSAge: binary.BigEndian.Uint16(data[i : i+2]), + LSOptions: data[i+2], + LSType: uint16(data[i+3]), + LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]), + LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]), + Length: binary.BigEndian.Uint16(data[i+18 : i+20]), + } + lsas = append(lsas, lsa) + } + ospf.Content = lsas + } + return nil +} + +// DecodeFromBytes decodes the given bytes into the OSPF layer. +func (ospf *OSPFv3) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + + if len(data) < 16 { + return fmt.Errorf("Packet too smal for OSPF Version 3") + } + + ospf.Version = uint8(data[0]) + ospf.Type = OSPFType(data[1]) + ospf.PacketLength = binary.BigEndian.Uint16(data[2:4]) + ospf.RouterID = binary.BigEndian.Uint32(data[4:8]) + ospf.AreaID = binary.BigEndian.Uint32(data[8:12]) + ospf.Checksum = binary.BigEndian.Uint16(data[12:14]) + ospf.Instance = uint8(data[14]) + ospf.Reserved = uint8(data[15]) + + switch ospf.Type { + case OSPFHello: + var neighbors []uint32 + for i := 36; uint16(i+4) <= ospf.PacketLength; i += 4 { + neighbors = append(neighbors, binary.BigEndian.Uint32(data[i:i+4])) + } + ospf.Content = HelloPkg{ + InterfaceID: binary.BigEndian.Uint32(data[16:20]), + RtrPriority: uint8(data[20]), + Options: binary.BigEndian.Uint32(data[21:25]) >> 8, + HelloInterval: binary.BigEndian.Uint16(data[24:26]), + RouterDeadInterval: uint32(binary.BigEndian.Uint16(data[26:28])), + DesignatedRouterID: binary.BigEndian.Uint32(data[28:32]), + BackupDesignatedRouterID: binary.BigEndian.Uint32(data[32:36]), + NeighborID: neighbors, + } + case OSPFDatabaseDescription: + var lsas []LSAheader + for i := 28; uint16(i+20) <= ospf.PacketLength; i += 20 { + lsa := LSAheader{ + LSAge: binary.BigEndian.Uint16(data[i : i+2]), + LSType: binary.BigEndian.Uint16(data[i+2 : i+4]), + LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]), + LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]), + Length: binary.BigEndian.Uint16(data[i+18 : i+20]), + } + lsas = append(lsas, lsa) + } + ospf.Content = DbDescPkg{ + Options: binary.BigEndian.Uint32(data[16:20]) & 0x00FFFFFF, + InterfaceMTU: binary.BigEndian.Uint16(data[20:22]), + Flags: binary.BigEndian.Uint16(data[22:24]), + DDSeqNumber: binary.BigEndian.Uint32(data[24:28]), + LSAinfo: lsas, + } + case OSPFLinkStateRequest: + var lsrs []LSReq + for i := 16; uint16(i+12) <= ospf.PacketLength; i += 12 { + lsr := LSReq{ + LSType: binary.BigEndian.Uint16(data[i+2 : i+4]), + LSID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + } + lsrs = append(lsrs, lsr) + } + ospf.Content = lsrs + case OSPFLinkStateUpdate: + num := binary.BigEndian.Uint32(data[16:20]) + lsas, err := getLSAs(num, data[20:]) + if err != nil { + return fmt.Errorf("Cannot parse Link State Update packet: %v", err) + } + ospf.Content = LSUpdate{ + NumOfLSAs: num, + LSAs: lsas, + } + + case OSPFLinkStateAcknowledgment: + var lsas []LSAheader + for i := 16; uint16(i+20) <= ospf.PacketLength; i += 20 { + lsa := LSAheader{ + LSAge: binary.BigEndian.Uint16(data[i : i+2]), + LSType: binary.BigEndian.Uint16(data[i+2 : i+4]), + LinkStateID: binary.BigEndian.Uint32(data[i+4 : i+8]), + AdvRouter: binary.BigEndian.Uint32(data[i+8 : i+12]), + LSSeqNumber: binary.BigEndian.Uint32(data[i+12 : i+16]), + LSChecksum: binary.BigEndian.Uint16(data[i+16 : i+18]), + Length: binary.BigEndian.Uint16(data[i+18 : i+20]), + } + lsas = append(lsas, lsa) + } + ospf.Content = lsas + default: + } + + return nil +} + +// LayerType returns LayerTypeOSPF +func (ospf *OSPFv2) LayerType() gopacket.LayerType { + return LayerTypeOSPF +} +func (ospf *OSPFv3) LayerType() gopacket.LayerType { + return LayerTypeOSPF +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (ospf *OSPFv2) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} +func (ospf *OSPFv3) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (ospf *OSPFv2) CanDecode() gopacket.LayerClass { + return LayerTypeOSPF +} +func (ospf *OSPFv3) CanDecode() gopacket.LayerClass { + return LayerTypeOSPF +} + +func decodeOSPF(data []byte, p gopacket.PacketBuilder) error { + if len(data) < 14 { + return fmt.Errorf("Packet too smal for OSPF") + } + + switch uint8(data[0]) { + case 2: + ospf := &OSPFv2{} + return decodingLayerDecoder(ospf, data, p) + case 3: + ospf := &OSPFv3{} + return decodingLayerDecoder(ospf, data, p) + default: + } + + return fmt.Errorf("Unable to determine OSPF type.") +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pflog.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pflog.go new file mode 100644 index 0000000000..2daf45579d --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pflog.go @@ -0,0 +1,84 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +type PFDirection uint8 + +const ( + PFDirectionInOut PFDirection = 0 + PFDirectionIn PFDirection = 1 + PFDirectionOut PFDirection = 2 +) + +// PFLog provides the layer for 'pf' packet-filter logging, as described at +// http://www.freebsd.org/cgi/man.cgi?query=pflog&sektion=4 +type PFLog struct { + BaseLayer + Length uint8 + Family ProtocolFamily + Action, Reason uint8 + IFName, Ruleset []byte + RuleNum, SubruleNum uint32 + UID uint32 + PID int32 + RuleUID uint32 + RulePID int32 + Direction PFDirection + // The remainder is padding +} + +func (pf *PFLog) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 60 { + df.SetTruncated() + return errors.New("PFLog data less than 60 bytes") + } + pf.Length = data[0] + pf.Family = ProtocolFamily(data[1]) + pf.Action = data[2] + pf.Reason = data[3] + pf.IFName = data[4:20] + pf.Ruleset = data[20:36] + pf.RuleNum = binary.BigEndian.Uint32(data[36:40]) + pf.SubruleNum = binary.BigEndian.Uint32(data[40:44]) + pf.UID = binary.BigEndian.Uint32(data[44:48]) + pf.PID = int32(binary.BigEndian.Uint32(data[48:52])) + pf.RuleUID = binary.BigEndian.Uint32(data[52:56]) + pf.RulePID = int32(binary.BigEndian.Uint32(data[56:60])) + pf.Direction = PFDirection(data[60]) + actualLength := int(pf.Length) + if pf.Length%4 == 1 { + actualLength += 3 + } + if len(data) < actualLength { + return fmt.Errorf("PFLog data size < %d", actualLength) + } + pf.Contents = data[:actualLength] + pf.Payload = data[actualLength:] + return nil +} + +// LayerType returns layers.LayerTypePFLog +func (pf *PFLog) LayerType() gopacket.LayerType { return LayerTypePFLog } + +func (pf *PFLog) CanDecode() gopacket.LayerClass { return LayerTypePFLog } + +func (pf *PFLog) NextLayerType() gopacket.LayerType { + return pf.Family.LayerType() +} + +func decodePFLog(data []byte, p gopacket.PacketBuilder) error { + pf := &PFLog{} + return decodingLayerDecoder(pf, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ports.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ports.go new file mode 100644 index 0000000000..4257a0403a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ports.go @@ -0,0 +1,201 @@ +// 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 layers + +import ( + "fmt" + "strconv" + + "github.com/gopacket/gopacket" +) + +// TCPPort is a port in a TCP layer. +type TCPPort uint16 + +// UDPPort is a port in a UDP layer. +type UDPPort uint16 + +// RUDPPort is a port in a RUDP layer. +type RUDPPort uint8 + +// SCTPPort is a port in a SCTP layer. +type SCTPPort uint16 + +// UDPLitePort is a port in a UDPLite layer. +type UDPLitePort uint16 + +// RUDPPortNames contains the string names for all RUDP ports. +var RUDPPortNames = map[RUDPPort]string{} + +// UDPLitePortNames contains the string names for all UDPLite ports. +var UDPLitePortNames = map[UDPLitePort]string{} + +// {TCP,UDP,SCTP}PortNames can be found in iana_ports.go + +// String returns the port as "number(name)" if there's a well-known port name, +// or just "number" if there isn't. Well-known names are stored in +// TCPPortNames. +func (a TCPPort) String() string { + if name, ok := TCPPortNames(a); ok { + return fmt.Sprintf("%d(%s)", a, name) + } + return strconv.Itoa(int(a)) +} + +// LayerType returns a LayerType that would be able to decode the +// application payload. It uses some well-known ports such as 53 for +// DNS. +// +// Returns gopacket.LayerTypePayload for unknown/unsupported port numbers. +func (a TCPPort) LayerType() gopacket.LayerType { + if tcpPortLayerTypeOverride.has(uint16(a)) { + return tcpPortLayerType[a] + } + switch a { + case 53: + return LayerTypeDNS + case 443: // https + return LayerTypeTLS + case 502: // modbustcp + return LayerTypeModbusTCP + case 636: // ldaps + return LayerTypeTLS + case 989: // ftps-data + return LayerTypeTLS + case 990: // ftps + return LayerTypeTLS + case 992: // telnets + return LayerTypeTLS + case 993: // imaps + return LayerTypeTLS + case 994: // ircs + return LayerTypeTLS + case 995: // pop3s + return LayerTypeTLS + case 2222: // EtherNet/IP-1 + return LayerTypeENIP + case 5061: // ips + return LayerTypeTLS + case 44818: // EtherNet/IP-2 + return LayerTypeENIP + } + return gopacket.LayerTypePayload +} + +var tcpPortLayerTypeOverride bitfield + +var tcpPortLayerType = map[TCPPort]gopacket.LayerType{} + +// RegisterTCPPortLayerType creates a new mapping between a TCPPort +// and an underlaying LayerType. +func RegisterTCPPortLayerType(port TCPPort, layerType gopacket.LayerType) { + tcpPortLayerTypeOverride.set(uint16(port)) + tcpPortLayerType[port] = layerType +} + +// String returns the port as "number(name)" if there's a well-known port name, +// or just "number" if there isn't. Well-known names are stored in +// UDPPortNames. +func (a UDPPort) String() string { + if name, ok := UDPPortNames(a); ok { + return fmt.Sprintf("%d(%s)", a, name) + } + return strconv.Itoa(int(a)) +} + +// LayerType returns a LayerType that would be able to decode the +// application payload. It uses some well-known ports such as 53 for +// DNS. +// +// Returns gopacket.LayerTypePayload for unknown/unsupported port numbers. +func (a UDPPort) LayerType() gopacket.LayerType { + if udpPortLayerTypeOverride.has(uint16(a)) { + return udpPortLayerType[a] + } + switch a { + case 53: + return LayerTypeDNS + case 67: + return LayerTypeDHCPv4 + case 68: + return LayerTypeDHCPv4 + case 123: + return LayerTypeNTP + case 546: + return LayerTypeDHCPv6 + case 547: + return LayerTypeDHCPv6 + case 623: + return LayerTypeRMCP + case 666: + return LayerTypeAGUEVar0 + case 1000: + return LayerTypeAPSP + case 1812: + return LayerTypeRADIUS + case 2123: + return LayerTypeGTPv2 + case 2152: + return LayerTypeGTPv1U + case 2222: // EtherNet/IP-1 + return LayerTypeENIP + case 3784: + return LayerTypeBFD + case 4789: + return LayerTypeVXLAN + case 5060: + return LayerTypeSIP + case 6081: + return LayerTypeGeneve + case 6343: + return LayerTypeSFlow + case 44818: // EtherNet/IP-2 + return LayerTypeENIP + } + return gopacket.LayerTypePayload +} + +var udpPortLayerTypeOverride bitfield + +var udpPortLayerType = map[UDPPort]gopacket.LayerType{} + +// RegisterUDPPortLayerType creates a new mapping between a UDPPort +// and an underlaying LayerType. +func RegisterUDPPortLayerType(port UDPPort, layerType gopacket.LayerType) { + udpPortLayerTypeOverride.set(uint16(port)) + udpPortLayerType[port] = layerType +} + +// String returns the port as "number(name)" if there's a well-known port name, +// or just "number" if there isn't. Well-known names are stored in +// RUDPPortNames. +func (a RUDPPort) String() string { + if name, ok := RUDPPortNames[a]; ok { + return fmt.Sprintf("%d(%s)", a, name) + } + return strconv.Itoa(int(a)) +} + +// String returns the port as "number(name)" if there's a well-known port name, +// or just "number" if there isn't. Well-known names are stored in +// SCTPPortNames. +func (a SCTPPort) String() string { + if name, ok := SCTPPortNames(a); ok { + return fmt.Sprintf("%d(%s)", a, name) + } + return strconv.Itoa(int(a)) +} + +// String returns the port as "number(name)" if there's a well-known port name, +// or just "number" if there isn't. Well-known names are stored in +// UDPLitePortNames. +func (a UDPLitePort) String() string { + if name, ok := UDPLitePortNames[a]; ok { + return fmt.Sprintf("%d(%s)", a, name) + } + return strconv.Itoa(int(a)) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ppp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ppp.go new file mode 100644 index 0000000000..0a66074b47 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/ppp.go @@ -0,0 +1,89 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// PPP is the layer for PPP encapsulation headers. +type PPP struct { + BaseLayer + PPPType PPPType + HasPPTPHeader bool +} + +// PPPEndpoint is a singleton endpoint for PPP. Since there is no actual +// addressing for the two ends of a PPP connection, we use a singleton value +// named 'point' for each endpoint. +var PPPEndpoint = gopacket.NewEndpoint(EndpointPPP, nil) + +// PPPFlow is a singleton flow for PPP. Since there is no actual addressing for +// the two ends of a PPP connection, we use a singleton value to represent the +// flow for all PPP connections. +var PPPFlow = gopacket.NewFlow(EndpointPPP, nil, nil) + +// LayerType returns LayerTypePPP +func (p *PPP) LayerType() gopacket.LayerType { return LayerTypePPP } + +// LinkFlow returns PPPFlow. +func (p *PPP) LinkFlow() gopacket.Flow { return PPPFlow } + +func decodePPP(data []byte, p gopacket.PacketBuilder) error { + ppp := &PPP{} + offset := 0 + if data[0] == 0xff && data[1] == 0x03 { + offset = 2 + ppp.HasPPTPHeader = true + } + if data[offset]&0x1 == 0 { + if data[offset+1]&0x1 == 0 { + return errors.New("PPP has invalid type") + } + ppp.PPPType = PPPType(binary.BigEndian.Uint16(data[offset : offset+2])) + ppp.Contents = data[offset : offset+2] + ppp.Payload = data[offset+2:] + } else { + ppp.PPPType = PPPType(data[offset]) + ppp.Contents = data[offset : offset+1] + ppp.Payload = data[offset+1:] + } + p.AddLayer(ppp) + p.SetLinkLayer(ppp) + return p.NextDecoder(ppp.PPPType) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p *PPP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + if p.PPPType&0x100 == 0 { + bytes, err := b.PrependBytes(2) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes, uint16(p.PPPType)) + } else { + bytes, err := b.PrependBytes(1) + if err != nil { + return err + } + bytes[0] = uint8(p.PPPType) + } + if p.HasPPTPHeader { + bytes, err := b.PrependBytes(2) + if err != nil { + return err + } + bytes[0] = 0xff + bytes[1] = 0x03 + } + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pppoe.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pppoe.go new file mode 100644 index 0000000000..549224d1b4 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/pppoe.go @@ -0,0 +1,61 @@ +// 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 layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +// PPPoE is the layer for PPPoE encapsulation headers. +type PPPoE struct { + BaseLayer + Version uint8 + Type uint8 + Code PPPoECode + SessionId uint16 + Length uint16 +} + +// LayerType returns gopacket.LayerTypePPPoE. +func (p *PPPoE) LayerType() gopacket.LayerType { + return LayerTypePPPoE +} + +// decodePPPoE decodes the PPPoE header (see http://tools.ietf.org/html/rfc2516). +func decodePPPoE(data []byte, p gopacket.PacketBuilder) error { + pppoe := &PPPoE{ + Version: data[0] >> 4, + Type: data[0] & 0x0F, + Code: PPPoECode(data[1]), + SessionId: binary.BigEndian.Uint16(data[2:4]), + Length: binary.BigEndian.Uint16(data[4:6]), + } + pppoe.BaseLayer = BaseLayer{data[:6], data[6 : 6+pppoe.Length]} + p.AddLayer(pppoe) + return p.NextDecoder(pppoe.Code) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (p *PPPoE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + payload := b.Bytes() + bytes, err := b.PrependBytes(6) + if err != nil { + return err + } + bytes[0] = (p.Version << 4) | p.Type + bytes[1] = byte(p.Code) + binary.BigEndian.PutUint16(bytes[2:], p.SessionId) + if opts.FixLengths { + p.Length = uint16(len(payload)) + } + binary.BigEndian.PutUint16(bytes[4:], p.Length) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/prism.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/prism.go new file mode 100644 index 0000000000..b075ac0aed --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/prism.go @@ -0,0 +1,146 @@ +// Copyright 2015 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. + +// http://www.tcpdump.org/linktypes/LINKTYPE_IEEE802_11_PRISM.html + +package layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +func decodePrismValue(data []byte, pv *PrismValue) { + pv.DID = PrismDID(binary.LittleEndian.Uint32(data[0:4])) + pv.Status = binary.LittleEndian.Uint16(data[4:6]) + pv.Length = binary.LittleEndian.Uint16(data[6:8]) + pv.Data = data[8 : 8+pv.Length] +} + +type PrismDID uint32 + +const ( + PrismDIDType1HostTime PrismDID = 0x10044 + PrismDIDType2HostTime PrismDID = 0x01041 + PrismDIDType1MACTime PrismDID = 0x20044 + PrismDIDType2MACTime PrismDID = 0x02041 + PrismDIDType1Channel PrismDID = 0x30044 + PrismDIDType2Channel PrismDID = 0x03041 + PrismDIDType1RSSI PrismDID = 0x40044 + PrismDIDType2RSSI PrismDID = 0x04041 + PrismDIDType1SignalQuality PrismDID = 0x50044 + PrismDIDType2SignalQuality PrismDID = 0x05041 + PrismDIDType1Signal PrismDID = 0x60044 + PrismDIDType2Signal PrismDID = 0x06041 + PrismDIDType1Noise PrismDID = 0x70044 + PrismDIDType2Noise PrismDID = 0x07041 + PrismDIDType1Rate PrismDID = 0x80044 + PrismDIDType2Rate PrismDID = 0x08041 + PrismDIDType1TransmittedFrameIndicator PrismDID = 0x90044 + PrismDIDType2TransmittedFrameIndicator PrismDID = 0x09041 + PrismDIDType1FrameLength PrismDID = 0xA0044 + PrismDIDType2FrameLength PrismDID = 0x0A041 +) + +const ( + PrismType1MessageCode uint16 = 0x00000044 + PrismType2MessageCode uint16 = 0x00000041 +) + +func (p PrismDID) String() string { + dids := map[PrismDID]string{ + PrismDIDType1HostTime: "Host Time", + PrismDIDType2HostTime: "Host Time", + PrismDIDType1MACTime: "MAC Time", + PrismDIDType2MACTime: "MAC Time", + PrismDIDType1Channel: "Channel", + PrismDIDType2Channel: "Channel", + PrismDIDType1RSSI: "RSSI", + PrismDIDType2RSSI: "RSSI", + PrismDIDType1SignalQuality: "Signal Quality", + PrismDIDType2SignalQuality: "Signal Quality", + PrismDIDType1Signal: "Signal", + PrismDIDType2Signal: "Signal", + PrismDIDType1Noise: "Noise", + PrismDIDType2Noise: "Noise", + PrismDIDType1Rate: "Rate", + PrismDIDType2Rate: "Rate", + PrismDIDType1TransmittedFrameIndicator: "Transmitted Frame Indicator", + PrismDIDType2TransmittedFrameIndicator: "Transmitted Frame Indicator", + PrismDIDType1FrameLength: "Frame Length", + PrismDIDType2FrameLength: "Frame Length", + } + + if str, ok := dids[p]; ok { + return str + } + + return "Unknown DID" +} + +type PrismValue struct { + DID PrismDID + Status uint16 + Length uint16 + Data []byte +} + +func (pv *PrismValue) IsSupplied() bool { + return pv.Status == 1 +} + +var ErrPrismExpectedMoreData = errors.New("Expected more data.") +var ErrPrismInvalidCode = errors.New("Invalid header code.") + +func decodePrismHeader(data []byte, p gopacket.PacketBuilder) error { + d := &PrismHeader{} + return decodingLayerDecoder(d, data, p) +} + +type PrismHeader struct { + BaseLayer + Code uint16 + Length uint16 + DeviceName string + Values []PrismValue +} + +func (m *PrismHeader) LayerType() gopacket.LayerType { return LayerTypePrismHeader } + +func (m *PrismHeader) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Code = binary.LittleEndian.Uint16(data[0:4]) + m.Length = binary.LittleEndian.Uint16(data[4:8]) + m.DeviceName = string(data[8:24]) + m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: data[m.Length:len(data)]} + + switch m.Code { + case PrismType1MessageCode: + fallthrough + case PrismType2MessageCode: + // valid message code + default: + return ErrPrismInvalidCode + } + + offset := uint16(24) + + m.Values = make([]PrismValue, (m.Length-offset)/12) + for i := 0; i < len(m.Values); i++ { + decodePrismValue(data[offset:offset+12], &m.Values[i]) + offset += 12 + } + + if offset != m.Length { + return ErrPrismExpectedMoreData + } + + return nil +} + +func (m *PrismHeader) CanDecode() gopacket.LayerClass { return LayerTypePrismHeader } +func (m *PrismHeader) NextLayerType() gopacket.LayerType { return LayerTypeDot11 } diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radiotap.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radiotap.go new file mode 100644 index 0000000000..c26776a297 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radiotap.go @@ -0,0 +1,1819 @@ +// Copyright 2014 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 layers + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + "strings" + + "github.com/gopacket/gopacket" +) + +// align calculates the number of bytes needed to align with the width +// on the offset, returning the number of bytes we need to skip to +// align to the offset (width). +func align(offset uint16, width uint16) uint16 { + return ((((offset) + ((width) - 1)) & (^((width) - 1))) - offset) +} + +type RadioTapPresent uint32 + +const ( + RadioTapPresentTSFT RadioTapPresent = 1 << iota + RadioTapPresentFlags + RadioTapPresentRate + RadioTapPresentChannel + RadioTapPresentFHSS + RadioTapPresentDBMAntennaSignal + RadioTapPresentDBMAntennaNoise + RadioTapPresentLockQuality + RadioTapPresentTxAttenuation + RadioTapPresentDBTxAttenuation + RadioTapPresentDBMTxPower + RadioTapPresentAntenna + RadioTapPresentDBAntennaSignal + RadioTapPresentDBAntennaNoise + RadioTapPresentRxFlags + RadioTapPresentTxFlags + RadioTapPresentRtsRetries + RadioTapPresentDataRetries + _ + RadioTapPresentMCS + RadioTapPresentAMPDUStatus + RadioTapPresentVHT + RadioTapPresentTimestamp + RadioTapPresentHE + RadioTapPresentHEMU + RadioTapPresentHEUOtherUser + RadioTapPresentZeroLengthPSDU + RadioTapPresentLSIG + RadioTapPresentTLVFields + RadioTapPresentRadioTapNamespace + RadioTapPresentVendorNamespace + RadioTapPresentEXT +) + +func (r RadioTapPresent) TSFT() bool { + return r&RadioTapPresentTSFT != 0 +} +func (r RadioTapPresent) Flags() bool { + return r&RadioTapPresentFlags != 0 +} +func (r RadioTapPresent) Rate() bool { + return r&RadioTapPresentRate != 0 +} +func (r RadioTapPresent) Channel() bool { + return r&RadioTapPresentChannel != 0 +} +func (r RadioTapPresent) FHSS() bool { + return r&RadioTapPresentFHSS != 0 +} +func (r RadioTapPresent) DBMAntennaSignal() bool { + return r&RadioTapPresentDBMAntennaSignal != 0 +} +func (r RadioTapPresent) DBMAntennaNoise() bool { + return r&RadioTapPresentDBMAntennaNoise != 0 +} +func (r RadioTapPresent) LockQuality() bool { + return r&RadioTapPresentLockQuality != 0 +} +func (r RadioTapPresent) TxAttenuation() bool { + return r&RadioTapPresentTxAttenuation != 0 +} +func (r RadioTapPresent) DBTxAttenuation() bool { + return r&RadioTapPresentDBTxAttenuation != 0 +} +func (r RadioTapPresent) DBMTxPower() bool { + return r&RadioTapPresentDBMTxPower != 0 +} +func (r RadioTapPresent) Antenna() bool { + return r&RadioTapPresentAntenna != 0 +} +func (r RadioTapPresent) DBAntennaSignal() bool { + return r&RadioTapPresentDBAntennaSignal != 0 +} +func (r RadioTapPresent) DBAntennaNoise() bool { + return r&RadioTapPresentDBAntennaNoise != 0 +} +func (r RadioTapPresent) RxFlags() bool { + return r&RadioTapPresentRxFlags != 0 +} +func (r RadioTapPresent) TxFlags() bool { + return r&RadioTapPresentTxFlags != 0 +} +func (r RadioTapPresent) RtsRetries() bool { + return r&RadioTapPresentRtsRetries != 0 +} +func (r RadioTapPresent) DataRetries() bool { + return r&RadioTapPresentDataRetries != 0 +} +func (r RadioTapPresent) MCS() bool { + return r&RadioTapPresentMCS != 0 +} +func (r RadioTapPresent) AMPDUStatus() bool { + return r&RadioTapPresentAMPDUStatus != 0 +} +func (r RadioTapPresent) VHT() bool { + return r&RadioTapPresentVHT != 0 +} +func (r RadioTapPresent) Timestamp() bool { + return r&RadioTapPresentTimestamp != 0 +} +func (r RadioTapPresent) HE() bool { + return r&RadioTapPresentHE != 0 +} +func (r RadioTapPresent) HEMU() bool { + return r&RadioTapPresentHEMU != 0 +} +func (r RadioTapPresent) HEUOtherUser() bool { + return r&RadioTapPresentHEUOtherUser != 0 +} +func (r RadioTapPresent) ZeroLengthPSDU() bool { + return r&RadioTapPresentZeroLengthPSDU != 0 +} +func (r RadioTapPresent) LSIG() bool { + return r&RadioTapPresentLSIG != 0 +} +func (r RadioTapPresent) TLVFields() bool { + return r&RadioTapPresentTLVFields != 0 +} +func (r RadioTapPresent) RadioTapNamespace() bool { + return r&RadioTapPresentRadioTapNamespace != 0 +} +func (r RadioTapPresent) VendorNamespace() bool { + return r&RadioTapPresentVendorNamespace != 0 +} +func (r RadioTapPresent) EXT() bool { + return r&RadioTapPresentEXT != 0 +} + +type RadioTapChannelFlags uint16 + +const ( + RadioTapChannelFlagsTurbo RadioTapChannelFlags = 0x0010 // Turbo channel + RadioTapChannelFlagsCCK RadioTapChannelFlags = 0x0020 // CCK channel + RadioTapChannelFlagsOFDM RadioTapChannelFlags = 0x0040 // OFDM channel + RadioTapChannelFlagsGhz2 RadioTapChannelFlags = 0x0080 // 2 GHz spectrum channel. + RadioTapChannelFlagsGhz5 RadioTapChannelFlags = 0x0100 // 5 GHz spectrum channel + RadioTapChannelFlagsPassive RadioTapChannelFlags = 0x0200 // Only passive scan allowed + RadioTapChannelFlagsDynamic RadioTapChannelFlags = 0x0400 // Dynamic CCK-OFDM channel + RadioTapChannelFlagsGFSK RadioTapChannelFlags = 0x0800 // GFSK channel (FHSS PHY) +) + +func (r RadioTapChannelFlags) Turbo() bool { + return r&RadioTapChannelFlagsTurbo != 0 +} +func (r RadioTapChannelFlags) CCK() bool { + return r&RadioTapChannelFlagsCCK != 0 +} +func (r RadioTapChannelFlags) OFDM() bool { + return r&RadioTapChannelFlagsOFDM != 0 +} +func (r RadioTapChannelFlags) Ghz2() bool { + return r&RadioTapChannelFlagsGhz2 != 0 +} +func (r RadioTapChannelFlags) Ghz5() bool { + return r&RadioTapChannelFlagsGhz5 != 0 +} +func (r RadioTapChannelFlags) Passive() bool { + return r&RadioTapChannelFlagsPassive != 0 +} +func (r RadioTapChannelFlags) Dynamic() bool { + return r&RadioTapChannelFlagsDynamic != 0 +} +func (r RadioTapChannelFlags) GFSK() bool { + return r&RadioTapChannelFlagsGFSK != 0 +} + +// String provides a human readable string for RadioTapChannelFlags. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the RadioTapChannelFlags value, not its string. +func (a RadioTapChannelFlags) String() string { + var out bytes.Buffer + if a.Turbo() { + out.WriteString("Turbo,") + } + if a.CCK() { + out.WriteString("CCK,") + } + if a.OFDM() { + out.WriteString("OFDM,") + } + if a.Ghz2() { + out.WriteString("Ghz2,") + } + if a.Ghz5() { + out.WriteString("Ghz5,") + } + if a.Passive() { + out.WriteString("Passive,") + } + if a.Dynamic() { + out.WriteString("Dynamic,") + } + if a.GFSK() { + out.WriteString("GFSK,") + } + + if length := out.Len(); length > 0 { + return string(out.Bytes()[:length-1]) // strip final comma + } + return "" +} + +type RadioTapFlags uint8 + +const ( + RadioTapFlagsCFP RadioTapFlags = 1 << iota // sent/received during CFP + RadioTapFlagsShortPreamble // sent/received * with short * preamble + RadioTapFlagsWEP // sent/received * with WEP encryption + RadioTapFlagsFrag // sent/received * with fragmentation + RadioTapFlagsFCS // frame includes FCS + RadioTapFlagsDatapad // frame has padding between * 802.11 header and payload * (to 32-bit boundary) + RadioTapFlagsBadFCS // does not pass FCS check + RadioTapFlagsShortGI // HT short GI +) + +func (r RadioTapFlags) CFP() bool { + return r&RadioTapFlagsCFP != 0 +} +func (r RadioTapFlags) ShortPreamble() bool { + return r&RadioTapFlagsShortPreamble != 0 +} +func (r RadioTapFlags) WEP() bool { + return r&RadioTapFlagsWEP != 0 +} +func (r RadioTapFlags) Frag() bool { + return r&RadioTapFlagsFrag != 0 +} +func (r RadioTapFlags) FCS() bool { + return r&RadioTapFlagsFCS != 0 +} +func (r RadioTapFlags) Datapad() bool { + return r&RadioTapFlagsDatapad != 0 +} +func (r RadioTapFlags) BadFCS() bool { + return r&RadioTapFlagsBadFCS != 0 +} +func (r RadioTapFlags) ShortGI() bool { + return r&RadioTapFlagsShortGI != 0 +} + +// String provides a human readable string for RadioTapFlags. +// This string is possibly subject to change over time; if you're storing this +// persistently, you should probably store the RadioTapFlags value, not its string. +func (a RadioTapFlags) String() string { + var out bytes.Buffer + if a.CFP() { + out.WriteString("CFP,") + } + if a.ShortPreamble() { + out.WriteString("SHORT-PREAMBLE,") + } + if a.WEP() { + out.WriteString("WEP,") + } + if a.Frag() { + out.WriteString("FRAG,") + } + if a.FCS() { + out.WriteString("FCS,") + } + if a.Datapad() { + out.WriteString("DATAPAD,") + } + if a.ShortGI() { + out.WriteString("SHORT-GI,") + } + + if length := out.Len(); length > 0 { + return string(out.Bytes()[:length-1]) // strip final comma + } + return "" +} + +type RadioTapRate uint8 + +func (a RadioTapRate) String() string { + return fmt.Sprintf("%v Mb/s", 0.5*float32(a)) +} + +type RadioTapChannelFrequency uint16 + +func (a RadioTapChannelFrequency) String() string { + return fmt.Sprintf("%d MHz", a) +} + +type RadioTapRxFlags uint16 + +const ( + RadioTapRxFlagsBadPlcp RadioTapRxFlags = 0x0002 +) + +func (f RadioTapRxFlags) BadPlcp() bool { + return f&RadioTapRxFlagsBadPlcp != 0 +} + +func (f RadioTapRxFlags) String() string { + if f.BadPlcp() { + return "BADPLCP" + } + return "" +} + +type RadioTapTxFlags uint16 + +const ( + RadioTapTxFlagsFail RadioTapTxFlags = 1 << iota + RadioTapTxFlagsCTS + RadioTapTxFlagsRTS + RadioTapTxFlagsNoACK +) + +func (f RadioTapTxFlags) Fail() bool { return f&RadioTapTxFlagsFail != 0 } +func (f RadioTapTxFlags) CTS() bool { return f&RadioTapTxFlagsCTS != 0 } +func (f RadioTapTxFlags) RTS() bool { return f&RadioTapTxFlagsRTS != 0 } +func (f RadioTapTxFlags) NoACK() bool { return f&RadioTapTxFlagsNoACK != 0 } + +func (f RadioTapTxFlags) String() string { + var tokens []string + if f.Fail() { + tokens = append(tokens, "Fail") + } + if f.CTS() { + tokens = append(tokens, "CTS") + } + if f.RTS() { + tokens = append(tokens, "RTS") + } + if f.NoACK() { + tokens = append(tokens, "NoACK") + } + return strings.Join(tokens, ",") +} + +type RadioTapMCS struct { + Known RadioTapMCSKnown + Flags RadioTapMCSFlags + MCS uint8 +} + +func (mcs RadioTapMCS) String() string { + var tokens []string + if mcs.Known.Bandwidth() { + token := "?" + switch mcs.Flags.Bandwidth() { + case 0: + token = "20" + case 1: + token = "40" + case 2: + token = "40(20L)" + case 3: + token = "40(20U)" + } + tokens = append(tokens, token) + } + if mcs.Known.MCSIndex() { + tokens = append(tokens, fmt.Sprintf("MCSIndex#%d", mcs.MCS)) + } + if mcs.Known.GuardInterval() { + if mcs.Flags.ShortGI() { + tokens = append(tokens, "shortGI") + } else { + tokens = append(tokens, "longGI") + } + } + if mcs.Known.HTFormat() { + if mcs.Flags.Greenfield() { + tokens = append(tokens, "HT-greenfield") + } else { + tokens = append(tokens, "HT-mixed") + } + } + if mcs.Known.FECType() { + if mcs.Flags.FECLDPC() { + tokens = append(tokens, "LDPC") + } else { + tokens = append(tokens, "BCC") + } + } + if mcs.Known.STBC() { + tokens = append(tokens, fmt.Sprintf("STBC#%d", mcs.Flags.STBC())) + } + if mcs.Known.NESS() { + num := 0 + if mcs.Known.NESS1() { + num |= 0x02 + } + if mcs.Flags.NESS0() { + num |= 0x01 + } + tokens = append(tokens, fmt.Sprintf("num-of-ESS#%d", num)) + } + return strings.Join(tokens, ",") +} + +type RadioTapMCSKnown uint8 + +const ( + RadioTapMCSKnownBandwidth RadioTapMCSKnown = 1 << iota + RadioTapMCSKnownMCSIndex + RadioTapMCSKnownGuardInterval + RadioTapMCSKnownHTFormat + RadioTapMCSKnownFECType + RadioTapMCSKnownSTBC + RadioTapMCSKnownNESS + RadioTapMCSKnownNESS1 +) + +func (known RadioTapMCSKnown) Bandwidth() bool { return known&RadioTapMCSKnownBandwidth != 0 } +func (known RadioTapMCSKnown) MCSIndex() bool { return known&RadioTapMCSKnownMCSIndex != 0 } +func (known RadioTapMCSKnown) GuardInterval() bool { return known&RadioTapMCSKnownGuardInterval != 0 } +func (known RadioTapMCSKnown) HTFormat() bool { return known&RadioTapMCSKnownHTFormat != 0 } +func (known RadioTapMCSKnown) FECType() bool { return known&RadioTapMCSKnownFECType != 0 } +func (known RadioTapMCSKnown) STBC() bool { return known&RadioTapMCSKnownSTBC != 0 } +func (known RadioTapMCSKnown) NESS() bool { return known&RadioTapMCSKnownNESS != 0 } +func (known RadioTapMCSKnown) NESS1() bool { return known&RadioTapMCSKnownNESS1 != 0 } + +type RadioTapMCSFlags uint8 + +const ( + RadioTapMCSFlagsBandwidthMask RadioTapMCSFlags = 0x03 + RadioTapMCSFlagsShortGI = 0x04 + RadioTapMCSFlagsGreenfield = 0x08 + RadioTapMCSFlagsFECLDPC = 0x10 + RadioTapMCSFlagsSTBCMask = 0x60 + RadioTapMCSFlagsNESS0 = 0x80 +) + +func (flags RadioTapMCSFlags) Bandwidth() int { + return int(flags & RadioTapMCSFlagsBandwidthMask) +} +func (flags RadioTapMCSFlags) ShortGI() bool { return flags&RadioTapMCSFlagsShortGI != 0 } +func (flags RadioTapMCSFlags) Greenfield() bool { return flags&RadioTapMCSFlagsGreenfield != 0 } +func (flags RadioTapMCSFlags) FECLDPC() bool { return flags&RadioTapMCSFlagsFECLDPC != 0 } +func (flags RadioTapMCSFlags) STBC() int { + return int(flags&RadioTapMCSFlagsSTBCMask) >> 5 +} +func (flags RadioTapMCSFlags) NESS0() bool { return flags&RadioTapMCSFlagsNESS0 != 0 } + +type RadioTapAMPDUStatus struct { + Reference uint32 + Flags RadioTapAMPDUStatusFlags + CRC uint8 +} + +func (status RadioTapAMPDUStatus) String() string { + tokens := []string{ + fmt.Sprintf("ref#%x", status.Reference), + } + if status.Flags.ReportZerolen() && status.Flags.IsZerolen() { + tokens = append(tokens, "zero-length") + } + if status.Flags.LastKnown() && status.Flags.IsLast() { + tokens = append(tokens, "last") + } + if status.Flags.DelimCRCErr() { + tokens = append(tokens, "delimiter CRC error") + } + if status.Flags.DelimCRCKnown() { + tokens = append(tokens, fmt.Sprintf("delimiter-CRC=%02x", status.CRC)) + } + return strings.Join(tokens, ",") +} + +type RadioTapAMPDUStatusFlags uint16 + +const ( + RadioTapAMPDUStatusFlagsReportZerolen RadioTapAMPDUStatusFlags = 1 << iota + RadioTapAMPDUIsZerolen + RadioTapAMPDULastKnown + RadioTapAMPDUIsLast + RadioTapAMPDUDelimCRCErr + RadioTapAMPDUDelimCRCKnown +) + +func (flags RadioTapAMPDUStatusFlags) ReportZerolen() bool { + return flags&RadioTapAMPDUStatusFlagsReportZerolen != 0 +} +func (flags RadioTapAMPDUStatusFlags) IsZerolen() bool { return flags&RadioTapAMPDUIsZerolen != 0 } +func (flags RadioTapAMPDUStatusFlags) LastKnown() bool { return flags&RadioTapAMPDULastKnown != 0 } +func (flags RadioTapAMPDUStatusFlags) IsLast() bool { return flags&RadioTapAMPDUIsLast != 0 } +func (flags RadioTapAMPDUStatusFlags) DelimCRCErr() bool { return flags&RadioTapAMPDUDelimCRCErr != 0 } +func (flags RadioTapAMPDUStatusFlags) DelimCRCKnown() bool { + return flags&RadioTapAMPDUDelimCRCKnown != 0 +} + +type RadioTapVHT struct { + Known RadioTapVHTKnown + Flags RadioTapVHTFlags + Bandwidth uint8 + MCSNSS [4]RadioTapVHTMCSNSS + Coding uint8 + GroupId uint8 + PartialAID uint16 +} + +func (vht RadioTapVHT) String() string { + var tokens []string + if vht.Known.STBC() { + if vht.Flags.STBC() { + tokens = append(tokens, "STBC") + } else { + tokens = append(tokens, "no STBC") + } + } + if vht.Known.TXOPPSNotAllowed() { + if vht.Flags.TXOPPSNotAllowed() { + tokens = append(tokens, "TXOP doze not allowed") + } else { + tokens = append(tokens, "TXOP doze allowed") + } + } + if vht.Known.GI() { + if vht.Flags.SGI() { + tokens = append(tokens, "short GI") + } else { + tokens = append(tokens, "long GI") + } + } + if vht.Known.SGINSYMDisambiguation() { + if vht.Flags.SGINSYMMod() { + tokens = append(tokens, "NSYM mod 10=9") + } else { + tokens = append(tokens, "NSYM mod 10!=9 or no short GI") + } + } + if vht.Known.LDPCExtraOFDMSymbol() { + if vht.Flags.LDPCExtraOFDMSymbol() { + tokens = append(tokens, "LDPC extra OFDM symbols") + } else { + tokens = append(tokens, "no LDPC extra OFDM symbols") + } + } + if vht.Known.Beamformed() { + if vht.Flags.Beamformed() { + tokens = append(tokens, "beamformed") + } else { + tokens = append(tokens, "no beamformed") + } + } + if vht.Known.Bandwidth() { + token := "?" + switch vht.Bandwidth & 0x1f { + case 0: + token = "20" + case 1: + token = "40" + case 2: + token = "40(20L)" + case 3: + token = "40(20U)" + case 4: + token = "80" + case 5: + token = "80(40L)" + case 6: + token = "80(40U)" + case 7: + token = "80(20LL)" + case 8: + token = "80(20LU)" + case 9: + token = "80(20UL)" + case 10: + token = "80(20UU)" + case 11: + token = "160" + case 12: + token = "160(80L)" + case 13: + token = "160(80U)" + case 14: + token = "160(40LL)" + case 15: + token = "160(40LU)" + case 16: + token = "160(40UL)" + case 17: + token = "160(40UU)" + case 18: + token = "160(20LLL)" + case 19: + token = "160(20LLU)" + case 20: + token = "160(20LUL)" + case 21: + token = "160(20LUU)" + case 22: + token = "160(20ULL)" + case 23: + token = "160(20ULU)" + case 24: + token = "160(20UUL)" + case 25: + token = "160(20UUU)" + } + tokens = append(tokens, token) + } + for i, MCSNSS := range vht.MCSNSS { + if MCSNSS.Present() { + fec := "?" + switch vht.Coding & (1 << uint8(i)) { + case 0: + fec = "BCC" + case 1: + fec = "LDPC" + } + tokens = append(tokens, fmt.Sprintf("user%d(%s,%s)", i, MCSNSS.String(), fec)) + } + } + if vht.Known.GroupId() { + tokens = append(tokens, + fmt.Sprintf("group=%d", vht.GroupId)) + } + if vht.Known.PartialAID() { + tokens = append(tokens, + fmt.Sprintf("partial-AID=%d", vht.PartialAID)) + } + return strings.Join(tokens, ",") +} + +type RadioTapVHTKnown uint16 + +const ( + RadioTapVHTKnownSTBC RadioTapVHTKnown = 1 << iota + RadioTapVHTKnownTXOPPSNotAllowed + RadioTapVHTKnownGI + RadioTapVHTKnownSGINSYMDisambiguation + RadioTapVHTKnownLDPCExtraOFDMSymbol + RadioTapVHTKnownBeamformed + RadioTapVHTKnownBandwidth + RadioTapVHTKnownGroupId + RadioTapVHTKnownPartialAID +) + +func (self RadioTapVHTKnown) STBC() bool { return self&RadioTapVHTKnownSTBC != 0 } +func (self RadioTapVHTKnown) TXOPPSNotAllowed() bool { + return self&RadioTapVHTKnownTXOPPSNotAllowed != 0 +} +func (self RadioTapVHTKnown) GI() bool { return self&RadioTapVHTKnownGI != 0 } +func (self RadioTapVHTKnown) SGINSYMDisambiguation() bool { + return self&RadioTapVHTKnownSGINSYMDisambiguation != 0 +} +func (self RadioTapVHTKnown) LDPCExtraOFDMSymbol() bool { + return self&RadioTapVHTKnownLDPCExtraOFDMSymbol != 0 +} +func (self RadioTapVHTKnown) Beamformed() bool { return self&RadioTapVHTKnownBeamformed != 0 } +func (self RadioTapVHTKnown) Bandwidth() bool { return self&RadioTapVHTKnownBandwidth != 0 } +func (self RadioTapVHTKnown) GroupId() bool { return self&RadioTapVHTKnownGroupId != 0 } +func (self RadioTapVHTKnown) PartialAID() bool { return self&RadioTapVHTKnownPartialAID != 0 } + +type RadioTapVHTFlags uint8 + +const ( + RadioTapVHTFlagsSTBC RadioTapVHTFlags = 1 << iota + RadioTapVHTFlagsTXOPPSNotAllowed + RadioTapVHTFlagsSGI + RadioTapVHTFlagsSGINSYMMod + RadioTapVHTFlagsLDPCExtraOFDMSymbol + RadioTapVHTFlagsBeamformed +) + +func (self RadioTapVHTFlags) STBC() bool { return self&RadioTapVHTFlagsSTBC != 0 } +func (self RadioTapVHTFlags) TXOPPSNotAllowed() bool { + return self&RadioTapVHTFlagsTXOPPSNotAllowed != 0 +} +func (self RadioTapVHTFlags) SGI() bool { return self&RadioTapVHTFlagsSGI != 0 } +func (self RadioTapVHTFlags) SGINSYMMod() bool { return self&RadioTapVHTFlagsSGINSYMMod != 0 } +func (self RadioTapVHTFlags) LDPCExtraOFDMSymbol() bool { + return self&RadioTapVHTFlagsLDPCExtraOFDMSymbol != 0 +} +func (self RadioTapVHTFlags) Beamformed() bool { return self&RadioTapVHTFlagsBeamformed != 0 } + +type RadioTapVHTMCSNSS uint8 + +func (self RadioTapVHTMCSNSS) Present() bool { + return self&0x0F != 0 +} + +func (self RadioTapVHTMCSNSS) String() string { + return fmt.Sprintf("NSS#%dMCS#%d", uint32(self&0xf), uint32(self>>4)) +} + +type RadiotapHE struct { + Data1 RadiotapHEData1 + Data2 RadiotapHEData2 + Data3 RadiotapHEData3 + Data4 RadiotapHEData4 + Data5 RadiotapHEData5 + Data6 RadiotapHEData6 +} + +func (self RadiotapHE) String() string { + var tokens []string + tokens = append(tokens, fmt.Sprintf("HE PPDU Format: %v", self.Data1.HE_PPDUFormat())) + if self.Data1.BSSColorKnown() { + tokens = append(tokens, fmt.Sprintf("BSS Color: %d", self.Data3.BSSColor())) + } + if self.Data1.BeamChangeKnown() { + if self.Data3.BeamChange() { + tokens = append(tokens, "Beam Change") + } else { + tokens = append(tokens, "No Beam Change") + } + } + if self.Data1.ULDLKnown() { + if self.Data3.ULDL() { + tokens = append(tokens, "UL") + } else { + tokens = append(tokens, "DL") + } + } + if self.Data1.DataMCSKnown() { + tokens = append(tokens, fmt.Sprintf("Data MCS: %d", self.Data3.DataMCS())) + } + if self.Data1.DataDCMKnown() { + if self.Data3.DataDCM() { + tokens = append(tokens, "Data DCM applied") + } else { + tokens = append(tokens, "Data DCM not applied") + } + } + if self.Data1.CodingKnown() { + tokens = append(tokens, fmt.Sprintf("Coding: %v", self.Data3.Coding())) + } + if self.Data1.LDPCExtraSymbolSegmentKnown() { + if self.Data3.LDPCExtraSymbolSegment() { + tokens = append(tokens, "LDPC Extra Symbol Segment") + } else { + tokens = append(tokens, "No LDPC Extra Symbol Segment") + } + } + if self.Data1.STBCKnown() { + if self.Data3.STBC() { + tokens = append(tokens, "STBC") + } else { + tokens = append(tokens, "No STBC") + } + } + switch self.Data1.HE_PPDUFormat() { + case RadiotapHePpduFormatHE_SU: + case RadiotapHePpduFormatHE_EXT_SU: + if self.Data1.SpatialReuseKnown() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse: %d", self.Data4&0x000f)) + } + case RadiotapHePpduFormatHE_TRIG: + if self.Data1.SpatialReuse1Known() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse 1: %d", self.Data4&0x000f)) + } + if self.Data1.SpatialReuse2Known() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse 2: %d", self.Data4&0x00f0>>4)) + } + if self.Data1.SpatialReuse3Known() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse 3: %d", self.Data4&0x0f00>>8)) + } + if self.Data1.SpatialReuse4Known() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse 4: %d", self.Data4&0xf000>>12)) + } + case RadiotapHePpduFormatHE_MU: + if self.Data1.SpatialReuseKnown() { + tokens = append(tokens, fmt.Sprintf("Spatial Reuse: %d", self.Data4&0x000f)) + } + if self.Data1.StaIDKnown() { + tokens = append(tokens, fmt.Sprintf("STA ID: %d", self.Data4&0x7ff0>>4)) + } + } + if self.Data1.DataBWRUAllocationKnown() { + tokens = append(tokens, fmt.Sprintf("Data BW/RU Allocation: %s", self.Data5.DataBandwidth())) + } + if self.Data2.GIKnown() { + tokens = append(tokens, fmt.Sprintf("GI: %v", self.Data5.Gi())) + } + if self.Data2.NumLTFKnown() { + tokens = append(tokens, fmt.Sprintf("LTF Symbol size: %s", self.Data5.LTFSize())) + tokens = append(tokens, fmt.Sprintf("Number of LTF symbols: %s", self.Data5.NumLTFSymbols())) + } + if self.Data2.PreFECPaddingFactorKnown() { + tokens = append(tokens, fmt.Sprintf("Pre-FEC Padding Factor: %d", self.Data5.PreFECPaddingFactor())) + } + if self.Data2.TxBFKnown() { + if self.Data5.TxBF() { + tokens = append(tokens, "TxBF") + } else { + tokens = append(tokens, "No TxBF") + } + } + if self.Data2.PEDisambiguityKnown() { + if self.Data5.PEDisambiguity() { + tokens = append(tokens, "PE Disambiguity") + } else { + tokens = append(tokens, "No PE Disambiguity") + } + } + nSts := self.Data6.NSTS() + if nSts > 0 { + tokens = append(tokens, fmt.Sprintf("NSTS: %d", self.Data6.NSTS())) + } else { + tokens = append(tokens, "NSTS: unknown") + } + if self.Data1.DopplerKnown() { + if self.Data6.Doppler() { + tokens = append(tokens, "Doppler") + } else { + tokens = append(tokens, "No Doppler") + } + } + if self.Data2.TXOPKnown() { + tokens = append(tokens, fmt.Sprintf("TXOP: %d", self.Data6.TXOP())) + } + if self.Data2.MidamblePeriodicityKnown() { + tokens = append(tokens, fmt.Sprintf("Midamble Periodicity: %v", self.Data6.MidamblePeriodicity())) + } + return strings.Join(tokens, ",") +} + +type RadiotapHEData1 uint16 + +const ( + RadiotapHEData1_HE_PPDUFormatMask RadiotapHEData1 = 0x0003 + RadiotapHEData1BSSColorKnown RadiotapHEData1 = 0x0004 + RadiotapHEData1BeamChangeKnown RadiotapHEData1 = 0x0008 + RadiotapHEData1ULDLKnown RadiotapHEData1 = 0x0010 + RadiotapHEData1DataMCSKnown RadiotapHEData1 = 0x0020 + RadiotapHEData1DataDCMKnown RadiotapHEData1 = 0x0040 + RadiotapHEData1CodingKnown RadiotapHEData1 = 0x0080 + RadiotapHEData1LDPCExtraSymbolSegmentKnown RadiotapHEData1 = 0x0100 + RadiotapHEData1STBCKnown RadiotapHEData1 = 0x0200 + RadiotapHEData1SpatialReuseKnown RadiotapHEData1 = 0x0400 + RadiotapHEData1SpatialReuse1Known RadiotapHEData1 = 0x0400 + RadiotapHEData1SpatialReuse2Known RadiotapHEData1 = 0x0800 + RadiotapHEData1StaIDKnown RadiotapHEData1 = 0x8000 + RadiotapHEData1SpatialReuse3Known RadiotapHEData1 = 0x1000 + RadiotapHEData1SpatialReuse4Known RadiotapHEData1 = 0x2000 + RadiotapHEData1DataBWRUAllocationKnown RadiotapHEData1 = 0x4000 + RadiotapHEData1DopplerKnown RadiotapHEData1 = 0x8000 +) + +func (self RadiotapHEData1) HE_PPDUFormat() RadiotapHePpduFormat { + return RadiotapHePpduFormat(self & 0x0003) +} + +func (self RadiotapHEData1) BSSColorKnown() bool { + return self&RadiotapHEData1BSSColorKnown != 0 +} + +func (self RadiotapHEData1) BeamChangeKnown() bool { + return self&RadiotapHEData1BeamChangeKnown != 0 +} + +func (self RadiotapHEData1) ULDLKnown() bool { + return self&RadiotapHEData1ULDLKnown != 0 +} + +func (self RadiotapHEData1) DataMCSKnown() bool { + return self&RadiotapHEData1DataMCSKnown != 0 +} + +func (self RadiotapHEData1) DataDCMKnown() bool { + return self&RadiotapHEData1DataDCMKnown != 0 +} + +func (self RadiotapHEData1) CodingKnown() bool { + return self&RadiotapHEData1CodingKnown != 0 +} + +func (self RadiotapHEData1) LDPCExtraSymbolSegmentKnown() bool { + return self&RadiotapHEData1LDPCExtraSymbolSegmentKnown != 0 +} + +func (self RadiotapHEData1) STBCKnown() bool { + return self&RadiotapHEData1STBCKnown != 0 +} + +func (self RadiotapHEData1) SpatialReuseKnown() bool { + return self&RadiotapHEData1SpatialReuseKnown != 0 +} + +func (self RadiotapHEData1) SpatialReuse1Known() bool { + return self&RadiotapHEData1SpatialReuse1Known != 0 +} + +func (self RadiotapHEData1) SpatialReuse2Known() bool { + return self&RadiotapHEData1SpatialReuse2Known != 0 +} + +func (self RadiotapHEData1) StaIDKnown() bool { + return self&RadiotapHEData1StaIDKnown != 0 +} + +func (self RadiotapHEData1) SpatialReuse3Known() bool { + return self&RadiotapHEData1SpatialReuse3Known != 0 +} + +func (self RadiotapHEData1) SpatialReuse4Known() bool { + return self&RadiotapHEData1SpatialReuse4Known != 0 +} + +func (self RadiotapHEData1) DataBWRUAllocationKnown() bool { + return self&RadiotapHEData1DataBWRUAllocationKnown != 0 +} + +func (self RadiotapHEData1) DopplerKnown() bool { + return self&RadiotapHEData1DopplerKnown != 0 +} + +type RadiotapHePpduFormat uint8 + +const ( + RadiotapHePpduFormatHE_SU RadiotapHePpduFormat = iota + RadiotapHePpduFormatHE_EXT_SU + RadiotapHePpduFormatHE_MU + RadiotapHePpduFormatHE_TRIG +) + +func (self RadiotapHePpduFormat) String() string { + switch self { + case RadiotapHePpduFormatHE_SU: + return "HE SU" + case RadiotapHePpduFormatHE_EXT_SU: + return "HE EXT SU" + case RadiotapHePpduFormatHE_MU: + return "HE MU" + case RadiotapHePpduFormatHE_TRIG: + return "HE TRIG" + } + return fmt.Sprintf("HE Unknown(%d)", self) +} + +type RadiotapHEData2 uint16 + +const ( + RadiotapHEData2PriSec80MHzKnown RadiotapHEData2 = 0x0001 + RadiotapHEData2GIKnown RadiotapHEData2 = 0x0002 + RadiotapHEData2NumLTFKnown RadiotapHEData2 = 0x0004 + RadiotapHEData2PreFECPaddingFactorKnown RadiotapHEData2 = 0x0008 + RadiotapHEData2TxBFKnown RadiotapHEData2 = 0x0010 + RadiotapHEData2PEDisambiguityKnown RadiotapHEData2 = 0x0020 + RadiotapHEData2TXOPKnown RadiotapHEData2 = 0x0040 + RadiotapHEData2MidamblePeriodicityKnown RadiotapHEData2 = 0x0080 + RadiotapHEData2RUAllocationOffset RadiotapHEData2 = 0x3f00 + RadiotapHEData2RUAllocationOffsetKnown RadiotapHEData2 = 0x4000 + RadiotapHEData2PriSec80MHz RadiotapHEData2 = 0x8000 +) + +func (self RadiotapHEData2) PriSec80MHzKnown() bool { + return self&RadiotapHEData2PriSec80MHzKnown != 0 +} + +func (self RadiotapHEData2) GIKnown() bool { + return self&RadiotapHEData2GIKnown != 0 +} + +func (self RadiotapHEData2) NumLTFKnown() bool { + return self&RadiotapHEData2NumLTFKnown != 0 +} + +func (self RadiotapHEData2) PreFECPaddingFactorKnown() bool { + return self&RadiotapHEData2PreFECPaddingFactorKnown != 0 +} + +func (self RadiotapHEData2) TxBFKnown() bool { + return self&RadiotapHEData2TxBFKnown != 0 +} + +func (self RadiotapHEData2) PEDisambiguityKnown() bool { + return self&RadiotapHEData2PEDisambiguityKnown != 0 +} + +func (self RadiotapHEData2) TXOPKnown() bool { + return self&RadiotapHEData2TXOPKnown != 0 +} + +func (self RadiotapHEData2) MidamblePeriodicityKnown() bool { + return self&RadiotapHEData2MidamblePeriodicityKnown != 0 +} + +func (self RadiotapHEData2) RUAllocationOffset() int { + return int(self&RadiotapHEData2RUAllocationOffset) >> 8 +} + +func (self RadiotapHEData2) RUAllocationOffsetKnown() bool { + return self&RadiotapHEData2RUAllocationOffsetKnown != 0 +} + +func (self RadiotapHEData2) PriSec80MHz() bool { + return self&RadiotapHEData2PriSec80MHz != 0 +} + +type RadiotapHEPriSec80MHz bool + +type RadiotapHEData3 uint16 + +const ( + RadiotapHEData3BSSColorMask RadiotapHEData3 = 0x003F + RadiotapHEData3BeamChange RadiotapHEData3 = 0x0040 + RadiotapHEData3ULDL RadiotapHEData3 = 0x0080 + RadiotapHEData3DataMCSMask RadiotapHEData3 = 0x0F00 + RadiotapHEData3DataDCM RadiotapHEData3 = 0x1000 + RadiotapHEData3Coding RadiotapHEData3 = 0x2000 + RadiotapHEData3LDPCEXtraSymbolSegment RadiotapHEData3 = 0x4000 + RadiotapHEData3STBC RadiotapHEData3 = 0x8000 +) + +func (self RadiotapHEData3) BSSColor() int { + return int(self & RadiotapHEData3BSSColorMask) +} + +func (self RadiotapHEData3) BeamChange() bool { + return self&RadiotapHEData3BeamChange != 0 +} + +func (self RadiotapHEData3) ULDL() bool { + return self&RadiotapHEData3ULDL != 0 +} + +func (self RadiotapHEData3) DataMCS() uint8 { + return uint8((self & RadiotapHEData3DataMCSMask) >> 8) +} + +func (self RadiotapHEData3) DataDCM() bool { + return self&RadiotapHEData3DataDCM != 0 +} + +func (self RadiotapHEData3) Coding() RadiotapHECoding { + return self&RadiotapHEData3Coding != 0 +} + +func (self RadiotapHEData3) LDPCExtraSymbolSegment() bool { + return self&RadiotapHEData3LDPCEXtraSymbolSegment != 0 +} + +func (self RadiotapHEData3) STBC() bool { + return self&RadiotapHEData3STBC != 0 +} + +type RadiotapHECoding bool + +const ( + RadiotapHECodingBCC RadiotapHECoding = false + RadiotapHECodingLDPC RadiotapHECoding = true +) + +type RadiotapHEData4 uint16 + +type RadiotapHEData5 uint16 + +const ( + RadiotapHEData5DataBandwidthMask RadiotapHEData5 = 0x000F + RadiotapHEData5GI RadiotapHEData5 = 0x0030 + RadiotapHEData5LTFSize RadiotapHEData5 = 0x00C0 + RadiotapHEData5NumLTFSymbols RadiotapHEData5 = 0x0700 + RadiotapHEData5PreFECPaddingFactor RadiotapHEData5 = 0x3000 + RadiotapHEData5TxBF RadiotapHEData5 = 0x4000 + RadiotapHEData5PEDisambiguity RadiotapHEData5 = 0x8000 +) + +type DataBandwidth uint8 + +const ( + DataBandwidth20 DataBandwidth = iota + DataBandwidth40 + DataBandwidth80 + DataBandwidth160 + DataBandwidth26ToneRU + DataBandwidth52ToneRU + DataBandwidth106ToneRU + DataBandwidth242ToneRU + DataBandwidth484ToneRU + DataBandwidth996ToneRU + DataBandwidth2x996ToneRU +) + +func (db DataBandwidth) String() string { + switch db { + case DataBandwidth20: + return "20" + case DataBandwidth40: + return "40" + case DataBandwidth80: + return "80" + case DataBandwidth160: + return "160/80+80" + case DataBandwidth26ToneRU: + return "26-tone RU" + case DataBandwidth52ToneRU: + return "52-tone RU" + case DataBandwidth106ToneRU: + return "106-tone RU" + case DataBandwidth242ToneRU: + return "242-tone RU" + case DataBandwidth484ToneRU: + return "484-tone RU" + case DataBandwidth996ToneRU: + return "996-tone RU" + case DataBandwidth2x996ToneRU: + return "2x996-tone RU" + default: + return "Unknown" + } +} + +func (self RadiotapHEData5) DataBandwidth() DataBandwidth { + return DataBandwidth(self & RadiotapHEData5DataBandwidthMask) +} + +func (self RadiotapHEData5) Gi() Gi { + return Gi((self & RadiotapHEData5GI) >> 4) +} + +func (self RadiotapHEData5) LTFSize() LTF { + return LTF((self & RadiotapHEData5LTFSize) >> 6) +} + +func (self RadiotapHEData5) NumLTFSymbols() NLTF { + return NLTF((self & RadiotapHEData5NumLTFSymbols) >> 8) +} + +func (self RadiotapHEData5) PreFECPaddingFactor() uint8 { + return uint8((self & RadiotapHEData5PreFECPaddingFactor) >> 12) +} + +func (self RadiotapHEData5) TxBF() bool { + return self&RadiotapHEData5TxBF != 0 +} + +func (self RadiotapHEData5) PEDisambiguity() bool { + return self&RadiotapHEData5PEDisambiguity != 0 +} + +type Gi uint8 + +const ( + Gi_0_8us Gi = iota + Gi_1_6us + Gi_3_2us + Gi_reserved +) + +func (gi Gi) String() string { + switch gi { + case Gi_0_8us: + return "0.8us" + case Gi_1_6us: + return "1.6us" + case Gi_3_2us: + return "3.2us" + default: + return "Reserved" + } +} + +type LTF uint8 + +const ( + LTF_unknown LTF = iota + LTF_1x + LTF_2x + LTF_4x +) + +func (ltf LTF) String() string { + switch ltf { + case LTF_unknown: + return "Unknown" + case LTF_1x: + return "1x" + case LTF_2x: + return "2x" + case LTF_4x: + return "4x" + default: + return "Unknown" + } +} + +type NLTF uint8 + +const ( + NLTF_1x NLTF = iota + NLTF_2x + NLTF_4x + NLTF_6x + NLTF_8x + NLTF_reserved +) + +func (nltf NLTF) String() string { + switch nltf { + case NLTF_1x: + return "1x" + case NLTF_2x: + return "2x" + case NLTF_4x: + return "4x" + case NLTF_6x: + return "6x" + case NLTF_8x: + return "8x" + default: + return "Reserved" + } +} + +type MidamblePeriodicity uint8 + +const ( + MidamblePeriodicity_10 MidamblePeriodicity = iota + MidamblePeriodicity_20 +) + +func (mp MidamblePeriodicity) String() string { + switch mp { + case MidamblePeriodicity_10: + return "10" + case MidamblePeriodicity_20: + return "20" + default: + return "Unknown" + } +} + +type RadiotapHEData6 uint16 + +const ( + RadiotapHEData6NSTS RadiotapHEData6 = 0x000F + RadiotapHEData6Doppler RadiotapHEData6 = 0x0010 + RadiotapHEData6TXOP RadiotapHEData6 = 0x7F00 + RadiotapHEData6MidamblePeriodic RadiotapHEData6 = 0x8000 +) + +func (self RadiotapHEData6) NSTS() int { + return int(self & RadiotapHEData6NSTS) +} + +func (self RadiotapHEData6) Doppler() bool { + return self&RadiotapHEData6Doppler != 0 +} + +func (self RadiotapHEData6) TXOP() int { + return int((self & RadiotapHEData6TXOP) >> 8) +} + +func (self RadiotapHEData6) MidamblePeriodicity() MidamblePeriodicity { + return MidamblePeriodicity((self & RadiotapHEData6MidamblePeriodic) >> 15) +} + +func decodeRadioTap(data []byte, p gopacket.PacketBuilder) error { + d := &RadioTap{} + // TODO: Should we set LinkLayer here? And implement LinkFlow + return decodingLayerDecoder(d, data, p) +} + +type RadioTapNamespace struct { + // TSFT: value in microseconds of the MAC's 64-bit 802.11 Time Synchronization Function timer when the first bit of the MPDU arrived at the MAC. For received frames, only. + TSFT uint64 + Flags RadioTapFlags + // Rate Tx/Rx data rate + Rate RadioTapRate + // ChannelFrequency Tx/Rx frequency in MHz, followed by flags + ChannelFrequency RadioTapChannelFrequency + ChannelFlags RadioTapChannelFlags + // FHSS For frequency-hopping radios, the hop set (first byte) and pattern (second byte). + FHSS uint16 + // DBMAntennaSignal RF signal power at the antenna, decibel difference from one milliwatt. + DBMAntennaSignal int8 + // DBMAntennaNoise RF noise power at the antenna, decibel difference from one milliwatt. + DBMAntennaNoise int8 + // LockQuality Quality of Barker code lock. Unitless. Monotonically nondecreasing with "better" lock strength. Called "Signal Quality" in datasheets. + LockQuality uint16 + // TxAttenuation Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels. + TxAttenuation uint16 + // DBTxAttenuation Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels. + DBTxAttenuation uint16 + // DBMTxPower Transmit power expressed as dBm (decibels from a 1 milliwatt reference). This is the absolute power level measured at the antenna port. + DBMTxPower int8 + // Antenna Unitless indication of the Rx/Tx antenna for this packet. The first antenna is antenna 0. + Antenna uint8 + // DBAntennaSignal RF signal power at the antenna, decibel difference from an arbitrary, fixed reference. + DBAntennaSignal uint8 + // DBAntennaNoise RF noise power at the antenna, decibel difference from an arbitrary, fixed reference point. + DBAntennaNoise uint8 + // + RxFlags RadioTapRxFlags + TxFlags RadioTapTxFlags + RtsRetries uint8 + DataRetries uint8 + MCS RadioTapMCS + AMPDUStatus RadioTapAMPDUStatus + VHT RadioTapVHT + HE RadiotapHE +} + +type VendorNamespace struct { + OUI []uint8 // The vendor's Organizationally Unique Identifier + SubNamespace uint8 // Selector to determine which vendor-specific namespace the fields represent + SkipLength uint16 // Amount of data present for this vendor namespace (does not include the header size of the vendor namespace field itself) + Contents []uint8 // The custom data for the vendor namespace. This library does not yet attempt to parse specific vendor fields. +} + +type RadioTap struct { + BaseLayer + + // Version 0. Only increases for drastic changes, introduction of compatible new fields does not count. + Version uint8 + // Length of the whole header in bytes, including it_version, it_pad, it_len, and data fields. + Length uint16 + // Present is a bitmap telling which fields are present. Set bit 31 (0x80000000) to extend the bitmap by another 32 bits. Additional extensions are made by setting bit 31. + Present []RadioTapPresent + // Multiple segments of the defined RadioTap fields can be present, if the extension bit and RadioTap namespace bit are both set. + RadioTapValues []RadioTapNamespace + // Multiple segments of fields defined by the hardware vendor of the packet sending hardware can be included, if the extension bit and vendor namespace bit are both set. + VendorValues []VendorNamespace +} + +func (m *RadioTap) LayerType() gopacket.LayerType { return LayerTypeRadioTap } + +func (m *RadioTap) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + dataLen := uint16(len(data)) + if dataLen < 8 { + df.SetTruncated() + return errors.New("RadioTap too small") + } + m.Version = uint8(data[0]) + m.Length = binary.LittleEndian.Uint16(data[2:4]) + + // Truncate the length to avoid panics, might be smaller due to corruption or loss + if m.Length > dataLen { + m.Length = dataLen + } + + // at least one present field will always be included, but we parse out the rest as well + offset := uint16(4) + m.Present = []RadioTapPresent{RadioTapPresent(binary.LittleEndian.Uint32(data[offset : offset+4]))} + for (m.Present[len(m.Present)-1] & RadioTapPresentEXT) != 0 { + // This parser only handles standard radiotap namespace, + // and expects all fields are packed in the first it_present. + // Extended bitmap will be just ignored. + offset += 4 + m.Present = append(m.Present, RadioTapPresent(binary.LittleEndian.Uint32(data[offset:offset+4]))) + } + offset += 4 // move past the previous present bitmap + + // now we extract a namespace for each Present bitmap, the first is always a radio tap namespace + radioTapNamespace := true + vendorNamespace := false + for _, present := range m.Present { + if radioTapNamespace { + rValues, newOffset := RadioTapNamespace{}.decodeRadioTapNamespace(data, offset, present) + m.RadioTapValues = append(m.RadioTapValues, rValues) + offset = newOffset + } else if vendorNamespace { + vValues, newOffset := VendorNamespace{}.decodeVendorNamespace(data, offset, present) + m.VendorValues = append(m.VendorValues, vValues) + offset = newOffset + } else { + // TODO: this library does not yet handle fields defined on bits higher than 31, just break for now + break + } + + // Also break for now on present that doesn't extend, even if there's more present beyond it + if !present.EXT() { + break + } + + // determine what the next namespace to add will be + radioTapNamespace = present.RadioTapNamespace() + vendorNamespace = present.VendorNamespace() + } + + payload := data[m.Length:] + + // Remove non standard padding used by some Wi-Fi drivers + if m.RadioTapValues[0].Flags.Datapad() && + payload[0]&0xC == 0x8 { //&& // Data frame + headlen := 24 + if payload[0]&0x8C == 0x88 { // QoS + headlen += 2 + } + if payload[1]&0x3 == 0x3 { // 4 addresses + headlen += 2 + } + if headlen%4 == 2 { + payload = append(payload[:headlen], payload[headlen+2:len(payload)]...) + } + } + + if !m.RadioTapValues[0].Flags.FCS() { + // Dot11.DecodeFromBytes() expects FCS present and performs a hard chop on the checksum + // If a user is handing in subslices or packets from a buffered stream, the capacity of the slice + // may extend beyond the len, rather than expecting callers to enforce cap==len on every packet + // we take the hit in this one case and do a reallocation. If the user DOES enforce cap==len + // then the reallocation will happen anyway on the append. This is requried because the append + // write to the memory directly after the payload if there is sufficient capacity, which callers + // may not expect. + reallocPayload := make([]byte, len(payload)+4) + copy(reallocPayload[0:len(payload)], payload) + h := crc32.NewIEEE() + h.Write(payload) + binary.LittleEndian.PutUint32(reallocPayload[len(payload):], h.Sum32()) + payload = reallocPayload + } + m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: payload} + + return nil +} + +func (m RadioTapNamespace) decodeRadioTapNamespace(data []byte, offset uint16, present RadioTapPresent) (RadioTapNamespace, uint16) { + if present.TSFT() { + offset += align(offset, 8) + m.TSFT = binary.LittleEndian.Uint64(data[offset : offset+8]) + offset += 8 + } + if present.Flags() { + m.Flags = RadioTapFlags(data[offset]) + offset++ + } + if present.Rate() { + m.Rate = RadioTapRate(data[offset]) + offset++ + } + if present.Channel() { + offset += align(offset, 2) + m.ChannelFrequency = RadioTapChannelFrequency(binary.LittleEndian.Uint16(data[offset : offset+2])) + offset += 2 + m.ChannelFlags = RadioTapChannelFlags(binary.LittleEndian.Uint16(data[offset : offset+2])) + offset += 2 + } + if present.FHSS() { + m.FHSS = binary.LittleEndian.Uint16(data[offset : offset+2]) + offset += 2 + } + if present.DBMAntennaSignal() { + m.DBMAntennaSignal = int8(data[offset]) + offset++ + } + if present.DBMAntennaNoise() { + m.DBMAntennaNoise = int8(data[offset]) + offset++ + } + if present.LockQuality() { + offset += align(offset, 2) + m.LockQuality = binary.LittleEndian.Uint16(data[offset : offset+2]) + offset += 2 + } + if present.TxAttenuation() { + offset += align(offset, 2) + m.TxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2]) + offset += 2 + } + if present.DBTxAttenuation() { + offset += align(offset, 2) + m.DBTxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2]) + offset += 2 + } + if present.DBMTxPower() { + m.DBMTxPower = int8(data[offset]) + offset++ + } + if present.Antenna() { + m.Antenna = uint8(data[offset]) + offset++ + } + if present.DBAntennaSignal() { + m.DBAntennaSignal = uint8(data[offset]) + offset++ + } + if present.DBAntennaNoise() { + m.DBAntennaNoise = uint8(data[offset]) + offset++ + } + if present.RxFlags() { + offset += align(offset, 2) + m.RxFlags = RadioTapRxFlags(binary.LittleEndian.Uint16(data[offset:])) + offset += 2 + } + if present.TxFlags() { + offset += align(offset, 2) + m.TxFlags = RadioTapTxFlags(binary.LittleEndian.Uint16(data[offset:])) + offset += 2 + } + if present.RtsRetries() { + m.RtsRetries = uint8(data[offset]) + offset++ + } + if present.DataRetries() { + m.DataRetries = uint8(data[offset]) + offset++ + } + if present.MCS() { + m.MCS = RadioTapMCS{ + RadioTapMCSKnown(data[offset]), + RadioTapMCSFlags(data[offset+1]), + uint8(data[offset+2]), + } + offset += 3 + } + if present.AMPDUStatus() { + offset += align(offset, 4) + m.AMPDUStatus = RadioTapAMPDUStatus{ + Reference: binary.LittleEndian.Uint32(data[offset:]), + Flags: RadioTapAMPDUStatusFlags(binary.LittleEndian.Uint16(data[offset+4:])), + CRC: uint8(data[offset+6]), + } + offset += 8 + } + if present.VHT() { + offset += align(offset, 2) + m.VHT = RadioTapVHT{ + Known: RadioTapVHTKnown(binary.LittleEndian.Uint16(data[offset:])), + Flags: RadioTapVHTFlags(data[offset+2]), + Bandwidth: uint8(data[offset+3]), + MCSNSS: [4]RadioTapVHTMCSNSS{ + RadioTapVHTMCSNSS(data[offset+4]), + RadioTapVHTMCSNSS(data[offset+5]), + RadioTapVHTMCSNSS(data[offset+6]), + RadioTapVHTMCSNSS(data[offset+7]), + }, + Coding: uint8(data[offset+8]), + GroupId: uint8(data[offset+9]), + PartialAID: binary.LittleEndian.Uint16(data[offset+10:]), + } + offset += 12 + } + if present.Timestamp() { + offset += align(offset, 8) + offset += 12 + } + if present.HE() { + offset += align(offset, 2) + m.HE = RadiotapHE{ + Data1: RadiotapHEData1(binary.LittleEndian.Uint16(data[offset:])), + Data2: RadiotapHEData2(binary.LittleEndian.Uint16(data[offset+2:])), + Data3: RadiotapHEData3(binary.LittleEndian.Uint16(data[offset+4:])), + Data4: RadiotapHEData4(binary.LittleEndian.Uint16(data[offset+6:])), + Data5: RadiotapHEData5(binary.LittleEndian.Uint16(data[offset+8:])), + Data6: RadiotapHEData6(binary.LittleEndian.Uint16(data[offset+10:])), + } + offset += 12 + } + + return m, offset +} + +func (v VendorNamespace) decodeVendorNamespace(data []byte, offset uint16, present RadioTapPresent) (VendorNamespace, uint16) { + offset += align(offset, 2) + + v.OUI = data[offset : offset+3] + offset += 4 + + v.SubNamespace = data[offset] + offset += 2 + + v.SkipLength = binary.LittleEndian.Uint16(data[offset:]) + offset += 2 + + v.Contents = data[offset : offset+v.SkipLength] + offset += v.SkipLength + + return v, offset +} + +func (m RadioTap) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + buf := make([]byte, 1024) + + buf[0] = m.Version + buf[1] = 0 + + // save length encoding for the end when it's easier to know how long everything is + + // encode full present bitmap + offset := uint16(4) + for _, present := range m.Present { + binary.LittleEndian.PutUint32(buf[offset:offset+4], uint32(present)) + offset += 4 + } + + // encode namespace values, alternating according to the namespace bits in the present bitmap + // first namespace will always be a radio tap namespace + radioTapNamespace := true + vendorNamespace := false + radioTapNamespaceIndex := 0 + vendorNamespaceIndex := 0 + for _, present := range m.Present { + if radioTapNamespace { + offset = m.RadioTapValues[radioTapNamespaceIndex].serializeTo(buf, offset, present) + radioTapNamespaceIndex += 1 + } else if vendorNamespace { + offset = m.VendorValues[vendorNamespaceIndex].serializeTo(buf, offset, present) + vendorNamespaceIndex += 1 + } else { + // TODO: this library does not yet handle fields defined on bits higher than 31, just break for now + break + } + + radioTapNamespace = present.RadioTapNamespace() + vendorNamespace = present.VendorNamespace() + } + + packetBuf, err := b.PrependBytes(int(offset)) + + if err != nil { + return err + } + + if opts.FixLengths { + m.Length = offset + } + + binary.LittleEndian.PutUint16(buf[2:4], m.Length) + + copy(packetBuf, buf) + + return nil +} + +func (m RadioTapNamespace) serializeTo(buf []byte, offset uint16, present RadioTapPresent) uint16 { + if present.TSFT() { + offset += align(offset, 8) + binary.LittleEndian.PutUint64(buf[offset:offset+8], m.TSFT) + offset += 8 + } + + if present.Flags() { + buf[offset] = uint8(m.Flags) + offset++ + } + + if present.Rate() { + buf[offset] = uint8(m.Rate) + offset++ + } + + if present.Channel() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFrequency)) + offset += 2 + binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFlags)) + offset += 2 + } + + if present.FHSS() { + binary.LittleEndian.PutUint16(buf[offset:offset+2], m.FHSS) + offset += 2 + } + + if present.DBMAntennaSignal() { + buf[offset] = byte(m.DBMAntennaSignal) + offset++ + } + + if present.DBMAntennaNoise() { + buf[offset] = byte(m.DBMAntennaNoise) + offset++ + } + + if present.LockQuality() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], m.LockQuality) + offset += 2 + } + + if present.TxAttenuation() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], m.TxAttenuation) + offset += 2 + } + + if present.DBTxAttenuation() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], m.DBTxAttenuation) + offset += 2 + } + + if present.DBMTxPower() { + buf[offset] = byte(m.DBMTxPower) + offset++ + } + + if present.Antenna() { + buf[offset] = uint8(m.Antenna) + offset++ + } + + if present.DBAntennaSignal() { + buf[offset] = uint8(m.DBAntennaSignal) + offset++ + } + + if present.DBAntennaNoise() { + buf[offset] = uint8(m.DBAntennaNoise) + offset++ + } + + if present.RxFlags() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.RxFlags)) + offset += 2 + } + + if present.TxFlags() { + offset += align(offset, 2) + binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.TxFlags)) + offset += 2 + } + + if present.RtsRetries() { + buf[offset] = m.RtsRetries + offset++ + } + + if present.DataRetries() { + buf[offset] = m.DataRetries + offset++ + } + + if present.MCS() { + buf[offset] = uint8(m.MCS.Known) + buf[offset+1] = uint8(m.MCS.Flags) + buf[offset+2] = uint8(m.MCS.MCS) + + offset += 3 + } + + if present.AMPDUStatus() { + offset += align(offset, 4) + + binary.LittleEndian.PutUint32(buf[offset:offset+4], m.AMPDUStatus.Reference) + binary.LittleEndian.PutUint16(buf[offset+4:offset+6], uint16(m.AMPDUStatus.Flags)) + + buf[offset+6] = m.AMPDUStatus.CRC + + offset += 8 + } + + if present.VHT() { + offset += align(offset, 2) + + binary.LittleEndian.PutUint16(buf[offset:], uint16(m.VHT.Known)) + + buf[offset+2] = uint8(m.VHT.Flags) + buf[offset+3] = uint8(m.VHT.Bandwidth) + buf[offset+4] = uint8(m.VHT.MCSNSS[0]) + buf[offset+5] = uint8(m.VHT.MCSNSS[1]) + buf[offset+6] = uint8(m.VHT.MCSNSS[2]) + buf[offset+7] = uint8(m.VHT.MCSNSS[3]) + buf[offset+8] = uint8(m.VHT.Coding) + buf[offset+9] = uint8(m.VHT.GroupId) + + binary.LittleEndian.PutUint16(buf[offset+10:offset+12], m.VHT.PartialAID) + + offset += 12 + } + + if present.Timestamp() { + offset += align(offset, 8) + offset += 12 + } + + if present.HE() { + offset += align(offset, 2) + + binary.LittleEndian.PutUint16(buf[offset:], uint16(m.HE.Data1)) + binary.LittleEndian.PutUint16(buf[offset+2:], uint16(m.HE.Data2)) + binary.LittleEndian.PutUint16(buf[offset+4:], uint16(m.HE.Data3)) + binary.LittleEndian.PutUint16(buf[offset+6:], uint16(m.HE.Data4)) + binary.LittleEndian.PutUint16(buf[offset+8:], uint16(m.HE.Data5)) + binary.LittleEndian.PutUint16(buf[offset+10:], uint16(m.HE.Data6)) + offset += 12 + } + + return offset +} + +func (v VendorNamespace) serializeTo(buf []byte, offset uint16, present RadioTapPresent) uint16 { + offset += align(offset, 2) + + copy(buf[offset:], v.OUI[0:3]) + offset += 4 + buf[offset] = v.SubNamespace + offset += 2 + binary.LittleEndian.PutUint16(buf[offset:], v.SkipLength) + offset += 2 + copy(buf[offset:], v.Contents) + offset += v.SkipLength + + return offset +} + +func (m *RadioTap) CanDecode() gopacket.LayerClass { return LayerTypeRadioTap } +func (m *RadioTap) NextLayerType() gopacket.LayerType { return LayerTypeDot11 } diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radius.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radius.go new file mode 100644 index 0000000000..f2cd280cb5 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/radius.go @@ -0,0 +1,560 @@ +// Copyright 2020 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. + +package layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +const ( + // RFC 2865 3. Packet Format + // `The minimum length is 20 and maximum length is 4096.` + radiusMinimumRecordSizeInBytes int = 20 + radiusMaximumRecordSizeInBytes int = 4096 + + // RFC 2865 5. Attributes + // `The Length field is one octet, and indicates the length of this Attribute including the Type, Length and Value fields.` + // `The Value field is zero or more octets and contains information specific to the Attribute.` + radiusAttributesMinimumRecordSizeInBytes int = 2 +) + +// RADIUS represents a Remote Authentication Dial In User Service layer. +type RADIUS struct { + BaseLayer + + Code RADIUSCode + Identifier RADIUSIdentifier + Length RADIUSLength + Authenticator RADIUSAuthenticator + Attributes []RADIUSAttribute +} + +// RADIUSCode represents packet type. +type RADIUSCode uint8 + +// constants that define RADIUSCode. +const ( + RADIUSCodeAccessRequest RADIUSCode = 1 // RFC2865 3. Packet Format + RADIUSCodeAccessAccept RADIUSCode = 2 // RFC2865 3. Packet Format + RADIUSCodeAccessReject RADIUSCode = 3 // RFC2865 3. Packet Format + RADIUSCodeAccountingRequest RADIUSCode = 4 // RFC2865 3. Packet Format + RADIUSCodeAccountingResponse RADIUSCode = 5 // RFC2865 3. Packet Format + RADIUSCodeAccessChallenge RADIUSCode = 11 // RFC2865 3. Packet Format + RADIUSCodeStatusServer RADIUSCode = 12 // RFC2865 3. Packet Format (experimental) + RADIUSCodeStatusClient RADIUSCode = 13 // RFC2865 3. Packet Format (experimental) + RADIUSCodeReserved RADIUSCode = 255 // RFC2865 3. Packet Format +) + +// String returns a string version of a RADIUSCode. +func (t RADIUSCode) String() (s string) { + switch t { + case RADIUSCodeAccessRequest: + s = "Access-Request" + case RADIUSCodeAccessAccept: + s = "Access-Accept" + case RADIUSCodeAccessReject: + s = "Access-Reject" + case RADIUSCodeAccountingRequest: + s = "Accounting-Request" + case RADIUSCodeAccountingResponse: + s = "Accounting-Response" + case RADIUSCodeAccessChallenge: + s = "Access-Challenge" + case RADIUSCodeStatusServer: + s = "Status-Server" + case RADIUSCodeStatusClient: + s = "Status-Client" + case RADIUSCodeReserved: + s = "Reserved" + default: + s = fmt.Sprintf("Unknown(%d)", t) + } + return +} + +// RADIUSIdentifier represents packet identifier. +type RADIUSIdentifier uint8 + +// RADIUSLength represents packet length. +type RADIUSLength uint16 + +// RADIUSAuthenticator represents authenticator. +type RADIUSAuthenticator [16]byte + +// RADIUSAttribute represents attributes. +type RADIUSAttribute struct { + Type RADIUSAttributeType + Length RADIUSAttributeLength + Value RADIUSAttributeValue +} + +// RADIUSAttributeType represents attribute type. +type RADIUSAttributeType uint8 + +// constants that define RADIUSAttributeType. +const ( + RADIUSAttributeTypeUserName RADIUSAttributeType = 1 // RFC2865 5.1. User-Name + RADIUSAttributeTypeUserPassword RADIUSAttributeType = 2 // RFC2865 5.2. User-Password + RADIUSAttributeTypeCHAPPassword RADIUSAttributeType = 3 // RFC2865 5.3. CHAP-Password + RADIUSAttributeTypeNASIPAddress RADIUSAttributeType = 4 // RFC2865 5.4. NAS-IP-Address + RADIUSAttributeTypeNASPort RADIUSAttributeType = 5 // RFC2865 5.5. NAS-Port + RADIUSAttributeTypeServiceType RADIUSAttributeType = 6 // RFC2865 5.6. Service-Type + RADIUSAttributeTypeFramedProtocol RADIUSAttributeType = 7 // RFC2865 5.7. Framed-Protocol + RADIUSAttributeTypeFramedIPAddress RADIUSAttributeType = 8 // RFC2865 5.8. Framed-IP-Address + RADIUSAttributeTypeFramedIPNetmask RADIUSAttributeType = 9 // RFC2865 5.9. Framed-IP-Netmask + RADIUSAttributeTypeFramedRouting RADIUSAttributeType = 10 // RFC2865 5.10. Framed-Routing + RADIUSAttributeTypeFilterId RADIUSAttributeType = 11 // RFC2865 5.11. Filter-Id + RADIUSAttributeTypeFramedMTU RADIUSAttributeType = 12 // RFC2865 5.12. Framed-MTU + RADIUSAttributeTypeFramedCompression RADIUSAttributeType = 13 // RFC2865 5.13. Framed-Compression + RADIUSAttributeTypeLoginIPHost RADIUSAttributeType = 14 // RFC2865 5.14. Login-IP-Host + RADIUSAttributeTypeLoginService RADIUSAttributeType = 15 // RFC2865 5.15. Login-Service + RADIUSAttributeTypeLoginTCPPort RADIUSAttributeType = 16 // RFC2865 5.16. Login-TCP-Port + RADIUSAttributeTypeReplyMessage RADIUSAttributeType = 18 // RFC2865 5.18. Reply-Message + RADIUSAttributeTypeCallbackNumber RADIUSAttributeType = 19 // RFC2865 5.19. Callback-Number + RADIUSAttributeTypeCallbackId RADIUSAttributeType = 20 // RFC2865 5.20. Callback-Id + RADIUSAttributeTypeFramedRoute RADIUSAttributeType = 22 // RFC2865 5.22. Framed-Route + RADIUSAttributeTypeFramedIPXNetwork RADIUSAttributeType = 23 // RFC2865 5.23. Framed-IPX-Network + RADIUSAttributeTypeState RADIUSAttributeType = 24 // RFC2865 5.24. State + RADIUSAttributeTypeClass RADIUSAttributeType = 25 // RFC2865 5.25. Class + RADIUSAttributeTypeVendorSpecific RADIUSAttributeType = 26 // RFC2865 5.26. Vendor-Specific + RADIUSAttributeTypeSessionTimeout RADIUSAttributeType = 27 // RFC2865 5.27. Session-Timeout + RADIUSAttributeTypeIdleTimeout RADIUSAttributeType = 28 // RFC2865 5.28. Idle-Timeout + RADIUSAttributeTypeTerminationAction RADIUSAttributeType = 29 // RFC2865 5.29. Termination-Action + RADIUSAttributeTypeCalledStationId RADIUSAttributeType = 30 // RFC2865 5.30. Called-Station-Id + RADIUSAttributeTypeCallingStationId RADIUSAttributeType = 31 // RFC2865 5.31. Calling-Station-Id + RADIUSAttributeTypeNASIdentifier RADIUSAttributeType = 32 // RFC2865 5.32. NAS-Identifier + RADIUSAttributeTypeProxyState RADIUSAttributeType = 33 // RFC2865 5.33. Proxy-State + RADIUSAttributeTypeLoginLATService RADIUSAttributeType = 34 // RFC2865 5.34. Login-LAT-Service + RADIUSAttributeTypeLoginLATNode RADIUSAttributeType = 35 // RFC2865 5.35. Login-LAT-Node + RADIUSAttributeTypeLoginLATGroup RADIUSAttributeType = 36 // RFC2865 5.36. Login-LAT-Group + RADIUSAttributeTypeFramedAppleTalkLink RADIUSAttributeType = 37 // RFC2865 5.37. Framed-AppleTalk-Link + RADIUSAttributeTypeFramedAppleTalkNetwork RADIUSAttributeType = 38 // RFC2865 5.38. Framed-AppleTalk-Network + RADIUSAttributeTypeFramedAppleTalkZone RADIUSAttributeType = 39 // RFC2865 5.39. Framed-AppleTalk-Zone + RADIUSAttributeTypeAcctStatusType RADIUSAttributeType = 40 // RFC2866 5.1. Acct-Status-Type + RADIUSAttributeTypeAcctDelayTime RADIUSAttributeType = 41 // RFC2866 5.2. Acct-Delay-Time + RADIUSAttributeTypeAcctInputOctets RADIUSAttributeType = 42 // RFC2866 5.3. Acct-Input-Octets + RADIUSAttributeTypeAcctOutputOctets RADIUSAttributeType = 43 // RFC2866 5.4. Acct-Output-Octets + RADIUSAttributeTypeAcctSessionId RADIUSAttributeType = 44 // RFC2866 5.5. Acct-Session-Id + RADIUSAttributeTypeAcctAuthentic RADIUSAttributeType = 45 // RFC2866 5.6. Acct-Authentic + RADIUSAttributeTypeAcctSessionTime RADIUSAttributeType = 46 // RFC2866 5.7. Acct-Session-Time + RADIUSAttributeTypeAcctInputPackets RADIUSAttributeType = 47 // RFC2866 5.8. Acct-Input-Packets + RADIUSAttributeTypeAcctOutputPackets RADIUSAttributeType = 48 // RFC2866 5.9. Acct-Output-Packets + RADIUSAttributeTypeAcctTerminateCause RADIUSAttributeType = 49 // RFC2866 5.10. Acct-Terminate-Cause + RADIUSAttributeTypeAcctMultiSessionId RADIUSAttributeType = 50 // RFC2866 5.11. Acct-Multi-Session-Id + RADIUSAttributeTypeAcctLinkCount RADIUSAttributeType = 51 // RFC2866 5.12. Acct-Link-Count + RADIUSAttributeTypeAcctInputGigawords RADIUSAttributeType = 52 // RFC2869 5.1. Acct-Input-Gigawords + RADIUSAttributeTypeAcctOutputGigawords RADIUSAttributeType = 53 // RFC2869 5.2. Acct-Output-Gigawords + RADIUSAttributeTypeEventTimestamp RADIUSAttributeType = 55 // RFC2869 5.3. Event-Timestamp + RADIUSAttributeTypeCHAPChallenge RADIUSAttributeType = 60 // RFC2865 5.40. CHAP-Challenge + RADIUSAttributeTypeNASPortType RADIUSAttributeType = 61 // RFC2865 5.41. NAS-Port-Type + RADIUSAttributeTypePortLimit RADIUSAttributeType = 62 // RFC2865 5.42. Port-Limit + RADIUSAttributeTypeLoginLATPort RADIUSAttributeType = 63 // RFC2865 5.43. Login-LAT-Port + RADIUSAttributeTypeTunnelType RADIUSAttributeType = 64 // RFC2868 3.1. Tunnel-Type + RADIUSAttributeTypeTunnelMediumType RADIUSAttributeType = 65 // RFC2868 3.2. Tunnel-Medium-Type + RADIUSAttributeTypeTunnelClientEndpoint RADIUSAttributeType = 66 // RFC2868 3.3. Tunnel-Client-Endpoint + RADIUSAttributeTypeTunnelServerEndpoint RADIUSAttributeType = 67 // RFC2868 3.4. Tunnel-Server-Endpoint + RADIUSAttributeTypeAcctTunnelConnection RADIUSAttributeType = 68 // RFC2867 4.1. Acct-Tunnel-Connection + RADIUSAttributeTypeTunnelPassword RADIUSAttributeType = 69 // RFC2868 3.5. Tunnel-Password + RADIUSAttributeTypeARAPPassword RADIUSAttributeType = 70 // RFC2869 5.4. ARAP-Password + RADIUSAttributeTypeARAPFeatures RADIUSAttributeType = 71 // RFC2869 5.5. ARAP-Features + RADIUSAttributeTypeARAPZoneAccess RADIUSAttributeType = 72 // RFC2869 5.6. ARAP-Zone-Access + RADIUSAttributeTypeARAPSecurity RADIUSAttributeType = 73 // RFC2869 5.7. ARAP-Security + RADIUSAttributeTypeARAPSecurityData RADIUSAttributeType = 74 // RFC2869 5.8. ARAP-Security-Data + RADIUSAttributeTypePasswordRetry RADIUSAttributeType = 75 // RFC2869 5.9. Password-Retry + RADIUSAttributeTypePrompt RADIUSAttributeType = 76 // RFC2869 5.10. Prompt + RADIUSAttributeTypeConnectInfo RADIUSAttributeType = 77 // RFC2869 5.11. Connect-Info + RADIUSAttributeTypeConfigurationToken RADIUSAttributeType = 78 // RFC2869 5.12. Configuration-Token + RADIUSAttributeTypeEAPMessage RADIUSAttributeType = 79 // RFC2869 5.13. EAP-Message + RADIUSAttributeTypeMessageAuthenticator RADIUSAttributeType = 80 // RFC2869 5.14. Message-Authenticator + RADIUSAttributeTypeTunnelPrivateGroupID RADIUSAttributeType = 81 // RFC2868 3.6. Tunnel-Private-Group-ID + RADIUSAttributeTypeTunnelAssignmentID RADIUSAttributeType = 82 // RFC2868 3.7. Tunnel-Assignment-ID + RADIUSAttributeTypeTunnelPreference RADIUSAttributeType = 83 // RFC2868 3.8. Tunnel-Preference + RADIUSAttributeTypeARAPChallengeResponse RADIUSAttributeType = 84 // RFC2869 5.15. ARAP-Challenge-Response + RADIUSAttributeTypeAcctInterimInterval RADIUSAttributeType = 85 // RFC2869 5.16. Acct-Interim-Interval + RADIUSAttributeTypeAcctTunnelPacketsLost RADIUSAttributeType = 86 // RFC2867 4.2. Acct-Tunnel-Packets-Lost + RADIUSAttributeTypeNASPortId RADIUSAttributeType = 87 // RFC2869 5.17. NAS-Port-Id + RADIUSAttributeTypeFramedPool RADIUSAttributeType = 88 // RFC2869 5.18. Framed-Pool + RADIUSAttributeTypeTunnelClientAuthID RADIUSAttributeType = 90 // RFC2868 3.9. Tunnel-Client-Auth-ID + RADIUSAttributeTypeTunnelServerAuthID RADIUSAttributeType = 91 // RFC2868 3.10. Tunnel-Server-Auth-ID +) + +// RADIUSAttributeType represents attribute length. +type RADIUSAttributeLength uint8 + +// RADIUSAttributeType represents attribute value. +type RADIUSAttributeValue []byte + +// String returns a string version of a RADIUSAttributeType. +func (t RADIUSAttributeType) String() (s string) { + switch t { + case RADIUSAttributeTypeUserName: + s = "User-Name" + case RADIUSAttributeTypeUserPassword: + s = "User-Password" + case RADIUSAttributeTypeCHAPPassword: + s = "CHAP-Password" + case RADIUSAttributeTypeNASIPAddress: + s = "NAS-IP-Address" + case RADIUSAttributeTypeNASPort: + s = "NAS-Port" + case RADIUSAttributeTypeServiceType: + s = "Service-Type" + case RADIUSAttributeTypeFramedProtocol: + s = "Framed-Protocol" + case RADIUSAttributeTypeFramedIPAddress: + s = "Framed-IP-Address" + case RADIUSAttributeTypeFramedIPNetmask: + s = "Framed-IP-Netmask" + case RADIUSAttributeTypeFramedRouting: + s = "Framed-Routing" + case RADIUSAttributeTypeFilterId: + s = "Filter-Id" + case RADIUSAttributeTypeFramedMTU: + s = "Framed-MTU" + case RADIUSAttributeTypeFramedCompression: + s = "Framed-Compression" + case RADIUSAttributeTypeLoginIPHost: + s = "Login-IP-Host" + case RADIUSAttributeTypeLoginService: + s = "Login-Service" + case RADIUSAttributeTypeLoginTCPPort: + s = "Login-TCP-Port" + case RADIUSAttributeTypeReplyMessage: + s = "Reply-Message" + case RADIUSAttributeTypeCallbackNumber: + s = "Callback-Number" + case RADIUSAttributeTypeCallbackId: + s = "Callback-Id" + case RADIUSAttributeTypeFramedRoute: + s = "Framed-Route" + case RADIUSAttributeTypeFramedIPXNetwork: + s = "Framed-IPX-Network" + case RADIUSAttributeTypeState: + s = "State" + case RADIUSAttributeTypeClass: + s = "Class" + case RADIUSAttributeTypeVendorSpecific: + s = "Vendor-Specific" + case RADIUSAttributeTypeSessionTimeout: + s = "Session-Timeout" + case RADIUSAttributeTypeIdleTimeout: + s = "Idle-Timeout" + case RADIUSAttributeTypeTerminationAction: + s = "Termination-Action" + case RADIUSAttributeTypeCalledStationId: + s = "Called-Station-Id" + case RADIUSAttributeTypeCallingStationId: + s = "Calling-Station-Id" + case RADIUSAttributeTypeNASIdentifier: + s = "NAS-Identifier" + case RADIUSAttributeTypeProxyState: + s = "Proxy-State" + case RADIUSAttributeTypeLoginLATService: + s = "Login-LAT-Service" + case RADIUSAttributeTypeLoginLATNode: + s = "Login-LAT-Node" + case RADIUSAttributeTypeLoginLATGroup: + s = "Login-LAT-Group" + case RADIUSAttributeTypeFramedAppleTalkLink: + s = "Framed-AppleTalk-Link" + case RADIUSAttributeTypeFramedAppleTalkNetwork: + s = "Framed-AppleTalk-Network" + case RADIUSAttributeTypeFramedAppleTalkZone: + s = "Framed-AppleTalk-Zone" + case RADIUSAttributeTypeAcctStatusType: + s = "Acct-Status-Type" + case RADIUSAttributeTypeAcctDelayTime: + s = "Acct-Delay-Time" + case RADIUSAttributeTypeAcctInputOctets: + s = "Acct-Input-Octets" + case RADIUSAttributeTypeAcctOutputOctets: + s = "Acct-Output-Octets" + case RADIUSAttributeTypeAcctSessionId: + s = "Acct-Session-Id" + case RADIUSAttributeTypeAcctAuthentic: + s = "Acct-Authentic" + case RADIUSAttributeTypeAcctSessionTime: + s = "Acct-Session-Time" + case RADIUSAttributeTypeAcctInputPackets: + s = "Acct-Input-Packets" + case RADIUSAttributeTypeAcctOutputPackets: + s = "Acct-Output-Packets" + case RADIUSAttributeTypeAcctTerminateCause: + s = "Acct-Terminate-Cause" + case RADIUSAttributeTypeAcctMultiSessionId: + s = "Acct-Multi-Session-Id" + case RADIUSAttributeTypeAcctLinkCount: + s = "Acct-Link-Count" + case RADIUSAttributeTypeAcctInputGigawords: + s = "Acct-Input-Gigawords" + case RADIUSAttributeTypeAcctOutputGigawords: + s = "Acct-Output-Gigawords" + case RADIUSAttributeTypeEventTimestamp: + s = "Event-Timestamp" + case RADIUSAttributeTypeCHAPChallenge: + s = "CHAP-Challenge" + case RADIUSAttributeTypeNASPortType: + s = "NAS-Port-Type" + case RADIUSAttributeTypePortLimit: + s = "Port-Limit" + case RADIUSAttributeTypeLoginLATPort: + s = "Login-LAT-Port" + case RADIUSAttributeTypeTunnelType: + s = "Tunnel-Type" + case RADIUSAttributeTypeTunnelMediumType: + s = "Tunnel-Medium-Type" + case RADIUSAttributeTypeTunnelClientEndpoint: + s = "Tunnel-Client-Endpoint" + case RADIUSAttributeTypeTunnelServerEndpoint: + s = "Tunnel-Server-Endpoint" + case RADIUSAttributeTypeAcctTunnelConnection: + s = "Acct-Tunnel-Connection" + case RADIUSAttributeTypeTunnelPassword: + s = "Tunnel-Password" + case RADIUSAttributeTypeARAPPassword: + s = "ARAP-Password" + case RADIUSAttributeTypeARAPFeatures: + s = "ARAP-Features" + case RADIUSAttributeTypeARAPZoneAccess: + s = "ARAP-Zone-Access" + case RADIUSAttributeTypeARAPSecurity: + s = "ARAP-Security" + case RADIUSAttributeTypeARAPSecurityData: + s = "ARAP-Security-Data" + case RADIUSAttributeTypePasswordRetry: + s = "Password-Retry" + case RADIUSAttributeTypePrompt: + s = "Prompt" + case RADIUSAttributeTypeConnectInfo: + s = "Connect-Info" + case RADIUSAttributeTypeConfigurationToken: + s = "Configuration-Token" + case RADIUSAttributeTypeEAPMessage: + s = "EAP-Message" + case RADIUSAttributeTypeMessageAuthenticator: + s = "Message-Authenticator" + case RADIUSAttributeTypeTunnelPrivateGroupID: + s = "Tunnel-Private-Group-ID" + case RADIUSAttributeTypeTunnelAssignmentID: + s = "Tunnel-Assignment-ID" + case RADIUSAttributeTypeTunnelPreference: + s = "Tunnel-Preference" + case RADIUSAttributeTypeARAPChallengeResponse: + s = "ARAP-Challenge-Response" + case RADIUSAttributeTypeAcctInterimInterval: + s = "Acct-Interim-Interval" + case RADIUSAttributeTypeAcctTunnelPacketsLost: + s = "Acct-Tunnel-Packets-Lost" + case RADIUSAttributeTypeNASPortId: + s = "NAS-Port-Id" + case RADIUSAttributeTypeFramedPool: + s = "Framed-Pool" + case RADIUSAttributeTypeTunnelClientAuthID: + s = "Tunnel-Client-Auth-ID" + case RADIUSAttributeTypeTunnelServerAuthID: + s = "Tunnel-Server-Auth-ID" + default: + s = fmt.Sprintf("Unknown(%d)", t) + } + return +} + +// Len returns the length of a RADIUS packet. +func (radius *RADIUS) Len() (int, error) { + n := radiusMinimumRecordSizeInBytes + for _, v := range radius.Attributes { + alen, err := attributeValueLength(v.Value) + if err != nil { + return 0, err + } + n += int(alen) + 2 // Added Type and Length + } + return n, nil +} + +// LayerType returns LayerTypeRADIUS. +func (radius *RADIUS) LayerType() gopacket.LayerType { + return LayerTypeRADIUS +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (radius *RADIUS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) > radiusMaximumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS length %d too big", len(data)) + } + + if len(data) < radiusMinimumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS length %d too short", len(data)) + } + + radius.BaseLayer = BaseLayer{Contents: data} + + radius.Code = RADIUSCode(data[0]) + radius.Identifier = RADIUSIdentifier(data[1]) + radius.Length = RADIUSLength(binary.BigEndian.Uint16(data[2:4])) + + if int(radius.Length) > radiusMaximumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS length %d too big", radius.Length) + } + + if int(radius.Length) < radiusMinimumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS length %d too short", radius.Length) + } + + // RFC 2865 3. Packet Format + // `If the packet is shorter than the Length field indicates, it MUST be silently discarded.` + if int(radius.Length) > len(data) { + df.SetTruncated() + return fmt.Errorf("RADIUS length %d too big", radius.Length) + } + + // RFC 2865 3. Packet Format + // `Octets outside the range of the Length field MUST be treated as padding and ignored on reception.` + if int(radius.Length) < len(data) { + df.SetTruncated() + data = data[:radius.Length] + } + + copy(radius.Authenticator[:], data[4:20]) + + if len(data) == radiusMinimumRecordSizeInBytes { + return nil + } + + pos := radiusMinimumRecordSizeInBytes + for { + if len(data) == pos { + break + } + + if len(data[pos:]) < radiusAttributesMinimumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS attributes length %d too short", len(data[pos:])) + } + + attr := RADIUSAttribute{} + attr.Type = RADIUSAttributeType(data[pos]) + attr.Length = RADIUSAttributeLength(data[pos+1]) + + if int(attr.Length) > len(data[pos:]) { + df.SetTruncated() + return fmt.Errorf("RADIUS attributes length %d too big", attr.Length) + } + + if int(attr.Length) < radiusAttributesMinimumRecordSizeInBytes { + df.SetTruncated() + return fmt.Errorf("RADIUS attributes length %d too short", attr.Length) + } + + if int(attr.Length) > radiusAttributesMinimumRecordSizeInBytes { + attr.Value = make([]byte, attr.Length-2) + copy(attr.Value[:], data[pos+2:pos+int(attr.Length)]) + radius.Attributes = append(radius.Attributes, attr) + } + + pos += int(attr.Length) + } + + for _, v := range radius.Attributes { + if v.Type == RADIUSAttributeTypeEAPMessage { + radius.BaseLayer.Payload = append(radius.BaseLayer.Payload, v.Value...) + } + } + + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (radius *RADIUS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + plen, err := radius.Len() + if err != nil { + return err + } + + if opts.FixLengths { + radius.Length = RADIUSLength(plen) + } + + data, err := b.PrependBytes(plen) + if err != nil { + return err + } + + data[0] = byte(radius.Code) + data[1] = byte(radius.Identifier) + binary.BigEndian.PutUint16(data[2:], uint16(radius.Length)) + copy(data[4:20], radius.Authenticator[:]) + + pos := radiusMinimumRecordSizeInBytes + for _, v := range radius.Attributes { + if opts.FixLengths { + v.Length, err = attributeValueLength(v.Value) + if err != nil { + return err + } + } + + data[pos] = byte(v.Type) + data[pos+1] = byte(v.Length) + copy(data[pos+2:], v.Value[:]) + + pos += len(v.Value) + 2 // Added Type and Length + } + + return nil +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (radius *RADIUS) CanDecode() gopacket.LayerClass { + return LayerTypeRADIUS +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (radius *RADIUS) NextLayerType() gopacket.LayerType { + if len(radius.BaseLayer.Payload) > 0 { + return LayerTypeEAP + } else { + return gopacket.LayerTypeZero + } +} + +// Payload returns the EAP Type-Data for EAP-Message attributes. +func (radius *RADIUS) Payload() []byte { + return radius.BaseLayer.Payload +} + +func decodeRADIUS(data []byte, p gopacket.PacketBuilder) error { + radius := &RADIUS{} + err := radius.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(radius) + p.SetApplicationLayer(radius) + next := radius.NextLayerType() + if next == gopacket.LayerTypeZero { + return nil + } + return p.NextDecoder(next) +} + +func attributeValueLength(v []byte) (RADIUSAttributeLength, error) { + n := len(v) + if n > 255 { + return 0, fmt.Errorf("RADIUS attribute value length %d too long", n) + } else { + return RADIUSAttributeLength(n), nil + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rmcp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rmcp.go new file mode 100644 index 0000000000..4e4a6e8071 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rmcp.go @@ -0,0 +1,170 @@ +// 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. + +package layers + +// This file implements the ASF-RMCP header specified in section 3.2.2.2 of +// https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf + +import ( + "fmt" + + "github.com/gopacket/gopacket" +) + +// RMCPClass is the class of a RMCP layer's payload, e.g. ASF or IPMI. This is a +// 4-bit unsigned int on the wire; all but 6 (ASF), 7 (IPMI) and 8 (OEM-defined) +// are currently reserved. +type RMCPClass uint8 + +// LayerType returns the payload layer type corresponding to a RMCP class. +func (c RMCPClass) LayerType() gopacket.LayerType { + if lt := rmcpClassLayerTypes[uint8(c)]; lt != 0 { + return lt + } + return gopacket.LayerTypePayload +} + +func (c RMCPClass) String() string { + return fmt.Sprintf("%v(%v)", uint8(c), c.LayerType()) +} + +const ( + // RMCPVersion1 identifies RMCP v1.0 in the Version header field. Lower + // values are considered legacy, while higher values are reserved by the + // specification. + RMCPVersion1 uint8 = 0x06 + + // RMCPNormal indicates a "normal" message, i.e. not an acknowledgement. + RMCPNormal uint8 = 0 + + // RMCPAck indicates a message is acknowledging a received normal message. + RMCPAck uint8 = 1 << 7 + + // RMCPClassASF identifies an RMCP message as containing an ASF-RMCP + // payload. + RMCPClassASF RMCPClass = 0x06 + + // RMCPClassIPMI identifies an RMCP message as containing an IPMI payload. + RMCPClassIPMI RMCPClass = 0x07 + + // RMCPClassOEM identifies an RMCP message as containing an OEM-defined + // payload. + RMCPClassOEM RMCPClass = 0x08 +) + +var ( + rmcpClassLayerTypes = [16]gopacket.LayerType{ + RMCPClassASF: LayerTypeASF, + // RMCPClassIPMI is to implement; RMCPClassOEM is deliberately not + // implemented, so we return LayerTypePayload + } +) + +// RegisterRMCPLayerType allows specifying that the payload of a RMCP packet of +// a certain class should processed by the provided layer type. This overrides +// any existing registrations, including defaults. +func RegisterRMCPLayerType(c RMCPClass, l gopacket.LayerType) { + rmcpClassLayerTypes[c] = l +} + +// RMCP describes the format of an RMCP header, which forms a UDP payload. See +// section 3.2.2.2. +type RMCP struct { + BaseLayer + + // Version identifies the version of the RMCP header. 0x06 indicates RMCP + // v1.0; lower values are legacy, higher values are reserved. + Version uint8 + + // Sequence is the sequence number assicated with the message. Note that + // this rolls over to 0 after 254, not 255. Seq num 255 indicates the + // receiver must not send an ACK. + Sequence uint8 + + // Ack indicates whether this packet is an acknowledgement. If it is, the + // payload will be empty. + Ack bool + + // Class idicates the structure of the payload. There are only 2^4 valid + // values, however there is no uint4 data type. N.B. the Ack bit has been + // split off into another field. The most significant 4 bits of this field + // will always be 0. + Class RMCPClass +} + +// LayerType returns LayerTypeRMCP. It partially satisfies Layer and +// SerializableLayer. +func (*RMCP) LayerType() gopacket.LayerType { + return LayerTypeRMCP +} + +// CanDecode returns LayerTypeRMCP. It partially satisfies DecodingLayer. +func (r *RMCP) CanDecode() gopacket.LayerClass { + return r.LayerType() +} + +// DecodeFromBytes makes the layer represent the provided bytes. It partially +// satisfies DecodingLayer. +func (r *RMCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 4 { + df.SetTruncated() + return fmt.Errorf("invalid RMCP header, length %v less than 4", + len(data)) + } + + r.BaseLayer.Contents = data[:4] + r.BaseLayer.Payload = data[4:] + + r.Version = uint8(data[0]) + // 1 byte reserved + r.Sequence = uint8(data[2]) + r.Ack = data[3]&RMCPAck != 0 + r.Class = RMCPClass(data[3] & 0xF) + return nil +} + +// NextLayerType returns the data layer of this RMCP layer. This partially +// satisfies DecodingLayer. +func (r *RMCP) NextLayerType() gopacket.LayerType { + return r.Class.LayerType() +} + +// Payload returns the data layer. It partially satisfies ApplicationLayer. +func (r *RMCP) Payload() []byte { + return r.BaseLayer.Payload +} + +// SerializeTo writes the serialized fom of this layer into the SerializeBuffer, +// partially satisfying SerializableLayer. +func (r *RMCP) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { + // The IPMI v1.5 spec contains a pad byte for frame sizes of certain lengths + // to work around issues in LAN chips. This is no longer necessary as of + // IPMI v2.0 (renamed to "legacy pad") so we do not attempt to add it. The + // same approach is taken by FreeIPMI: + // http://git.savannah.gnu.org/cgit/freeipmi.git/tree/libfreeipmi/interface/ipmi-lan-interface.c?id=b5ffcd38317daf42074458879f4c55ba6804a595#n836 + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + bytes[0] = r.Version + bytes[1] = 0x00 + bytes[2] = r.Sequence + bytes[3] = bool2uint8(r.Ack)<<7 | uint8(r.Class) // thanks, BFD layer + return nil +} + +// decodeRMCP decodes the byte slice into an RMCP type, and sets the application +// layer to it. +func decodeRMCP(data []byte, p gopacket.PacketBuilder) error { + rmcp := &RMCP{} + err := rmcp.DecodeFromBytes(data, p) + p.AddLayer(rmcp) + p.SetApplicationLayer(rmcp) + if err != nil { + return err + } + return p.NextDecoder(rmcp.NextLayerType()) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rudp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rudp.go new file mode 100644 index 0000000000..5c3e769478 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/rudp.go @@ -0,0 +1,94 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +type RUDP struct { + BaseLayer + SYN, ACK, EACK, RST, NUL bool + Version uint8 + HeaderLength uint8 + SrcPort, DstPort RUDPPort + DataLength uint16 + Seq, Ack, Checksum uint32 + VariableHeaderArea []byte + // RUDPHeaderSyn contains SYN information for the RUDP packet, + // if the SYN flag is set + *RUDPHeaderSYN + // RUDPHeaderEack contains EACK information for the RUDP packet, + // if the EACK flag is set. + *RUDPHeaderEACK +} + +type RUDPHeaderSYN struct { + MaxOutstandingSegments, MaxSegmentSize, OptionFlags uint16 +} + +type RUDPHeaderEACK struct { + SeqsReceivedOK []uint32 +} + +// LayerType returns gopacket.LayerTypeRUDP. +func (r *RUDP) LayerType() gopacket.LayerType { return LayerTypeRUDP } + +func decodeRUDP(data []byte, p gopacket.PacketBuilder) error { + r := &RUDP{ + SYN: data[0]&0x80 != 0, + ACK: data[0]&0x40 != 0, + EACK: data[0]&0x20 != 0, + RST: data[0]&0x10 != 0, + NUL: data[0]&0x08 != 0, + Version: data[0] & 0x3, + HeaderLength: data[1], + SrcPort: RUDPPort(data[2]), + DstPort: RUDPPort(data[3]), + DataLength: binary.BigEndian.Uint16(data[4:6]), + Seq: binary.BigEndian.Uint32(data[6:10]), + Ack: binary.BigEndian.Uint32(data[10:14]), + Checksum: binary.BigEndian.Uint32(data[14:18]), + } + if r.HeaderLength < 9 { + return fmt.Errorf("RUDP packet with too-short header length %d", r.HeaderLength) + } + hlen := int(r.HeaderLength) * 2 + r.Contents = data[:hlen] + r.Payload = data[hlen : hlen+int(r.DataLength)] + r.VariableHeaderArea = data[18:hlen] + headerData := r.VariableHeaderArea + switch { + case r.SYN: + if len(headerData) != 6 { + return fmt.Errorf("RUDP packet invalid SYN header length: %d", len(headerData)) + } + r.RUDPHeaderSYN = &RUDPHeaderSYN{ + MaxOutstandingSegments: binary.BigEndian.Uint16(headerData[:2]), + MaxSegmentSize: binary.BigEndian.Uint16(headerData[2:4]), + OptionFlags: binary.BigEndian.Uint16(headerData[4:6]), + } + case r.EACK: + if len(headerData)%4 != 0 { + return fmt.Errorf("RUDP packet invalid EACK header length: %d", len(headerData)) + } + r.RUDPHeaderEACK = &RUDPHeaderEACK{make([]uint32, len(headerData)/4)} + for i := 0; i < len(headerData); i += 4 { + r.SeqsReceivedOK[i/4] = binary.BigEndian.Uint32(headerData[i : i+4]) + } + } + p.AddLayer(r) + p.SetTransportLayer(r) + return p.NextDecoder(gopacket.LayerTypePayload) +} + +func (r *RUDP) TransportFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointRUDPPort, []byte{byte(r.SrcPort)}, []byte{byte(r.DstPort)}) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sctp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sctp.go new file mode 100644 index 0000000000..368497bc51 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sctp.go @@ -0,0 +1,770 @@ +// 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + + "github.com/gopacket/gopacket" +) + +// SCTP contains information on the top level of an SCTP packet. +type SCTP struct { + BaseLayer + SrcPort, DstPort SCTPPort + VerificationTag uint32 + Checksum uint32 + sPort, dPort []byte +} + +// LayerType returns gopacket.LayerTypeSCTP +func (s *SCTP) LayerType() gopacket.LayerType { return LayerTypeSCTP } + +func decodeSCTP(data []byte, p gopacket.PacketBuilder) error { + sctp := &SCTP{} + err := sctp.DecodeFromBytes(data, p) + p.AddLayer(sctp) + p.SetTransportLayer(sctp) + if err != nil { + return err + } + return p.NextDecoder(sctpChunkTypePrefixDecoder) +} + +var sctpChunkTypePrefixDecoder = gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix) + +// TransportFlow returns a flow based on the source and destination SCTP port. +func (s *SCTP) TransportFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointSCTPPort, s.sPort, s.dPort) +} + +func decodeWithSCTPChunkTypePrefix(data []byte, p gopacket.PacketBuilder) error { + chunkType := SCTPChunkType(data[0]) + return chunkType.Decode(data, p) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (s SCTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(12) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes[0:2], uint16(s.SrcPort)) + binary.BigEndian.PutUint16(bytes[2:4], uint16(s.DstPort)) + binary.BigEndian.PutUint32(bytes[4:8], s.VerificationTag) + if opts.ComputeChecksums { + // Note: MakeTable(Castagnoli) actually only creates the table once, then + // passes back a singleton on every other call, so this shouldn't cause + // excessive memory allocation. + binary.LittleEndian.PutUint32(bytes[8:12], crc32.Checksum(b.Bytes(), crc32.MakeTable(crc32.Castagnoli))) + } + return nil +} + +func (sctp *SCTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 12 { + return errors.New("Invalid SCTP common header length") + } + sctp.SrcPort = SCTPPort(binary.BigEndian.Uint16(data[:2])) + sctp.sPort = data[:2] + sctp.DstPort = SCTPPort(binary.BigEndian.Uint16(data[2:4])) + sctp.dPort = data[2:4] + sctp.VerificationTag = binary.BigEndian.Uint32(data[4:8]) + sctp.Checksum = binary.BigEndian.Uint32(data[8:12]) + sctp.BaseLayer = BaseLayer{data[:12], data[12:]} + + return nil +} + +func (t *SCTP) CanDecode() gopacket.LayerClass { + return LayerTypeSCTP +} + +func (t *SCTP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// SCTPChunk contains the common fields in all SCTP chunks. +type SCTPChunk struct { + BaseLayer + Type SCTPChunkType + Flags uint8 + Length uint16 + // ActualLength is the total length of an SCTP chunk, including padding. + // SCTP chunks start and end on 4-byte boundaries. So if a chunk has a length + // of 18, it means that it has data up to and including byte 18, then padding + // up to the next 4-byte boundary, 20. In this case, Length would be 18, and + // ActualLength would be 20. + ActualLength int +} + +func roundUpToNearest4(i int) int { + if i%4 == 0 { + return i + } + return i + 4 - (i % 4) +} + +func decodeSCTPChunk(data []byte) (SCTPChunk, error) { + length := binary.BigEndian.Uint16(data[2:4]) + if length < 4 { + return SCTPChunk{}, errors.New("invalid SCTP chunk length") + } + actual := roundUpToNearest4(int(length)) + ct := SCTPChunkType(data[0]) + + // For SCTP Data, use a separate layer for the payload + delta := 0 + if ct == SCTPChunkTypeData { + delta = int(actual) - int(length) + actual = 16 + } + + return SCTPChunk{ + Type: ct, + Flags: data[1], + Length: length, + ActualLength: actual, + BaseLayer: BaseLayer{data[:actual], data[actual : len(data)-delta]}, + }, nil +} + +func decodeSCTPDataChunk(data []byte) (SCTPChunk, error) { + length := binary.BigEndian.Uint16(data[2:4]) + if length < 4 { + return SCTPChunk{}, errors.New("invalid SCTP chunk length") + } + actual := roundUpToNearest4(int(length)) + ct := SCTPChunkType(data[0]) + + return SCTPChunk{ + Type: ct, + Flags: data[1], + Length: length, + ActualLength: actual, + BaseLayer: BaseLayer{data[:actual], data[actual:]}, + }, nil +} + +// SCTPParameter is a TLV parameter inside a SCTPChunk. +type SCTPParameter struct { + Type uint16 + Length uint16 + ActualLength int + Value []byte +} + +func decodeSCTPParameter(data []byte) SCTPParameter { + length := binary.BigEndian.Uint16(data[2:4]) + return SCTPParameter{ + Type: binary.BigEndian.Uint16(data[0:2]), + Length: length, + Value: data[4:length], + ActualLength: roundUpToNearest4(int(length)), + } +} + +func (p SCTPParameter) Bytes() []byte { + length := 4 + len(p.Value) + data := make([]byte, roundUpToNearest4(length)) + binary.BigEndian.PutUint16(data[0:2], p.Type) + binary.BigEndian.PutUint16(data[2:4], uint16(length)) + copy(data[4:], p.Value) + return data +} + +// SCTPUnknownChunkType is the layer type returned when we don't recognize the +// chunk type. Since there's a length in a known location, we can skip over +// it even if we don't know what it is, and continue parsing the rest of the +// chunks. This chunk is stored as an ErrorLayer in the packet. +type SCTPUnknownChunkType struct { + SCTPChunk + bytes []byte +} + +func decodeSCTPChunkTypeUnknown(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPUnknownChunkType{SCTPChunk: chunk} + sc.bytes = data[:sc.ActualLength] + p.AddLayer(sc) + p.SetErrorLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (s SCTPUnknownChunkType) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(s.ActualLength) + if err != nil { + return err + } + copy(bytes, s.bytes) + return nil +} + +// LayerType returns gopacket.LayerTypeSCTPUnknownChunkType. +func (s *SCTPUnknownChunkType) LayerType() gopacket.LayerType { return LayerTypeSCTPUnknownChunkType } + +// Payload returns all bytes in this header, including the decoded Type, Length, +// and Flags. +func (s *SCTPUnknownChunkType) Payload() []byte { return s.bytes } + +// Error implements ErrorLayer. +func (s *SCTPUnknownChunkType) Error() error { + return fmt.Errorf("No decode method available for SCTP chunk type %s", s.Type) +} + +// SCTPData is the SCTP Data chunk layer. +type SCTPData struct { + SCTPChunk + Unordered, BeginFragment, EndFragment bool + TSN uint32 + StreamId uint16 + StreamSequence uint16 + PayloadProtocol SCTPPayloadProtocol + Payload []byte +} + +// LayerType returns gopacket.LayerTypeSCTPData. +func (s *SCTPData) LayerType() gopacket.LayerType { return LayerTypeSCTPData } + +// SCTPPayloadProtocol represents a payload protocol +type SCTPPayloadProtocol uint32 + +// SCTPPayloadProtocol constonts from http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml +const ( + SCTPProtocolReserved SCTPPayloadProtocol = 0 + SCTPPayloadUIA = 1 + SCTPPayloadM2UA = 2 + SCTPPayloadM3UA = 3 + SCTPPayloadSUA = 4 + SCTPPayloadM2PA = 5 + SCTPPayloadV5UA = 6 + SCTPPayloadH248 = 7 + SCTPPayloadBICC = 8 + SCTPPayloadTALI = 9 + SCTPPayloadDUA = 10 + SCTPPayloadASAP = 11 + SCTPPayloadENRP = 12 + SCTPPayloadH323 = 13 + SCTPPayloadQIPC = 14 + SCTPPayloadSIMCO = 15 + SCTPPayloadDDPSegment = 16 + SCTPPayloadDDPStream = 17 + SCTPPayloadS1AP = 18 +) + +func (p SCTPPayloadProtocol) String() string { + switch p { + case SCTPProtocolReserved: + return "Reserved" + case SCTPPayloadUIA: + return "UIA" + case SCTPPayloadM2UA: + return "M2UA" + case SCTPPayloadM3UA: + return "M3UA" + case SCTPPayloadSUA: + return "SUA" + case SCTPPayloadM2PA: + return "M2PA" + case SCTPPayloadV5UA: + return "V5UA" + case SCTPPayloadH248: + return "H.248" + case SCTPPayloadBICC: + return "BICC" + case SCTPPayloadTALI: + return "TALI" + case SCTPPayloadDUA: + return "DUA" + case SCTPPayloadASAP: + return "ASAP" + case SCTPPayloadENRP: + return "ENRP" + case SCTPPayloadH323: + return "H.323" + case SCTPPayloadQIPC: + return "QIPC" + case SCTPPayloadSIMCO: + return "SIMCO" + case SCTPPayloadDDPSegment: + return "DDPSegment" + case SCTPPayloadDDPStream: + return "DDPStream" + case SCTPPayloadS1AP: + return "S1AP" + } + return fmt.Sprintf("Unknown(%d)", p) +} + +func decodeSCTPData(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPDataChunk(data) + if err != nil { + return err + } + l := chunk.ActualLength + sc := &SCTPData{ + SCTPChunk: chunk, + Unordered: data[1]&0x4 != 0, + BeginFragment: data[1]&0x2 != 0, + EndFragment: data[1]&0x1 != 0, + TSN: binary.BigEndian.Uint32(data[4:8]), + StreamId: binary.BigEndian.Uint16(data[8:10]), + StreamSequence: binary.BigEndian.Uint16(data[10:12]), + PayloadProtocol: SCTPPayloadProtocol(binary.BigEndian.Uint32(data[12:16])), + Payload: []byte{}, + } + if l >= 16 { + sc.Payload = data[16:l] + } + // Length is the length in bytes of the data, INCLUDING the 16-byte header. + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPData) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + payload := sc.Payload + length := len(payload) + 16 + + if rem := length % 4; rem != 0 { + length += 4 - rem + } + bytes, err := b.PrependBytes(length) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + flags := uint8(0) + if sc.Unordered { + flags |= 0x4 + } + if sc.BeginFragment { + flags |= 0x2 + } + if sc.EndFragment { + flags |= 0x1 + } + bytes[1] = flags + binary.BigEndian.PutUint16(bytes[2:4], sc.Length) + binary.BigEndian.PutUint32(bytes[4:8], sc.TSN) + binary.BigEndian.PutUint16(bytes[8:10], sc.StreamId) + binary.BigEndian.PutUint16(bytes[10:12], sc.StreamSequence) + binary.BigEndian.PutUint32(bytes[12:16], uint32(sc.PayloadProtocol)) + copy(bytes[16:], payload) + return nil +} + +// SCTPInitParameter is a parameter for an SCTP Init or InitAck packet. +type SCTPInitParameter SCTPParameter + +// SCTPInit is used as the return value for both SCTPInit and SCTPInitAck +// messages. +type SCTPInit struct { + SCTPChunk + InitiateTag uint32 + AdvertisedReceiverWindowCredit uint32 + OutboundStreams, InboundStreams uint16 + InitialTSN uint32 + Parameters []SCTPInitParameter +} + +// LayerType returns either gopacket.LayerTypeSCTPInit or gopacket.LayerTypeSCTPInitAck. +func (sc *SCTPInit) LayerType() gopacket.LayerType { + if sc.Type == SCTPChunkTypeInitAck { + return LayerTypeSCTPInitAck + } + // sc.Type == SCTPChunkTypeInit + return LayerTypeSCTPInit +} + +func decodeSCTPInit(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPInit{ + SCTPChunk: chunk, + InitiateTag: binary.BigEndian.Uint32(data[4:8]), + AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]), + OutboundStreams: binary.BigEndian.Uint16(data[12:14]), + InboundStreams: binary.BigEndian.Uint16(data[14:16]), + InitialTSN: binary.BigEndian.Uint32(data[16:20]), + } + paramData := data[20:sc.ActualLength] + for len(paramData) > 0 { + p := SCTPInitParameter(decodeSCTPParameter(paramData)) + paramData = paramData[p.ActualLength:] + sc.Parameters = append(sc.Parameters, p) + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPInit) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var payload []byte + for _, param := range sc.Parameters { + payload = append(payload, SCTPParameter(param).Bytes()...) + } + length := 20 + len(payload) + bytes, err := b.PrependBytes(roundUpToNearest4(length)) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], uint16(length)) + binary.BigEndian.PutUint32(bytes[4:8], sc.InitiateTag) + binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit) + binary.BigEndian.PutUint16(bytes[12:14], sc.OutboundStreams) + binary.BigEndian.PutUint16(bytes[14:16], sc.InboundStreams) + binary.BigEndian.PutUint32(bytes[16:20], sc.InitialTSN) + copy(bytes[20:], payload) + return nil +} + +// SCTPSack is the SCTP Selective ACK chunk layer. +type SCTPSack struct { + SCTPChunk + CumulativeTSNAck uint32 + AdvertisedReceiverWindowCredit uint32 + NumGapACKs, NumDuplicateTSNs uint16 + GapACKs []uint16 + DuplicateTSNs []uint32 +} + +// LayerType return LayerTypeSCTPSack +func (sc *SCTPSack) LayerType() gopacket.LayerType { + return LayerTypeSCTPSack +} + +func decodeSCTPSack(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPSack{ + SCTPChunk: chunk, + CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]), + AdvertisedReceiverWindowCredit: binary.BigEndian.Uint32(data[8:12]), + NumGapACKs: binary.BigEndian.Uint16(data[12:14]), + NumDuplicateTSNs: binary.BigEndian.Uint16(data[14:16]), + } + // We maximize gapAcks and dupTSNs here so we're not allocating tons + // of memory based on a user-controlable field. Our maximums are not exact, + // but should give us sane defaults... we'll still hit slice boundaries and + // fail if the user-supplied values are too high (in the for loops below), but + // the amount of memory we'll have allocated because of that should be small + // (< sc.ActualLength) + gapAcks := sc.SCTPChunk.ActualLength / 2 + dupTSNs := (sc.SCTPChunk.ActualLength - gapAcks*2) / 4 + if gapAcks > int(sc.NumGapACKs) { + gapAcks = int(sc.NumGapACKs) + } + if dupTSNs > int(sc.NumDuplicateTSNs) { + dupTSNs = int(sc.NumDuplicateTSNs) + } + sc.GapACKs = make([]uint16, 0, gapAcks) + sc.DuplicateTSNs = make([]uint32, 0, dupTSNs) + bytesRemaining := data[16:] + for i := 0; i < int(sc.NumGapACKs); i++ { + sc.GapACKs = append(sc.GapACKs, binary.BigEndian.Uint16(bytesRemaining[:2])) + bytesRemaining = bytesRemaining[2:] + } + for i := 0; i < int(sc.NumDuplicateTSNs); i++ { + sc.DuplicateTSNs = append(sc.DuplicateTSNs, binary.BigEndian.Uint32(bytesRemaining[:4])) + bytesRemaining = bytesRemaining[4:] + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPSack) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + length := 16 + 2*len(sc.GapACKs) + 4*len(sc.DuplicateTSNs) + bytes, err := b.PrependBytes(roundUpToNearest4(length)) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], uint16(length)) + binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck) + binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit) + binary.BigEndian.PutUint16(bytes[12:14], uint16(len(sc.GapACKs))) + binary.BigEndian.PutUint16(bytes[14:16], uint16(len(sc.DuplicateTSNs))) + for i, v := range sc.GapACKs { + binary.BigEndian.PutUint16(bytes[16+i*2:], v) + } + offset := 16 + 2*len(sc.GapACKs) + for i, v := range sc.DuplicateTSNs { + binary.BigEndian.PutUint32(bytes[offset+i*4:], v) + } + return nil +} + +// SCTPHeartbeatParameter is the parameter type used by SCTP heartbeat and +// heartbeat ack layers. +type SCTPHeartbeatParameter SCTPParameter + +// SCTPHeartbeat is the SCTP heartbeat layer, also used for heatbeat ack. +type SCTPHeartbeat struct { + SCTPChunk + Parameters []SCTPHeartbeatParameter +} + +// LayerType returns gopacket.LayerTypeSCTPHeartbeat. +func (sc *SCTPHeartbeat) LayerType() gopacket.LayerType { + if sc.Type == SCTPChunkTypeHeartbeatAck { + return LayerTypeSCTPHeartbeatAck + } + // sc.Type == SCTPChunkTypeHeartbeat + return LayerTypeSCTPHeartbeat +} + +func decodeSCTPHeartbeat(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPHeartbeat{ + SCTPChunk: chunk, + } + paramData := data[4:sc.Length] + for len(paramData) > 0 { + p := SCTPHeartbeatParameter(decodeSCTPParameter(paramData)) + paramData = paramData[p.ActualLength:] + sc.Parameters = append(sc.Parameters, p) + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPHeartbeat) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var payload []byte + for _, param := range sc.Parameters { + payload = append(payload, SCTPParameter(param).Bytes()...) + } + length := 4 + len(payload) + + bytes, err := b.PrependBytes(roundUpToNearest4(length)) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], uint16(length)) + copy(bytes[4:], payload) + return nil +} + +// SCTPErrorParameter is the parameter type used by SCTP Abort and Error layers. +type SCTPErrorParameter SCTPParameter + +// SCTPError is the SCTP error layer, also used for SCTP aborts. +type SCTPError struct { + SCTPChunk + Parameters []SCTPErrorParameter +} + +// LayerType returns LayerTypeSCTPAbort or LayerTypeSCTPError. +func (sc *SCTPError) LayerType() gopacket.LayerType { + if sc.Type == SCTPChunkTypeAbort { + return LayerTypeSCTPAbort + } + // sc.Type == SCTPChunkTypeError + return LayerTypeSCTPError +} + +func decodeSCTPError(data []byte, p gopacket.PacketBuilder) error { + // remarkably similar to decodeSCTPHeartbeat ;) + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPError{ + SCTPChunk: chunk, + } + paramData := data[4:sc.Length] + for len(paramData) > 0 { + p := SCTPErrorParameter(decodeSCTPParameter(paramData)) + paramData = paramData[p.ActualLength:] + sc.Parameters = append(sc.Parameters, p) + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPError) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var payload []byte + for _, param := range sc.Parameters { + payload = append(payload, SCTPParameter(param).Bytes()...) + } + length := 4 + len(payload) + + bytes, err := b.PrependBytes(roundUpToNearest4(length)) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], uint16(length)) + copy(bytes[4:], payload) + return nil +} + +// SCTPShutdown is the SCTP shutdown layer. +type SCTPShutdown struct { + SCTPChunk + CumulativeTSNAck uint32 +} + +// LayerType returns gopacket.LayerTypeSCTPShutdown. +func (sc *SCTPShutdown) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdown } + +func decodeSCTPShutdown(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPShutdown{ + SCTPChunk: chunk, + CumulativeTSNAck: binary.BigEndian.Uint32(data[4:8]), + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPShutdown) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], 8) + binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck) + return nil +} + +// SCTPShutdownAck is the SCTP shutdown layer. +type SCTPShutdownAck struct { + SCTPChunk +} + +// LayerType returns gopacket.LayerTypeSCTPShutdownAck. +func (sc *SCTPShutdownAck) LayerType() gopacket.LayerType { return LayerTypeSCTPShutdownAck } + +func decodeSCTPShutdownAck(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPShutdownAck{ + SCTPChunk: chunk, + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPShutdownAck) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], 4) + return nil +} + +// SCTPCookieEcho is the SCTP Cookie Echo layer. +type SCTPCookieEcho struct { + SCTPChunk + Cookie []byte +} + +// LayerType returns gopacket.LayerTypeSCTPCookieEcho. +func (sc *SCTPCookieEcho) LayerType() gopacket.LayerType { return LayerTypeSCTPCookieEcho } + +func decodeSCTPCookieEcho(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPCookieEcho{ + SCTPChunk: chunk, + } + sc.Cookie = data[4:sc.Length] + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPCookieEcho) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + length := 4 + len(sc.Cookie) + bytes, err := b.PrependBytes(roundUpToNearest4(length)) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], uint16(length)) + copy(bytes[4:], sc.Cookie) + return nil +} + +// This struct is used by all empty SCTP chunks (currently CookieAck and +// ShutdownComplete). +type SCTPEmptyLayer struct { + SCTPChunk +} + +// LayerType returns either gopacket.LayerTypeSCTPShutdownComplete or +// LayerTypeSCTPCookieAck. +func (sc *SCTPEmptyLayer) LayerType() gopacket.LayerType { + if sc.Type == SCTPChunkTypeShutdownComplete { + return LayerTypeSCTPShutdownComplete + } + // sc.Type == SCTPChunkTypeCookieAck + return LayerTypeSCTPCookieAck +} + +func decodeSCTPEmptyLayer(data []byte, p gopacket.PacketBuilder) error { + chunk, err := decodeSCTPChunk(data) + if err != nil { + return err + } + sc := &SCTPEmptyLayer{ + SCTPChunk: chunk, + } + p.AddLayer(sc) + return p.NextDecoder(gopacket.DecodeFunc(decodeWithSCTPChunkTypePrefix)) +} + +// SerializeTo is for gopacket.SerializableLayer. +func (sc SCTPEmptyLayer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(4) + if err != nil { + return err + } + bytes[0] = uint8(sc.Type) + bytes[1] = sc.Flags + binary.BigEndian.PutUint16(bytes[2:4], 4) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sflow.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sflow.go new file mode 100644 index 0000000000..70fd787a4f --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sflow.go @@ -0,0 +1,2599 @@ +// Copyright 2014 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. + +/* +This layer decodes SFlow version 5 datagrams. + +The specification can be found here: http://sflow.org/sflow_version_5.txt + +Additional developer information about sflow can be found at: +http://sflow.org/developers/specifications.php + +And SFlow in general: +http://sflow.org/index.php + +Two forms of sample data are defined: compact and expanded. The +Specification has this to say: + + Compact and expand forms of counter and flow samples are defined. + An agent must not mix compact/expanded encodings. If an agent + will never use ifIndex numbers >= 2^24 then it must use compact + encodings for all interfaces. Otherwise the expanded formats must + be used for all interfaces. + +This decoder only supports the compact form, because that is the only +one for which data was available. + +The datagram is composed of one or more samples of type flow or counter, +and each sample is composed of one or more records describing the sample. +A sample is a single instance of sampled inforamtion, and each record in +the sample gives additional / supplimentary information about the sample. + +The following sample record types are supported: + + Raw Packet Header + opaque = flow_data; enterprise = 0; format = 1 + + Extended Switch Data + opaque = flow_data; enterprise = 0; format = 1001 + + Extended Router Data + opaque = flow_data; enterprise = 0; format = 1002 + + Extended Gateway Data + opaque = flow_data; enterprise = 0; format = 1003 + + Extended User Data + opaque = flow_data; enterprise = 0; format = 1004 + + Extended URL Data + opaque = flow_data; enterprise = 0; format = 1005 + +The following types of counter records are supported: + + Generic Interface Counters - see RFC 2233 + opaque = counter_data; enterprise = 0; format = 1 + + Ethernet Interface Counters - see RFC 2358 + opaque = counter_data; enterprise = 0; format = 2 + +SFlow is encoded using XDR (RFC4506). There are a few places +where the standard 4-byte fields are partitioned into two +bitfields of different lengths. I'm not sure why the designers +chose to pack together two values like this in some places, and +in others they use the entire 4-byte value to store a number that +will never be more than a few bits. In any case, there are a couple +of types defined to handle the decoding of these bitfields, and +that's why they're there. */ + +package layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +// SFlowRecord holds both flow sample records and counter sample records. +// A Record is the structure that actually holds the sampled data +// and / or counters. +type SFlowRecord interface { +} + +// SFlowDataSource encodes a 2-bit SFlowSourceFormat in its most significant +// 2 bits, and an SFlowSourceValue in its least significant 30 bits. +// These types and values define the meaning of the inteface information +// presented in the sample metadata. +type SFlowDataSource int32 + +func (sdc SFlowDataSource) decode() (SFlowSourceFormat, SFlowSourceValue) { + leftField := sdc >> 30 + rightField := uint32(0x3FFFFFFF) & uint32(sdc) + return SFlowSourceFormat(leftField), SFlowSourceValue(rightField) +} + +type SFlowDataSourceExpanded struct { + SourceIDClass SFlowSourceFormat + SourceIDIndex SFlowSourceValue +} + +func (sdce SFlowDataSourceExpanded) decode() (SFlowSourceFormat, SFlowSourceValue) { + leftField := sdce.SourceIDClass >> 30 + rightField := uint32(0x3FFFFFFF) & uint32(sdce.SourceIDIndex) + return SFlowSourceFormat(leftField), SFlowSourceValue(rightField) +} + +type SFlowSourceFormat uint32 + +type SFlowSourceValue uint32 + +const ( + SFlowTypeSingleInterface SFlowSourceFormat = 0 + SFlowTypePacketDiscarded SFlowSourceFormat = 1 + SFlowTypeMultipleDestinations SFlowSourceFormat = 2 +) + +func (sdf SFlowSourceFormat) String() string { + switch sdf { + case SFlowTypeSingleInterface: + return "Single Interface" + case SFlowTypePacketDiscarded: + return "Packet Discarded" + case SFlowTypeMultipleDestinations: + return "Multiple Destinations" + default: + return "UNKNOWN" + } +} + +func decodeSFlow(data []byte, p gopacket.PacketBuilder) error { + s := &SFlowDatagram{} + err := s.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(s) + p.SetApplicationLayer(s) + return nil +} + +// SFlowDatagram is the outermost container which holds some basic information +// about the reporting agent, and holds at least one sample record +type SFlowDatagram struct { + BaseLayer + + DatagramVersion uint32 + AgentAddress net.IP + SubAgentID uint32 + SequenceNumber uint32 + AgentUptime uint32 + SampleCount uint32 + FlowSamples []SFlowFlowSample + CounterSamples []SFlowCounterSample +} + +// An SFlow datagram's outer container has the following +// structure: + +// SFlowDataFormat +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sFlow version (2|4|5) | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int IP version of the Agent (1=v4|2=v6) | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Agent IP address (v4=4byte|v6=16byte) / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sub agent id | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int datagram sequence number | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int switch uptime in ms | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int n samples in datagram | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / n samples / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// SFlowDataFormat encodes the EnterpriseID in the most +// significant 12 bits, and the SampleType in the least significant +// 20 bits. +type SFlowDataFormat uint32 + +func (sdf SFlowDataFormat) decode() (SFlowEnterpriseID, SFlowSampleType) { + leftField := sdf >> 12 + rightField := uint32(0xFFF) & uint32(sdf) + return SFlowEnterpriseID(leftField), SFlowSampleType(rightField) +} + +// SFlowEnterpriseID is used to differentiate between the +// official SFlow standard, and other, vendor-specific +// types of flow data. (Similiar to SNMP's enterprise MIB +// OIDs) Only the office SFlow Enterprise ID is decoded +// here. +type SFlowEnterpriseID uint32 + +const ( + SFlowStandard SFlowEnterpriseID = 0 +) + +func (eid SFlowEnterpriseID) String() string { + switch eid { + case SFlowStandard: + return "Standard SFlow" + default: + return "" + } +} + +func (eid SFlowEnterpriseID) GetType() SFlowEnterpriseID { + return SFlowStandard +} + +// SFlowSampleType specifies the type of sample. Only flow samples +// and counter samples are supported +type SFlowSampleType uint32 + +const ( + SFlowTypeFlowSample SFlowSampleType = 1 + SFlowTypeCounterSample SFlowSampleType = 2 + SFlowTypeExpandedFlowSample SFlowSampleType = 3 + SFlowTypeExpandedCounterSample SFlowSampleType = 4 +) + +func (st SFlowSampleType) GetType() SFlowSampleType { + switch st { + case SFlowTypeFlowSample: + return SFlowTypeFlowSample + case SFlowTypeCounterSample: + return SFlowTypeCounterSample + case SFlowTypeExpandedFlowSample: + return SFlowTypeExpandedFlowSample + case SFlowTypeExpandedCounterSample: + return SFlowTypeExpandedCounterSample + default: + panic("Invalid Sample Type") + } +} + +func (st SFlowSampleType) String() string { + switch st { + case SFlowTypeFlowSample: + return "Flow Sample" + case SFlowTypeCounterSample: + return "Counter Sample" + case SFlowTypeExpandedFlowSample: + return "Expanded Flow Sample" + case SFlowTypeExpandedCounterSample: + return "Expanded Counter Sample" + default: + return "" + } +} + +func (s *SFlowDatagram) LayerType() gopacket.LayerType { return LayerTypeSFlow } + +func (d *SFlowDatagram) Payload() []byte { return nil } + +func (d *SFlowDatagram) CanDecode() gopacket.LayerClass { return LayerTypeSFlow } + +func (d *SFlowDatagram) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload } + +// SFlowIPType determines what form the IP address being decoded will +// take. This is an XDR union type allowing for both IPv4 and IPv6 +type SFlowIPType uint32 + +const ( + SFlowIPv4 SFlowIPType = 1 + SFlowIPv6 SFlowIPType = 2 +) + +func (s SFlowIPType) String() string { + switch s { + case SFlowIPv4: + return "IPv4" + case SFlowIPv6: + return "IPv6" + default: + return "" + } +} + +func (s SFlowIPType) Length() int { + switch s { + case SFlowIPv4: + return 4 + case SFlowIPv6: + return 16 + default: + return 0 + } +} + +func (s *SFlowDatagram) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + var agentAddressType SFlowIPType + + data, s.DatagramVersion = data[4:], binary.BigEndian.Uint32(data[:4]) + data, agentAddressType = data[4:], SFlowIPType(binary.BigEndian.Uint32(data[:4])) + data, s.AgentAddress = data[agentAddressType.Length():], data[:agentAddressType.Length()] + data, s.SubAgentID = data[4:], binary.BigEndian.Uint32(data[:4]) + data, s.SequenceNumber = data[4:], binary.BigEndian.Uint32(data[:4]) + data, s.AgentUptime = data[4:], binary.BigEndian.Uint32(data[:4]) + data, s.SampleCount = data[4:], binary.BigEndian.Uint32(data[:4]) + + if s.SampleCount < 1 { + return fmt.Errorf("SFlow Datagram has invalid sample length: %d", s.SampleCount) + } + for i := uint32(0); i < s.SampleCount; i++ { + sdf := SFlowDataFormat(binary.BigEndian.Uint32(data[:4])) + _, sampleType := sdf.decode() + switch sampleType { + case SFlowTypeFlowSample: + if flowSample, err := decodeFlowSample(&data, false); err == nil { + s.FlowSamples = append(s.FlowSamples, flowSample) + } else { + return err + } + case SFlowTypeCounterSample: + if counterSample, err := decodeCounterSample(&data, false); err == nil { + s.CounterSamples = append(s.CounterSamples, counterSample) + } else { + return err + } + case SFlowTypeExpandedFlowSample: + if flowSample, err := decodeFlowSample(&data, true); err == nil { + s.FlowSamples = append(s.FlowSamples, flowSample) + } else { + return err + } + case SFlowTypeExpandedCounterSample: + if counterSample, err := decodeCounterSample(&data, true); err == nil { + s.CounterSamples = append(s.CounterSamples, counterSample) + } else { + return err + } + + default: + return fmt.Errorf("Unsupported SFlow sample type %d", sampleType) + } + } + return nil +} + +// SFlowFlowSample represents a sampled packet and contains +// one or more records describing the packet +type SFlowFlowSample struct { + EnterpriseID SFlowEnterpriseID + Format SFlowSampleType + SampleLength uint32 + SequenceNumber uint32 + SourceIDClass SFlowSourceFormat + SourceIDIndex SFlowSourceValue + SamplingRate uint32 + SamplePool uint32 + Dropped uint32 + InputInterfaceFormat uint32 + InputInterface uint32 + OutputInterfaceFormat uint32 + OutputInterface uint32 + RecordCount uint32 + Records []SFlowRecord +} + +// Flow samples have the following structure. Note +// the bit fields to encode the Enterprise ID and the +// Flow record format: type 1 + +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | sample length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sample sequence number | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// |id type | src id index value | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sampling rate | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sample pool | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int drops | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int input ifIndex | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int output ifIndex | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int number of records | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / flow records / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// Flow samples have the following structure. +// Flow record format: type 3 + +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | sample length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sample sequence number | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int src id type | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int src id index value | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sampling rate | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sample pool | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int drops | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int input interface format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int input interface value | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int output interface format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int output interface value | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int number of records | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / flow records / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowFlowDataFormat uint32 + +func (fdf SFlowFlowDataFormat) decode() (SFlowEnterpriseID, SFlowFlowRecordType) { + leftField := fdf >> 12 + rightField := uint32(0xFFF) & uint32(fdf) + return SFlowEnterpriseID(leftField), SFlowFlowRecordType(rightField) +} + +func (fs SFlowFlowSample) GetRecords() []SFlowRecord { + return fs.Records +} + +func (fs SFlowFlowSample) GetType() SFlowSampleType { + return SFlowTypeFlowSample +} + +func skipRecord(data *[]byte) { + recordLength := int(binary.BigEndian.Uint32((*data)[4:])) + *data = (*data)[(recordLength+((4-recordLength)%4))+8:] +} + +func decodeFlowSample(data *[]byte, expanded bool) (SFlowFlowSample, error) { + s := SFlowFlowSample{} + var sdf SFlowDataFormat + *data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + var sdc SFlowDataSource + + s.EnterpriseID, s.Format = sdf.decode() + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if expanded { + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SourceIDClass = (*data)[4:], SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4])) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SourceIDIndex = (*data)[4:], SFlowSourceValue(binary.BigEndian.Uint32((*data)[:4])) + } else { + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4])) + s.SourceIDClass, s.SourceIDIndex = sdc.decode() + } + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SamplingRate = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.SamplePool = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.Dropped = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + if expanded { + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.InputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.OutputInterfaceFormat = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + } else { + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.InputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.OutputInterface = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + } + if len(*data) < 4 { + return SFlowFlowSample{}, errors.New("ethernet counters too small") + } + *data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + for i := uint32(0); i < s.RecordCount; i++ { + rdf := SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + enterpriseID, flowRecordType := rdf.decode() + + // Try to decode when EnterpriseID is 0 signaling + // default sflow structs are used according specification + // Unexpected behavior detected for e.g. with pmacct + if enterpriseID == 0 { + switch flowRecordType { + case SFlowTypeRawPacketFlow: + if record, err := decodeRawPacketFlowRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedUserFlow: + if record, err := decodeExtendedUserFlow(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedUrlFlow: + if record, err := decodeExtendedURLRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedSwitchFlow: + if record, err := decodeExtendedSwitchFlowRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedRouterFlow: + if record, err := decodeExtendedRouterFlowRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedGatewayFlow: + if record, err := decodeExtendedGatewayFlowRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeEthernetFrameFlow: + if record, err := decodeEthernetFrameFlowRecord(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeIpv4Flow: + if record, err := decodeSFlowIpv4Record(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeIpv6Flow: + if record, err := decodeSFlowIpv6Record(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedMlpsFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedMlpsFlow") + case SFlowTypeExtendedNatFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedNatFlow") + case SFlowTypeExtendedMlpsTunnelFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedMlpsTunnelFlow") + case SFlowTypeExtendedMlpsVcFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedMlpsVcFlow") + case SFlowTypeExtendedMlpsFecFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedMlpsFecFlow") + case SFlowTypeExtendedMlpsLvpFecFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedMlpsLvpFecFlow") + case SFlowTypeExtendedVlanFlow: + // TODO + skipRecord(data) + return s, errors.New("skipping TypeExtendedVlanFlow") + case SFlowTypeExtendedIpv4TunnelEgressFlow: + if record, err := decodeExtendedIpv4TunnelEgress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedIpv4TunnelIngressFlow: + if record, err := decodeExtendedIpv4TunnelIngress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedIpv6TunnelEgressFlow: + if record, err := decodeExtendedIpv6TunnelEgress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedIpv6TunnelIngressFlow: + if record, err := decodeExtendedIpv6TunnelIngress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedDecapsulateEgressFlow: + if record, err := decodeExtendedDecapsulateEgress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedDecapsulateIngressFlow: + if record, err := decodeExtendedDecapsulateIngress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedVniEgressFlow: + if record, err := decodeExtendedVniEgress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeExtendedVniIngressFlow: + if record, err := decodeExtendedVniIngress(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + default: + return s, fmt.Errorf("Unsupported flow record type: %d", flowRecordType) + } + } else { + skipRecord(data) + } + } + return s, nil +} + +// Counter samples report information about various counter +// objects. Typically these are items like IfInOctets, or +// CPU / Memory stats, etc. SFlow will report these at regular +// intervals as configured on the agent. If one were sufficiently +// industrious, this could be used to replace the typical +// SNMP polling used for such things. +type SFlowCounterSample struct { + EnterpriseID SFlowEnterpriseID + Format SFlowSampleType + SampleLength uint32 + SequenceNumber uint32 + SourceIDClass SFlowSourceFormat + SourceIDIndex SFlowSourceValue + RecordCount uint32 + Records []SFlowRecord +} + +// Counter samples have the following structure: + +// SFlowCounterDataFormat +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int sample sequence number | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// |id type | src id index value | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | int number of records | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / counter records / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowCounterDataFormat uint32 + +func (cdf SFlowCounterDataFormat) decode() (SFlowEnterpriseID, SFlowCounterRecordType) { + leftField := cdf >> 12 + rightField := uint32(0xFFF) & uint32(cdf) + return SFlowEnterpriseID(leftField), SFlowCounterRecordType(rightField) +} + +// GetRecords will return a slice of interface types +// representing records. A type switch can be used to +// get at the underlying SFlowCounterRecordType. +func (cs SFlowCounterSample) GetRecords() []SFlowRecord { + return cs.Records +} + +// GetType will report the type of sample. Only the +// compact form of counter samples is supported +func (cs SFlowCounterSample) GetType() SFlowSampleType { + return SFlowTypeCounterSample +} + +type SFlowCounterRecordType uint32 + +const ( + SFlowTypeGenericInterfaceCounters SFlowCounterRecordType = 1 + SFlowTypeEthernetInterfaceCounters SFlowCounterRecordType = 2 + SFlowTypeTokenRingInterfaceCounters SFlowCounterRecordType = 3 + SFlowType100BaseVGInterfaceCounters SFlowCounterRecordType = 4 + SFlowTypeVLANCounters SFlowCounterRecordType = 5 + SFlowTypeLACPCounters SFlowCounterRecordType = 7 + SFlowTypeProcessorCounters SFlowCounterRecordType = 1001 + SFlowTypeOpenflowPortCounters SFlowCounterRecordType = 1004 + SFlowTypePORTNAMECounters SFlowCounterRecordType = 1005 + SFLowTypeAPPRESOURCESCounters SFlowCounterRecordType = 2203 + SFlowTypeOVSDPCounters SFlowCounterRecordType = 2207 +) + +func (cr SFlowCounterRecordType) String() string { + switch cr { + case SFlowTypeGenericInterfaceCounters: + return "Generic Interface Counters" + case SFlowTypeEthernetInterfaceCounters: + return "Ethernet Interface Counters" + case SFlowTypeTokenRingInterfaceCounters: + return "Token Ring Interface Counters" + case SFlowType100BaseVGInterfaceCounters: + return "100BaseVG Interface Counters" + case SFlowTypeVLANCounters: + return "VLAN Counters" + case SFlowTypeLACPCounters: + return "LACP Counters" + case SFlowTypeProcessorCounters: + return "Processor Counters" + case SFlowTypeOpenflowPortCounters: + return "Openflow Port Counters" + case SFlowTypePORTNAMECounters: + return "PORT NAME Counters" + case SFLowTypeAPPRESOURCESCounters: + return "App Resources Counters" + case SFlowTypeOVSDPCounters: + return "OVSDP Counters" + default: + return "" + + } +} + +func decodeCounterSample(data *[]byte, expanded bool) (SFlowCounterSample, error) { + s := SFlowCounterSample{} + var sdc SFlowDataSource + var sdce SFlowDataSourceExpanded + var sdf SFlowDataFormat + + *data, sdf = (*data)[4:], SFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + s.EnterpriseID, s.Format = sdf.decode() + *data, s.SampleLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, s.SequenceNumber = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if expanded { + *data, sdce = (*data)[8:], SFlowDataSourceExpanded{SFlowSourceFormat(binary.BigEndian.Uint32((*data)[:4])), SFlowSourceValue(binary.BigEndian.Uint32((*data)[4:8]))} + s.SourceIDClass, s.SourceIDIndex = sdce.decode() + } else { + *data, sdc = (*data)[4:], SFlowDataSource(binary.BigEndian.Uint32((*data)[:4])) + s.SourceIDClass, s.SourceIDIndex = sdc.decode() + } + *data, s.RecordCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + for i := uint32(0); i < s.RecordCount; i++ { + cdf := SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + _, counterRecordType := cdf.decode() + switch counterRecordType { + case SFlowTypeGenericInterfaceCounters: + if record, err := decodeGenericInterfaceCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeEthernetInterfaceCounters: + if record, err := decodeEthernetCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeTokenRingInterfaceCounters: + skipRecord(data) + return s, errors.New("skipping TypeTokenRingInterfaceCounters") + case SFlowType100BaseVGInterfaceCounters: + skipRecord(data) + return s, errors.New("skipping Type100BaseVGInterfaceCounters") + case SFlowTypeVLANCounters: + if record, err := decodeVLANCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeLACPCounters: + if record, err := decodeLACPCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeProcessorCounters: + if record, err := decodeProcessorCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeOpenflowPortCounters: + if record, err := decodeOpenflowportCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypePORTNAMECounters: + if record, err := decodePortnameCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFLowTypeAPPRESOURCESCounters: + if record, err := decodeAppresourcesCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + case SFlowTypeOVSDPCounters: + if record, err := decodeOVSDPCounters(data); err == nil { + s.Records = append(s.Records, record) + } else { + return s, err + } + default: + return s, fmt.Errorf("Invalid counter record type: %d", counterRecordType) + } + } + return s, nil +} + +// SFlowBaseFlowRecord holds the fields common to all records +// of type SFlowFlowRecordType +type SFlowBaseFlowRecord struct { + EnterpriseID SFlowEnterpriseID + Format SFlowFlowRecordType + FlowDataLength uint32 +} + +func (bfr SFlowBaseFlowRecord) GetType() SFlowFlowRecordType { + return bfr.Format +} + +// SFlowFlowRecordType denotes what kind of Flow Record is +// represented. See RFC 3176 +type SFlowFlowRecordType uint32 + +const ( + SFlowTypeRawPacketFlow SFlowFlowRecordType = 1 + SFlowTypeEthernetFrameFlow SFlowFlowRecordType = 2 + SFlowTypeIpv4Flow SFlowFlowRecordType = 3 + SFlowTypeIpv6Flow SFlowFlowRecordType = 4 + SFlowTypeExtendedSwitchFlow SFlowFlowRecordType = 1001 + SFlowTypeExtendedRouterFlow SFlowFlowRecordType = 1002 + SFlowTypeExtendedGatewayFlow SFlowFlowRecordType = 1003 + SFlowTypeExtendedUserFlow SFlowFlowRecordType = 1004 + SFlowTypeExtendedUrlFlow SFlowFlowRecordType = 1005 + SFlowTypeExtendedMlpsFlow SFlowFlowRecordType = 1006 + SFlowTypeExtendedNatFlow SFlowFlowRecordType = 1007 + SFlowTypeExtendedMlpsTunnelFlow SFlowFlowRecordType = 1008 + SFlowTypeExtendedMlpsVcFlow SFlowFlowRecordType = 1009 + SFlowTypeExtendedMlpsFecFlow SFlowFlowRecordType = 1010 + SFlowTypeExtendedMlpsLvpFecFlow SFlowFlowRecordType = 1011 + SFlowTypeExtendedVlanFlow SFlowFlowRecordType = 1012 + SFlowTypeExtendedIpv4TunnelEgressFlow SFlowFlowRecordType = 1023 + SFlowTypeExtendedIpv4TunnelIngressFlow SFlowFlowRecordType = 1024 + SFlowTypeExtendedIpv6TunnelEgressFlow SFlowFlowRecordType = 1025 + SFlowTypeExtendedIpv6TunnelIngressFlow SFlowFlowRecordType = 1026 + SFlowTypeExtendedDecapsulateEgressFlow SFlowFlowRecordType = 1027 + SFlowTypeExtendedDecapsulateIngressFlow SFlowFlowRecordType = 1028 + SFlowTypeExtendedVniEgressFlow SFlowFlowRecordType = 1029 + SFlowTypeExtendedVniIngressFlow SFlowFlowRecordType = 1030 +) + +func (rt SFlowFlowRecordType) String() string { + switch rt { + case SFlowTypeRawPacketFlow: + return "Raw Packet Flow Record" + case SFlowTypeEthernetFrameFlow: + return "Ethernet Frame Flow Record" + case SFlowTypeIpv4Flow: + return "IPv4 Flow Record" + case SFlowTypeIpv6Flow: + return "IPv6 Flow Record" + case SFlowTypeExtendedSwitchFlow: + return "Extended Switch Flow Record" + case SFlowTypeExtendedRouterFlow: + return "Extended Router Flow Record" + case SFlowTypeExtendedGatewayFlow: + return "Extended Gateway Flow Record" + case SFlowTypeExtendedUserFlow: + return "Extended User Flow Record" + case SFlowTypeExtendedUrlFlow: + return "Extended URL Flow Record" + case SFlowTypeExtendedMlpsFlow: + return "Extended MPLS Flow Record" + case SFlowTypeExtendedNatFlow: + return "Extended NAT Flow Record" + case SFlowTypeExtendedMlpsTunnelFlow: + return "Extended MPLS Tunnel Flow Record" + case SFlowTypeExtendedMlpsVcFlow: + return "Extended MPLS VC Flow Record" + case SFlowTypeExtendedMlpsFecFlow: + return "Extended MPLS FEC Flow Record" + case SFlowTypeExtendedMlpsLvpFecFlow: + return "Extended MPLS LVP FEC Flow Record" + case SFlowTypeExtendedVlanFlow: + return "Extended VLAN Flow Record" + case SFlowTypeExtendedIpv4TunnelEgressFlow: + return "Extended IPv4 Tunnel Egress Record" + case SFlowTypeExtendedIpv4TunnelIngressFlow: + return "Extended IPv4 Tunnel Ingress Record" + case SFlowTypeExtendedIpv6TunnelEgressFlow: + return "Extended IPv6 Tunnel Egress Record" + case SFlowTypeExtendedIpv6TunnelIngressFlow: + return "Extended IPv6 Tunnel Ingress Record" + case SFlowTypeExtendedDecapsulateEgressFlow: + return "Extended Decapsulate Egress Record" + case SFlowTypeExtendedDecapsulateIngressFlow: + return "Extended Decapsulate Ingress Record" + case SFlowTypeExtendedVniEgressFlow: + return "Extended VNI Ingress Record" + case SFlowTypeExtendedVniIngressFlow: + return "Extended VNI Ingress Record" + default: + return "" + } +} + +// SFlowRawPacketFlowRecords hold information about a sampled +// packet grabbed as it transited the agent. This is +// perhaps the most useful and interesting record type, +// as it holds the headers of the sampled packet and +// can be used to build up a complete picture of the +// traffic patterns on a network. +// +// The raw packet header is sent back into gopacket for +// decoding, and the resulting gopackt.Packet is stored +// in the Header member +type SFlowRawPacketFlowRecord struct { + SFlowBaseFlowRecord + HeaderProtocol SFlowRawHeaderProtocol + FrameLength uint32 + PayloadRemoved uint32 + HeaderLength uint32 + Header gopacket.Packet +} + +// Raw packet record types have the following structure: +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Header Protocol | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Frame Length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Payload Removed | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Header Length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// \ Header \ +// \ \ +// \ \ +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowRawHeaderProtocol uint32 + +const ( + SFlowProtoEthernet SFlowRawHeaderProtocol = 1 + SFlowProtoISO88024 SFlowRawHeaderProtocol = 2 + SFlowProtoISO88025 SFlowRawHeaderProtocol = 3 + SFlowProtoFDDI SFlowRawHeaderProtocol = 4 + SFlowProtoFrameRelay SFlowRawHeaderProtocol = 5 + SFlowProtoX25 SFlowRawHeaderProtocol = 6 + SFlowProtoPPP SFlowRawHeaderProtocol = 7 + SFlowProtoSMDS SFlowRawHeaderProtocol = 8 + SFlowProtoAAL5 SFlowRawHeaderProtocol = 9 + SFlowProtoAAL5_IP SFlowRawHeaderProtocol = 10 /* e.g. Cisco AAL5 mux */ + SFlowProtoIPv4 SFlowRawHeaderProtocol = 11 + SFlowProtoIPv6 SFlowRawHeaderProtocol = 12 + SFlowProtoMPLS SFlowRawHeaderProtocol = 13 + SFlowProtoPOS SFlowRawHeaderProtocol = 14 /* RFC 1662, 2615 */ +) + +func (sfhp SFlowRawHeaderProtocol) String() string { + switch sfhp { + case SFlowProtoEthernet: + return "ETHERNET-ISO88023" + case SFlowProtoISO88024: + return "ISO88024-TOKENBUS" + case SFlowProtoISO88025: + return "ISO88025-TOKENRING" + case SFlowProtoFDDI: + return "FDDI" + case SFlowProtoFrameRelay: + return "FRAME-RELAY" + case SFlowProtoX25: + return "X25" + case SFlowProtoPPP: + return "PPP" + case SFlowProtoSMDS: + return "SMDS" + case SFlowProtoAAL5: + return "AAL5" + case SFlowProtoAAL5_IP: + return "AAL5-IP" + case SFlowProtoIPv4: + return "IPv4" + case SFlowProtoIPv6: + return "IPv6" + case SFlowProtoMPLS: + return "MPLS" + case SFlowProtoPOS: + return "POS" + } + return "UNKNOWN" +} + +func decodeRawPacketFlowRecord(data *[]byte) (SFlowRawPacketFlowRecord, error) { + rec := SFlowRawPacketFlowRecord{} + header := []byte{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.HeaderProtocol = (*data)[4:], SFlowRawHeaderProtocol(binary.BigEndian.Uint32((*data)[:4])) + *data, rec.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.PayloadRemoved = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.HeaderLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + headerLenWithPadding := int(rec.HeaderLength + ((4 - rec.HeaderLength) % 4)) + *data, header = (*data)[headerLenWithPadding:], (*data)[:headerLenWithPadding] + rec.Header = gopacket.NewPacket(header, LayerTypeEthernet, gopacket.Default) + return rec, nil +} + +// SFlowExtendedSwitchFlowRecord give additional information +// about the sampled packet if it's available. It's mainly +// useful for getting at the incoming and outgoing VLANs +// An agent may or may not provide this information. +type SFlowExtendedSwitchFlowRecord struct { + SFlowBaseFlowRecord + IncomingVLAN uint32 + IncomingVLANPriority uint32 + OutgoingVLAN uint32 + OutgoingVLANPriority uint32 +} + +// Extended switch records have the following structure: +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Incoming VLAN | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Incoming VLAN Priority | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Outgoing VLAN | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Outgoing VLAN Priority | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +func decodeExtendedSwitchFlowRecord(data *[]byte) (SFlowExtendedSwitchFlowRecord, error) { + es := SFlowExtendedSwitchFlowRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + es.EnterpriseID, es.Format = fdf.decode() + *data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, es.IncomingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, es.IncomingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, es.OutgoingVLAN = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, es.OutgoingVLANPriority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return es, nil +} + +// SFlowExtendedRouterFlowRecord gives additional information +// about the layer 3 routing information used to forward +// the packet +type SFlowExtendedRouterFlowRecord struct { + SFlowBaseFlowRecord + NextHop net.IP + NextHopSourceMask uint32 + NextHopDestinationMask uint32 +} + +// Extended router records have the following structure: +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IP version of next hop router (1=v4|2=v6) | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Next Hop address (v4=4byte|v6=16byte) / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Next Hop Source Mask | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Next Hop Destination Mask | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +func decodeExtendedRouterFlowRecord(data *[]byte) (SFlowExtendedRouterFlowRecord, error) { + er := SFlowExtendedRouterFlowRecord{} + var fdf SFlowFlowDataFormat + var extendedRouterAddressType SFlowIPType + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + er.EnterpriseID, er.Format = fdf.decode() + *data, er.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, extendedRouterAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4])) + *data, er.NextHop = (*data)[extendedRouterAddressType.Length():], (*data)[:extendedRouterAddressType.Length()] + *data, er.NextHopSourceMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, er.NextHopDestinationMask = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return er, nil +} + +// SFlowExtendedGatewayFlowRecord describes information treasured by +// nework engineers everywhere: AS path information listing which +// BGP peer sent the packet, and various other BGP related info. +// This information is vital because it gives a picture of how much +// traffic is being sent from / received by various BGP peers. + +// Extended gateway records have the following structure: +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IP version of next hop router (1=v4|2=v6) | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Next Hop address (v4=4byte|v6=16byte) / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | AS | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source AS | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Peer AS | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | AS Path Count | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / AS Path / Sequence / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Communities / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Local Pref | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// AS Path / Sequence: + +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | AS Source Type (Path=1 / Sequence=2) | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Path / Sequence length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Path / Sequence Members / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +// Communities: + +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | communitiy length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / communitiy Members / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowExtendedGatewayFlowRecord struct { + SFlowBaseFlowRecord + NextHop net.IP + AS uint32 + SourceAS uint32 + PeerAS uint32 + ASPathCount uint32 + ASPath []SFlowASDestination + Communities []uint32 + LocalPref uint32 +} + +type SFlowASPathType uint32 + +const ( + SFlowASSet SFlowASPathType = 1 + SFlowASSequence SFlowASPathType = 2 +) + +func (apt SFlowASPathType) String() string { + switch apt { + case SFlowASSet: + return "AS Set" + case SFlowASSequence: + return "AS Sequence" + default: + return "" + } +} + +type SFlowASDestination struct { + Type SFlowASPathType + Count uint32 + Members []uint32 +} + +func (asd SFlowASDestination) String() string { + switch asd.Type { + case SFlowASSet: + return fmt.Sprint("AS Set:", asd.Members) + case SFlowASSequence: + return fmt.Sprint("AS Sequence:", asd.Members) + default: + return "" + } +} + +func (ad *SFlowASDestination) decodePath(data *[]byte) { + *data, ad.Type = (*data)[4:], SFlowASPathType(binary.BigEndian.Uint32((*data)[:4])) + *data, ad.Count = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + ad.Members = make([]uint32, ad.Count) + for i := uint32(0); i < ad.Count; i++ { + var member uint32 + *data, member = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + ad.Members[i] = member + } +} + +func decodeExtendedGatewayFlowRecord(data *[]byte) (SFlowExtendedGatewayFlowRecord, error) { + eg := SFlowExtendedGatewayFlowRecord{} + var fdf SFlowFlowDataFormat + var extendedGatewayAddressType SFlowIPType + var communitiesLength uint32 + var community uint32 + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + eg.EnterpriseID, eg.Format = fdf.decode() + *data, eg.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, extendedGatewayAddressType = (*data)[4:], SFlowIPType(binary.BigEndian.Uint32((*data)[:4])) + *data, eg.NextHop = (*data)[extendedGatewayAddressType.Length():], (*data)[:extendedGatewayAddressType.Length()] + *data, eg.AS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, eg.SourceAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, eg.PeerAS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, eg.ASPathCount = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + for i := uint32(0); i < eg.ASPathCount; i++ { + asPath := SFlowASDestination{} + asPath.decodePath(data) + eg.ASPath = append(eg.ASPath, asPath) + } + *data, communitiesLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + eg.Communities = make([]uint32, communitiesLength) + for j := uint32(0); j < communitiesLength; j++ { + *data, community = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + eg.Communities[j] = community + } + *data, eg.LocalPref = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return eg, nil +} + +// ************************************************** +// Extended URL Flow Record +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | direction | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | URL | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Host | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowURLDirection uint32 + +const ( + SFlowURLsrc SFlowURLDirection = 1 + SFlowURLdst SFlowURLDirection = 2 +) + +func (urld SFlowURLDirection) String() string { + switch urld { + case SFlowURLsrc: + return "Source address is the server" + case SFlowURLdst: + return "Destination address is the server" + default: + return "" + } +} + +type SFlowExtendedURLRecord struct { + SFlowBaseFlowRecord + Direction SFlowURLDirection + URL string + Host string +} + +func decodeExtendedURLRecord(data *[]byte) (SFlowExtendedURLRecord, error) { + eur := SFlowExtendedURLRecord{} + var fdf SFlowFlowDataFormat + var urlLen uint32 + var urlLenWithPad int + var hostLen uint32 + var hostLenWithPad int + var urlBytes []byte + var hostBytes []byte + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + eur.EnterpriseID, eur.Format = fdf.decode() + *data, eur.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, eur.Direction = (*data)[4:], SFlowURLDirection(binary.BigEndian.Uint32((*data)[:4])) + *data, urlLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + urlLenWithPad = int(urlLen + ((4 - urlLen) % 4)) + *data, urlBytes = (*data)[urlLenWithPad:], (*data)[:urlLenWithPad] + eur.URL = string(urlBytes[:urlLen]) + *data, hostLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + hostLenWithPad = int(hostLen + ((4 - hostLen) % 4)) + *data, hostBytes = (*data)[hostLenWithPad:], (*data)[:hostLenWithPad] + eur.Host = string(hostBytes[:hostLen]) + return eur, nil +} + +// ************************************************** +// Extended User Flow Record +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source Character Set | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source User Id | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destination Character Set | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destination User ID | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowExtendedUserFlow struct { + SFlowBaseFlowRecord + SourceCharSet SFlowCharSet + SourceUserID string + DestinationCharSet SFlowCharSet + DestinationUserID string +} + +type SFlowCharSet uint32 + +const ( + SFlowCSunknown SFlowCharSet = 2 + SFlowCSASCII SFlowCharSet = 3 + SFlowCSISOLatin1 SFlowCharSet = 4 + SFlowCSISOLatin2 SFlowCharSet = 5 + SFlowCSISOLatin3 SFlowCharSet = 6 + SFlowCSISOLatin4 SFlowCharSet = 7 + SFlowCSISOLatinCyrillic SFlowCharSet = 8 + SFlowCSISOLatinArabic SFlowCharSet = 9 + SFlowCSISOLatinGreek SFlowCharSet = 10 + SFlowCSISOLatinHebrew SFlowCharSet = 11 + SFlowCSISOLatin5 SFlowCharSet = 12 + SFlowCSISOLatin6 SFlowCharSet = 13 + SFlowCSISOTextComm SFlowCharSet = 14 + SFlowCSHalfWidthKatakana SFlowCharSet = 15 + SFlowCSJISEncoding SFlowCharSet = 16 + SFlowCSShiftJIS SFlowCharSet = 17 + SFlowCSEUCPkdFmtJapanese SFlowCharSet = 18 + SFlowCSEUCFixWidJapanese SFlowCharSet = 19 + SFlowCSISO4UnitedKingdom SFlowCharSet = 20 + SFlowCSISO11SwedishForNames SFlowCharSet = 21 + SFlowCSISO15Italian SFlowCharSet = 22 + SFlowCSISO17Spanish SFlowCharSet = 23 + SFlowCSISO21German SFlowCharSet = 24 + SFlowCSISO60DanishNorwegian SFlowCharSet = 25 + SFlowCSISO69French SFlowCharSet = 26 + SFlowCSISO10646UTF1 SFlowCharSet = 27 + SFlowCSISO646basic1983 SFlowCharSet = 28 + SFlowCSINVARIANT SFlowCharSet = 29 + SFlowCSISO2IntlRefVersion SFlowCharSet = 30 + SFlowCSNATSSEFI SFlowCharSet = 31 + SFlowCSNATSSEFIADD SFlowCharSet = 32 + SFlowCSNATSDANO SFlowCharSet = 33 + SFlowCSNATSDANOADD SFlowCharSet = 34 + SFlowCSISO10Swedish SFlowCharSet = 35 + SFlowCSKSC56011987 SFlowCharSet = 36 + SFlowCSISO2022KR SFlowCharSet = 37 + SFlowCSEUCKR SFlowCharSet = 38 + SFlowCSISO2022JP SFlowCharSet = 39 + SFlowCSISO2022JP2 SFlowCharSet = 40 + SFlowCSISO13JISC6220jp SFlowCharSet = 41 + SFlowCSISO14JISC6220ro SFlowCharSet = 42 + SFlowCSISO16Portuguese SFlowCharSet = 43 + SFlowCSISO18Greek7Old SFlowCharSet = 44 + SFlowCSISO19LatinGreek SFlowCharSet = 45 + SFlowCSISO25French SFlowCharSet = 46 + SFlowCSISO27LatinGreek1 SFlowCharSet = 47 + SFlowCSISO5427Cyrillic SFlowCharSet = 48 + SFlowCSISO42JISC62261978 SFlowCharSet = 49 + SFlowCSISO47BSViewdata SFlowCharSet = 50 + SFlowCSISO49INIS SFlowCharSet = 51 + SFlowCSISO50INIS8 SFlowCharSet = 52 + SFlowCSISO51INISCyrillic SFlowCharSet = 53 + SFlowCSISO54271981 SFlowCharSet = 54 + SFlowCSISO5428Greek SFlowCharSet = 55 + SFlowCSISO57GB1988 SFlowCharSet = 56 + SFlowCSISO58GB231280 SFlowCharSet = 57 + SFlowCSISO61Norwegian2 SFlowCharSet = 58 + SFlowCSISO70VideotexSupp1 SFlowCharSet = 59 + SFlowCSISO84Portuguese2 SFlowCharSet = 60 + SFlowCSISO85Spanish2 SFlowCharSet = 61 + SFlowCSISO86Hungarian SFlowCharSet = 62 + SFlowCSISO87JISX0208 SFlowCharSet = 63 + SFlowCSISO88Greek7 SFlowCharSet = 64 + SFlowCSISO89ASMO449 SFlowCharSet = 65 + SFlowCSISO90 SFlowCharSet = 66 + SFlowCSISO91JISC62291984a SFlowCharSet = 67 + SFlowCSISO92JISC62991984b SFlowCharSet = 68 + SFlowCSISO93JIS62291984badd SFlowCharSet = 69 + SFlowCSISO94JIS62291984hand SFlowCharSet = 70 + SFlowCSISO95JIS62291984handadd SFlowCharSet = 71 + SFlowCSISO96JISC62291984kana SFlowCharSet = 72 + SFlowCSISO2033 SFlowCharSet = 73 + SFlowCSISO99NAPLPS SFlowCharSet = 74 + SFlowCSISO102T617bit SFlowCharSet = 75 + SFlowCSISO103T618bit SFlowCharSet = 76 + SFlowCSISO111ECMACyrillic SFlowCharSet = 77 + SFlowCSa71 SFlowCharSet = 78 + SFlowCSa72 SFlowCharSet = 79 + SFlowCSISO123CSAZ24341985gr SFlowCharSet = 80 + SFlowCSISO88596E SFlowCharSet = 81 + SFlowCSISO88596I SFlowCharSet = 82 + SFlowCSISO128T101G2 SFlowCharSet = 83 + SFlowCSISO88598E SFlowCharSet = 84 + SFlowCSISO88598I SFlowCharSet = 85 + SFlowCSISO139CSN369103 SFlowCharSet = 86 + SFlowCSISO141JUSIB1002 SFlowCharSet = 87 + SFlowCSISO143IECP271 SFlowCharSet = 88 + SFlowCSISO146Serbian SFlowCharSet = 89 + SFlowCSISO147Macedonian SFlowCharSet = 90 + SFlowCSISO150 SFlowCharSet = 91 + SFlowCSISO151Cuba SFlowCharSet = 92 + SFlowCSISO6937Add SFlowCharSet = 93 + SFlowCSISO153GOST1976874 SFlowCharSet = 94 + SFlowCSISO8859Supp SFlowCharSet = 95 + SFlowCSISO10367Box SFlowCharSet = 96 + SFlowCSISO158Lap SFlowCharSet = 97 + SFlowCSISO159JISX02121990 SFlowCharSet = 98 + SFlowCSISO646Danish SFlowCharSet = 99 + SFlowCSUSDK SFlowCharSet = 100 + SFlowCSDKUS SFlowCharSet = 101 + SFlowCSKSC5636 SFlowCharSet = 102 + SFlowCSUnicode11UTF7 SFlowCharSet = 103 + SFlowCSISO2022CN SFlowCharSet = 104 + SFlowCSISO2022CNEXT SFlowCharSet = 105 + SFlowCSUTF8 SFlowCharSet = 106 + SFlowCSISO885913 SFlowCharSet = 109 + SFlowCSISO885914 SFlowCharSet = 110 + SFlowCSISO885915 SFlowCharSet = 111 + SFlowCSISO885916 SFlowCharSet = 112 + SFlowCSGBK SFlowCharSet = 113 + SFlowCSGB18030 SFlowCharSet = 114 + SFlowCSOSDEBCDICDF0415 SFlowCharSet = 115 + SFlowCSOSDEBCDICDF03IRV SFlowCharSet = 116 + SFlowCSOSDEBCDICDF041 SFlowCharSet = 117 + SFlowCSISO115481 SFlowCharSet = 118 + SFlowCSKZ1048 SFlowCharSet = 119 + SFlowCSUnicode SFlowCharSet = 1000 + SFlowCSUCS4 SFlowCharSet = 1001 + SFlowCSUnicodeASCII SFlowCharSet = 1002 + SFlowCSUnicodeLatin1 SFlowCharSet = 1003 + SFlowCSUnicodeJapanese SFlowCharSet = 1004 + SFlowCSUnicodeIBM1261 SFlowCharSet = 1005 + SFlowCSUnicodeIBM1268 SFlowCharSet = 1006 + SFlowCSUnicodeIBM1276 SFlowCharSet = 1007 + SFlowCSUnicodeIBM1264 SFlowCharSet = 1008 + SFlowCSUnicodeIBM1265 SFlowCharSet = 1009 + SFlowCSUnicode11 SFlowCharSet = 1010 + SFlowCSSCSU SFlowCharSet = 1011 + SFlowCSUTF7 SFlowCharSet = 1012 + SFlowCSUTF16BE SFlowCharSet = 1013 + SFlowCSUTF16LE SFlowCharSet = 1014 + SFlowCSUTF16 SFlowCharSet = 1015 + SFlowCSCESU8 SFlowCharSet = 1016 + SFlowCSUTF32 SFlowCharSet = 1017 + SFlowCSUTF32BE SFlowCharSet = 1018 + SFlowCSUTF32LE SFlowCharSet = 1019 + SFlowCSBOCU1 SFlowCharSet = 1020 + SFlowCSWindows30Latin1 SFlowCharSet = 2000 + SFlowCSWindows31Latin1 SFlowCharSet = 2001 + SFlowCSWindows31Latin2 SFlowCharSet = 2002 + SFlowCSWindows31Latin5 SFlowCharSet = 2003 + SFlowCSHPRoman8 SFlowCharSet = 2004 + SFlowCSAdobeStandardEncoding SFlowCharSet = 2005 + SFlowCSVenturaUS SFlowCharSet = 2006 + SFlowCSVenturaInternational SFlowCharSet = 2007 + SFlowCSDECMCS SFlowCharSet = 2008 + SFlowCSPC850Multilingual SFlowCharSet = 2009 + SFlowCSPCp852 SFlowCharSet = 2010 + SFlowCSPC8CodePage437 SFlowCharSet = 2011 + SFlowCSPC8DanishNorwegian SFlowCharSet = 2012 + SFlowCSPC862LatinHebrew SFlowCharSet = 2013 + SFlowCSPC8Turkish SFlowCharSet = 2014 + SFlowCSIBMSymbols SFlowCharSet = 2015 + SFlowCSIBMThai SFlowCharSet = 2016 + SFlowCSHPLegal SFlowCharSet = 2017 + SFlowCSHPPiFont SFlowCharSet = 2018 + SFlowCSHPMath8 SFlowCharSet = 2019 + SFlowCSHPPSMath SFlowCharSet = 2020 + SFlowCSHPDesktop SFlowCharSet = 2021 + SFlowCSVenturaMath SFlowCharSet = 2022 + SFlowCSMicrosoftPublishing SFlowCharSet = 2023 + SFlowCSWindows31J SFlowCharSet = 2024 + SFlowCSGB2312 SFlowCharSet = 2025 + SFlowCSBig5 SFlowCharSet = 2026 + SFlowCSMacintosh SFlowCharSet = 2027 + SFlowCSIBM037 SFlowCharSet = 2028 + SFlowCSIBM038 SFlowCharSet = 2029 + SFlowCSIBM273 SFlowCharSet = 2030 + SFlowCSIBM274 SFlowCharSet = 2031 + SFlowCSIBM275 SFlowCharSet = 2032 + SFlowCSIBM277 SFlowCharSet = 2033 + SFlowCSIBM278 SFlowCharSet = 2034 + SFlowCSIBM280 SFlowCharSet = 2035 + SFlowCSIBM281 SFlowCharSet = 2036 + SFlowCSIBM284 SFlowCharSet = 2037 + SFlowCSIBM285 SFlowCharSet = 2038 + SFlowCSIBM290 SFlowCharSet = 2039 + SFlowCSIBM297 SFlowCharSet = 2040 + SFlowCSIBM420 SFlowCharSet = 2041 + SFlowCSIBM423 SFlowCharSet = 2042 + SFlowCSIBM424 SFlowCharSet = 2043 + SFlowCSIBM500 SFlowCharSet = 2044 + SFlowCSIBM851 SFlowCharSet = 2045 + SFlowCSIBM855 SFlowCharSet = 2046 + SFlowCSIBM857 SFlowCharSet = 2047 + SFlowCSIBM860 SFlowCharSet = 2048 + SFlowCSIBM861 SFlowCharSet = 2049 + SFlowCSIBM863 SFlowCharSet = 2050 + SFlowCSIBM864 SFlowCharSet = 2051 + SFlowCSIBM865 SFlowCharSet = 2052 + SFlowCSIBM868 SFlowCharSet = 2053 + SFlowCSIBM869 SFlowCharSet = 2054 + SFlowCSIBM870 SFlowCharSet = 2055 + SFlowCSIBM871 SFlowCharSet = 2056 + SFlowCSIBM880 SFlowCharSet = 2057 + SFlowCSIBM891 SFlowCharSet = 2058 + SFlowCSIBM903 SFlowCharSet = 2059 + SFlowCSIBBM904 SFlowCharSet = 2060 + SFlowCSIBM905 SFlowCharSet = 2061 + SFlowCSIBM918 SFlowCharSet = 2062 + SFlowCSIBM1026 SFlowCharSet = 2063 + SFlowCSIBMEBCDICATDE SFlowCharSet = 2064 + SFlowCSEBCDICATDEA SFlowCharSet = 2065 + SFlowCSEBCDICCAFR SFlowCharSet = 2066 + SFlowCSEBCDICDKNO SFlowCharSet = 2067 + SFlowCSEBCDICDKNOA SFlowCharSet = 2068 + SFlowCSEBCDICFISE SFlowCharSet = 2069 + SFlowCSEBCDICFISEA SFlowCharSet = 2070 + SFlowCSEBCDICFR SFlowCharSet = 2071 + SFlowCSEBCDICIT SFlowCharSet = 2072 + SFlowCSEBCDICPT SFlowCharSet = 2073 + SFlowCSEBCDICES SFlowCharSet = 2074 + SFlowCSEBCDICESA SFlowCharSet = 2075 + SFlowCSEBCDICESS SFlowCharSet = 2076 + SFlowCSEBCDICUK SFlowCharSet = 2077 + SFlowCSEBCDICUS SFlowCharSet = 2078 + SFlowCSUnknown8BiT SFlowCharSet = 2079 + SFlowCSMnemonic SFlowCharSet = 2080 + SFlowCSMnem SFlowCharSet = 2081 + SFlowCSVISCII SFlowCharSet = 2082 + SFlowCSVIQR SFlowCharSet = 2083 + SFlowCSKOI8R SFlowCharSet = 2084 + SFlowCSHZGB2312 SFlowCharSet = 2085 + SFlowCSIBM866 SFlowCharSet = 2086 + SFlowCSPC775Baltic SFlowCharSet = 2087 + SFlowCSKOI8U SFlowCharSet = 2088 + SFlowCSIBM00858 SFlowCharSet = 2089 + SFlowCSIBM00924 SFlowCharSet = 2090 + SFlowCSIBM01140 SFlowCharSet = 2091 + SFlowCSIBM01141 SFlowCharSet = 2092 + SFlowCSIBM01142 SFlowCharSet = 2093 + SFlowCSIBM01143 SFlowCharSet = 2094 + SFlowCSIBM01144 SFlowCharSet = 2095 + SFlowCSIBM01145 SFlowCharSet = 2096 + SFlowCSIBM01146 SFlowCharSet = 2097 + SFlowCSIBM01147 SFlowCharSet = 2098 + SFlowCSIBM01148 SFlowCharSet = 2099 + SFlowCSIBM01149 SFlowCharSet = 2100 + SFlowCSBig5HKSCS SFlowCharSet = 2101 + SFlowCSIBM1047 SFlowCharSet = 2102 + SFlowCSPTCP154 SFlowCharSet = 2103 + SFlowCSAmiga1251 SFlowCharSet = 2104 + SFlowCSKOI7switched SFlowCharSet = 2105 + SFlowCSBRF SFlowCharSet = 2106 + SFlowCSTSCII SFlowCharSet = 2107 + SFlowCSCP51932 SFlowCharSet = 2108 + SFlowCSWindows874 SFlowCharSet = 2109 + SFlowCSWindows1250 SFlowCharSet = 2250 + SFlowCSWindows1251 SFlowCharSet = 2251 + SFlowCSWindows1252 SFlowCharSet = 2252 + SFlowCSWindows1253 SFlowCharSet = 2253 + SFlowCSWindows1254 SFlowCharSet = 2254 + SFlowCSWindows1255 SFlowCharSet = 2255 + SFlowCSWindows1256 SFlowCharSet = 2256 + SFlowCSWindows1257 SFlowCharSet = 2257 + SFlowCSWindows1258 SFlowCharSet = 2258 + SFlowCSTIS620 SFlowCharSet = 2259 + SFlowCS50220 SFlowCharSet = 2260 + SFlowCSreserved SFlowCharSet = 3000 +) + +func decodeExtendedUserFlow(data *[]byte) (SFlowExtendedUserFlow, error) { + eu := SFlowExtendedUserFlow{} + var fdf SFlowFlowDataFormat + var srcUserLen uint32 + var srcUserLenWithPad int + var srcUserBytes []byte + var dstUserLen uint32 + var dstUserLenWithPad int + var dstUserBytes []byte + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + eu.EnterpriseID, eu.Format = fdf.decode() + *data, eu.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, eu.SourceCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4])) + *data, srcUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + srcUserLenWithPad = int(srcUserLen + ((4 - srcUserLen) % 4)) + *data, srcUserBytes = (*data)[srcUserLenWithPad:], (*data)[:srcUserLenWithPad] + eu.SourceUserID = string(srcUserBytes[:srcUserLen]) + *data, eu.DestinationCharSet = (*data)[4:], SFlowCharSet(binary.BigEndian.Uint32((*data)[:4])) + *data, dstUserLen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + dstUserLenWithPad = int(dstUserLen + ((4 - dstUserLen) % 4)) + *data, dstUserBytes = (*data)[dstUserLenWithPad:], (*data)[:dstUserLenWithPad] + eu.DestinationUserID = string(dstUserBytes[:dstUserLen]) + return eu, nil +} + +// ************************************************** +// Packet IP version 4 Record +// ************************************************** + +// SFlowIpv4Record +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Protocol | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source IPv4 | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destination IPv4 | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source Port | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destionation Port | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TCP Flags | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TOS | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowIpv4Record struct { + // The length of the IP packet excluding ower layer encapsulations + Length uint32 + // IP Protocol type (for example, TCP = 6, UDP = 17) + Protocol uint32 + // Source IP Address + IPSrc net.IP + // Destination IP Address + IPDst net.IP + // TCP/UDP source port number or equivalent + PortSrc uint32 + // TCP/UDP destination port number or equivalent + PortDst uint32 + // TCP flags + TCPFlags uint32 + // IP type of service + TOS uint32 +} + +func decodeSFlowIpv4Record(data *[]byte) (SFlowIpv4Record, error) { + si := SFlowIpv4Record{} + + *data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.IPSrc = (*data)[4:], net.IP((*data)[:4]) + *data, si.IPDst = (*data)[4:], net.IP((*data)[:4]) + *data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.TOS = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return si, nil +} + +// ************************************************** +// +// Packet IP version 6 Record +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Protocol | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source IPv4 | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destination IPv4 | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source Port | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destionation Port | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TCP Flags | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Priority | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowIpv6Record struct { + // The length of the IP packet excluding ower layer encapsulations + Length uint32 + // IP Protocol type (for example, TCP = 6, UDP = 17) + Protocol uint32 + // Source IP Address + IPSrc net.IP + // Destination IP Address + IPDst net.IP + // TCP/UDP source port number or equivalent + PortSrc uint32 + // TCP/UDP destination port number or equivalent + PortDst uint32 + // TCP flags + TCPFlags uint32 + // IP priority + Priority uint32 +} + +func decodeSFlowIpv6Record(data *[]byte) (SFlowIpv6Record, error) { + si := SFlowIpv6Record{} + + *data, si.Length = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.Protocol = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.IPSrc = (*data)[16:], net.IP((*data)[:16]) + *data, si.IPDst = (*data)[16:], net.IP((*data)[:16]) + *data, si.PortSrc = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.PortDst = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.TCPFlags = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, si.Priority = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return si, nil +} + +// ************************************************** +// +// Extended IPv4 Tunnel Egress +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Packet IP version 4 Record / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedIpv4TunnelEgressRecord struct { + SFlowBaseFlowRecord + SFlowIpv4Record SFlowIpv4Record +} + +func decodeExtendedIpv4TunnelEgress(data *[]byte) (SFlowExtendedIpv4TunnelEgressRecord, error) { + rec := SFlowExtendedIpv4TunnelEgressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data) + + return rec, nil +} + +// ************************************************** +// +// Extended IPv4 Tunnel Ingress +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Packet IP version 4 Record / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedIpv4TunnelIngressRecord struct { + SFlowBaseFlowRecord + SFlowIpv4Record SFlowIpv4Record +} + +func decodeExtendedIpv4TunnelIngress(data *[]byte) (SFlowExtendedIpv4TunnelIngressRecord, error) { + rec := SFlowExtendedIpv4TunnelIngressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + rec.SFlowIpv4Record, _ = decodeSFlowIpv4Record(data) + + return rec, nil +} + +// ************************************************** +// +// Extended IPv6 Tunnel Egress +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Packet IP version 6 Record / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedIpv6TunnelEgressRecord struct { + SFlowBaseFlowRecord + SFlowIpv6Record +} + +func decodeExtendedIpv6TunnelEgress(data *[]byte) (SFlowExtendedIpv6TunnelEgressRecord, error) { + rec := SFlowExtendedIpv6TunnelEgressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data) + + return rec, nil +} + +// ************************************************** +// +// Extended IPv6 Tunnel Ingress +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / Packet IP version 6 Record / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedIpv6TunnelIngressRecord struct { + SFlowBaseFlowRecord + SFlowIpv6Record +} + +func decodeExtendedIpv6TunnelIngress(data *[]byte) (SFlowExtendedIpv6TunnelIngressRecord, error) { + rec := SFlowExtendedIpv6TunnelIngressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + rec.SFlowIpv6Record, _ = decodeSFlowIpv6Record(data) + + return rec, nil +} + +// ************************************************** +// +// Extended Decapsulate Egress +// +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Inner Header Offset | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedDecapsulateEgressRecord struct { + SFlowBaseFlowRecord + InnerHeaderOffset uint32 +} + +func decodeExtendedDecapsulateEgress(data *[]byte) (SFlowExtendedDecapsulateEgressRecord, error) { + rec := SFlowExtendedDecapsulateEgressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return rec, nil +} + +// ************************************************** +// +// Extended Decapsulate Ingress +// +// ************************************************** + +// SFlowExtendedDecapsulateIngressRecord +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Inner Header Offset | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedDecapsulateIngressRecord struct { + SFlowBaseFlowRecord + InnerHeaderOffset uint32 +} + +func decodeExtendedDecapsulateIngress(data *[]byte) (SFlowExtendedDecapsulateIngressRecord, error) { + rec := SFlowExtendedDecapsulateIngressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.InnerHeaderOffset = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return rec, nil +} + +// ************************************************** +// +// Extended VNI Egress +// +// ************************************************** + +// SFlowExtendedVniEgressRecord +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | VNI | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedVniEgressRecord struct { + SFlowBaseFlowRecord + VNI uint32 +} + +func decodeExtendedVniEgress(data *[]byte) (SFlowExtendedVniEgressRecord, error) { + rec := SFlowExtendedVniEgressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return rec, nil +} + +// ************************************************** +// +// Extended VNI Ingress +// +// ************************************************** + +// SFlowExtendedVniIngressRecord +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | VNI | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowExtendedVniIngressRecord struct { + SFlowBaseFlowRecord + VNI uint32 +} + +func decodeExtendedVniIngress(data *[]byte) (SFlowExtendedVniIngressRecord, error) { + rec := SFlowExtendedVniIngressRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + rec.EnterpriseID, rec.Format = fdf.decode() + *data, rec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, rec.VNI = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return rec, nil +} + +// ************************************************** +// Counter Record +// ************************************************** + +// SFlowBaseCounterRecord +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | counter length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | counter data | +// | | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +type SFlowBaseCounterRecord struct { + EnterpriseID SFlowEnterpriseID + Format SFlowCounterRecordType + FlowDataLength uint32 +} + +func (bcr SFlowBaseCounterRecord) GetType() SFlowCounterRecordType { + switch bcr.Format { + case SFlowTypeGenericInterfaceCounters: + return SFlowTypeGenericInterfaceCounters + case SFlowTypeEthernetInterfaceCounters: + return SFlowTypeEthernetInterfaceCounters + case SFlowTypeTokenRingInterfaceCounters: + return SFlowTypeTokenRingInterfaceCounters + case SFlowType100BaseVGInterfaceCounters: + return SFlowType100BaseVGInterfaceCounters + case SFlowTypeVLANCounters: + return SFlowTypeVLANCounters + case SFlowTypeLACPCounters: + return SFlowTypeLACPCounters + case SFlowTypeProcessorCounters: + return SFlowTypeProcessorCounters + case SFlowTypeOpenflowPortCounters: + return SFlowTypeOpenflowPortCounters + case SFlowTypePORTNAMECounters: + return SFlowTypePORTNAMECounters + case SFLowTypeAPPRESOURCESCounters: + return SFLowTypeAPPRESOURCESCounters + case SFlowTypeOVSDPCounters: + return SFlowTypeOVSDPCounters + } + unrecognized := fmt.Sprint("Unrecognized counter record type:", bcr.Format) + panic(unrecognized) +} + +// ************************************************** +// Counter Record +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | counter length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfIndex | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfType | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfSpeed | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfDirection | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfStatus | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IFInOctets | +// | | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfInUcastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfInMulticastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfInBroadcastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfInDiscards | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | InInErrors | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfInUnknownProtos | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOutOctets | +// | | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOutUcastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOutMulticastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOutBroadcastPkts | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOutDiscards | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfOUtErrors | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | IfPromiscouousMode | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowGenericInterfaceCounters struct { + SFlowBaseCounterRecord + IfIndex uint32 + IfType uint32 + IfSpeed uint64 + IfDirection uint32 + IfStatus uint32 + IfInOctets uint64 + IfInUcastPkts uint32 + IfInMulticastPkts uint32 + IfInBroadcastPkts uint32 + IfInDiscards uint32 + IfInErrors uint32 + IfInUnknownProtos uint32 + IfOutOctets uint64 + IfOutUcastPkts uint32 + IfOutMulticastPkts uint32 + IfOutBroadcastPkts uint32 + IfOutDiscards uint32 + IfOutErrors uint32 + IfPromiscuousMode uint32 +} + +func decodeGenericInterfaceCounters(data *[]byte) (SFlowGenericInterfaceCounters, error) { + gic := SFlowGenericInterfaceCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + gic.EnterpriseID, gic.Format = cdf.decode() + *data, gic.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfIndex = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfType = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfSpeed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, gic.IfDirection = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfStatus = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, gic.IfInUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfInUnknownProtos = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfOutOctets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, gic.IfOutUcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfOutMulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfOutBroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfOutDiscards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfOutErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, gic.IfPromiscuousMode = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return gic, nil +} + +// ************************************************** +// Counter Record +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | counter length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// / counter data / +// / / +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowEthernetCounters struct { + SFlowBaseCounterRecord + AlignmentErrors uint32 + FCSErrors uint32 + SingleCollisionFrames uint32 + MultipleCollisionFrames uint32 + SQETestErrors uint32 + DeferredTransmissions uint32 + LateCollisions uint32 + ExcessiveCollisions uint32 + InternalMacTransmitErrors uint32 + CarrierSenseErrors uint32 + FrameTooLongs uint32 + InternalMacReceiveErrors uint32 + SymbolErrors uint32 +} + +func decodeEthernetCounters(data *[]byte) (SFlowEthernetCounters, error) { + ec := SFlowEthernetCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + ec.EnterpriseID, ec.Format = cdf.decode() + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.AlignmentErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.FCSErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.SingleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.MultipleCollisionFrames = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.SQETestErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.DeferredTransmissions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.LateCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.ExcessiveCollisions = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.InternalMacTransmitErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.CarrierSenseErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.FrameTooLongs = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.InternalMacReceiveErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + if len(*data) < 4 { + return SFlowEthernetCounters{}, errors.New("ethernet counters too small") + } + *data, ec.SymbolErrors = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return ec, nil +} + +// VLAN Counter + +type SFlowVLANCounters struct { + SFlowBaseCounterRecord + VlanID uint32 + Octets uint64 + UcastPkts uint32 + MulticastPkts uint32 + BroadcastPkts uint32 + Discards uint32 +} + +func decodeVLANCounters(data *[]byte) (SFlowVLANCounters, error) { + vc := SFlowVLANCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + vc.EnterpriseID, vc.Format = cdf.decode() + vc.EnterpriseID, vc.Format = cdf.decode() + *data, vc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, vc.VlanID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, vc.Octets = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, vc.UcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, vc.MulticastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, vc.BroadcastPkts = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, vc.Discards = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return vc, nil +} + +// SFLLACPportState : SFlow LACP Port State (All(4) - 32 bit) +type SFLLACPPortState struct { + PortStateAll uint32 +} + +// LACPcounters : LACP SFlow Counters ( 64 Bytes ) +type SFlowLACPCounters struct { + SFlowBaseCounterRecord + ActorSystemID net.HardwareAddr + PartnerSystemID net.HardwareAddr + AttachedAggID uint32 + LacpPortState SFLLACPPortState + LACPDUsRx uint32 + MarkerPDUsRx uint32 + MarkerResponsePDUsRx uint32 + UnknownRx uint32 + IllegalRx uint32 + LACPDUsTx uint32 + MarkerPDUsTx uint32 + MarkerResponsePDUsTx uint32 +} + +func decodeLACPCounters(data *[]byte) (SFlowLACPCounters, error) { + la := SFlowLACPCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + la.EnterpriseID, la.Format = cdf.decode() + *data, la.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.ActorSystemID = (*data)[6:], (*data)[:6] + *data = (*data)[2:] // remove padding + *data, la.PartnerSystemID = (*data)[6:], (*data)[:6] + *data = (*data)[2:] //remove padding + *data, la.AttachedAggID = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.LacpPortState.PortStateAll = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.LACPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.MarkerPDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.MarkerResponsePDUsRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.UnknownRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.IllegalRx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.LACPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.MarkerPDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, la.MarkerResponsePDUsTx = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return la, nil + +} + +// ************************************************** +// Processor Counter Record +// ************************************************** +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | counter length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | FiveSecCpu | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | OneMinCpu | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | GiveMinCpu | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | TotalMemory | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | FreeMemory | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +type SFlowProcessorCounters struct { + SFlowBaseCounterRecord + FiveSecCpu uint32 // 5 second average CPU utilization + OneMinCpu uint32 // 1 minute average CPU utilization + FiveMinCpu uint32 // 5 minute average CPU utilization + TotalMemory uint64 // total memory (in bytes) + FreeMemory uint64 // free memory (in bytes) +} + +func decodeProcessorCounters(data *[]byte) (SFlowProcessorCounters, error) { + pc := SFlowProcessorCounters{} + var cdf SFlowCounterDataFormat + var high32, low32 uint32 + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + pc.EnterpriseID, pc.Format = cdf.decode() + *data, pc.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + *data, pc.FiveSecCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, pc.OneMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, pc.FiveMinCpu = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + pc.TotalMemory = (uint64(high32) << 32) + uint64(low32) + *data, high32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, low32 = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + pc.FreeMemory = (uint64(high32)) + uint64(low32) + + return pc, nil +} + +// SFlowEthernetFrameFlowRecord give additional information +// about the sampled packet if it's available. +// An agent may or may not provide this information. +type SFlowEthernetFrameFlowRecord struct { + SFlowBaseFlowRecord + FrameLength uint32 + SrcMac net.HardwareAddr + DstMac net.HardwareAddr + Type uint32 +} + +// Ethernet frame flow records have the following structure: +// +// 0 15 31 +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | 20 bit Interprise (0) |12 bit format | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | record length | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Source Mac Address | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Destination Mac Address | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +// | Ethernet Packet Type | +// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + +func decodeEthernetFrameFlowRecord(data *[]byte) (SFlowEthernetFrameFlowRecord, error) { + es := SFlowEthernetFrameFlowRecord{} + var fdf SFlowFlowDataFormat + + *data, fdf = (*data)[4:], SFlowFlowDataFormat(binary.BigEndian.Uint32((*data)[:4])) + es.EnterpriseID, es.Format = fdf.decode() + *data, es.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + *data, es.FrameLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, es.SrcMac = (*data)[8:], net.HardwareAddr((*data)[:6]) + *data, es.DstMac = (*data)[8:], net.HardwareAddr((*data)[:6]) + *data, es.Type = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + return es, nil +} + +// SFlowOpenflowPortCounters : OVS-Sflow OpenFlow Port Counter ( 20 Bytes ) +type SFlowOpenflowPortCounters struct { + SFlowBaseCounterRecord + DatapathID uint64 + PortNo uint32 +} + +func decodeOpenflowportCounters(data *[]byte) (SFlowOpenflowPortCounters, error) { + ofp := SFlowOpenflowPortCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + ofp.EnterpriseID, ofp.Format = cdf.decode() + *data, ofp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, ofp.DatapathID = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, ofp.PortNo = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return ofp, nil +} + +// SFlowAppresourcesCounters : OVS_Sflow App Resources Counter ( 48 Bytes ) +type SFlowAppresourcesCounters struct { + SFlowBaseCounterRecord + UserTime uint32 + SystemTime uint32 + MemUsed uint64 + MemMax uint64 + FdOpen uint32 + FdMax uint32 + ConnOpen uint32 + ConnMax uint32 +} + +func decodeAppresourcesCounters(data *[]byte) (SFlowAppresourcesCounters, error) { + app := SFlowAppresourcesCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + app.EnterpriseID, app.Format = cdf.decode() + *data, app.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.UserTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.SystemTime = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.MemUsed = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, app.MemMax = (*data)[8:], binary.BigEndian.Uint64((*data)[:8]) + *data, app.FdOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.FdMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.ConnOpen = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, app.ConnMax = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return app, nil +} + +// SFlowOVSDPCounters : OVS-Sflow DataPath Counter ( 32 Bytes ) +type SFlowOVSDPCounters struct { + SFlowBaseCounterRecord + NHit uint32 + NMissed uint32 + NLost uint32 + NMaskHit uint32 + NFlows uint32 + NMasks uint32 +} + +func decodeOVSDPCounters(data *[]byte) (SFlowOVSDPCounters, error) { + dp := SFlowOVSDPCounters{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + dp.EnterpriseID, dp.Format = cdf.decode() + *data, dp.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NMissed = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NLost = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NMaskHit = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NFlows = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + *data, dp.NMasks = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + + return dp, nil +} + +// SFlowPORTNAME : OVS-Sflow PORTNAME Counter Sampletype ( 20 Bytes ) +type SFlowPORTNAME struct { + SFlowBaseCounterRecord + Len uint32 + Str string +} + +func decodeString(data *[]byte) (len uint32, str string) { + *data, len = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + str = string((*data)[:len]) + if (len % 4) != 0 { + len += 4 - len%4 + } + *data = (*data)[len:] + return +} + +func decodePortnameCounters(data *[]byte) (SFlowPORTNAME, error) { + pn := SFlowPORTNAME{} + var cdf SFlowCounterDataFormat + + *data, cdf = (*data)[4:], SFlowCounterDataFormat(binary.BigEndian.Uint32((*data)[:4])) + pn.EnterpriseID, pn.Format = cdf.decode() + *data, pn.FlowDataLength = (*data)[4:], binary.BigEndian.Uint32((*data)[:4]) + pn.Len, pn.Str = decodeString(data) + + return pn, nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sip.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sip.go new file mode 100644 index 0000000000..0e7719c981 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/sip.go @@ -0,0 +1,600 @@ +// Copyright 2017 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 layers + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/gopacket/gopacket" +) + +// SIPVersion defines the different versions of the SIP Protocol +type SIPVersion uint8 + +// Represents all the versions of SIP protocol +const ( + SIPVersion1 SIPVersion = 1 + SIPVersion2 SIPVersion = 2 +) + +func (sv SIPVersion) String() string { + switch sv { + default: + // Defaulting to SIP/2.0 + return "SIP/2.0" + case SIPVersion1: + return "SIP/1.0" + case SIPVersion2: + return "SIP/2.0" + } +} + +// GetSIPVersion is used to get SIP version constant +func GetSIPVersion(version string) (SIPVersion, error) { + switch strings.ToUpper(version) { + case "SIP/1.0": + return SIPVersion1, nil + case "SIP/2.0": + return SIPVersion2, nil + default: + return 0, fmt.Errorf("Unknown SIP version: '%s'", version) + + } +} + +// SIPMethod defines the different methods of the SIP Protocol +// defined in the different RFC's +type SIPMethod uint16 + +// Here are all the SIP methods +const ( + SIPMethodInvite SIPMethod = 1 // INVITE [RFC3261] + SIPMethodAck SIPMethod = 2 // ACK [RFC3261] + SIPMethodBye SIPMethod = 3 // BYE [RFC3261] + SIPMethodCancel SIPMethod = 4 // CANCEL [RFC3261] + SIPMethodOptions SIPMethod = 5 // OPTIONS [RFC3261] + SIPMethodRegister SIPMethod = 6 // REGISTER [RFC3261] + SIPMethodPrack SIPMethod = 7 // PRACK [RFC3262] + SIPMethodSubscribe SIPMethod = 8 // SUBSCRIBE [RFC6665] + SIPMethodNotify SIPMethod = 9 // NOTIFY [RFC6665] + SIPMethodPublish SIPMethod = 10 // PUBLISH [RFC3903] + SIPMethodInfo SIPMethod = 11 // INFO [RFC6086] + SIPMethodRefer SIPMethod = 12 // REFER [RFC3515] + SIPMethodMessage SIPMethod = 13 // MESSAGE [RFC3428] + SIPMethodUpdate SIPMethod = 14 // UPDATE [RFC3311] + SIPMethodPing SIPMethod = 15 // PING [https://tools.ietf.org/html/draft-fwmiller-ping-03] +) + +func (sm SIPMethod) String() string { + switch sm { + default: + return "Unknown method" + case SIPMethodInvite: + return "INVITE" + case SIPMethodAck: + return "ACK" + case SIPMethodBye: + return "BYE" + case SIPMethodCancel: + return "CANCEL" + case SIPMethodOptions: + return "OPTIONS" + case SIPMethodRegister: + return "REGISTER" + case SIPMethodPrack: + return "PRACK" + case SIPMethodSubscribe: + return "SUBSCRIBE" + case SIPMethodNotify: + return "NOTIFY" + case SIPMethodPublish: + return "PUBLISH" + case SIPMethodInfo: + return "INFO" + case SIPMethodRefer: + return "REFER" + case SIPMethodMessage: + return "MESSAGE" + case SIPMethodUpdate: + return "UPDATE" + case SIPMethodPing: + return "PING" + } +} + +// GetSIPMethod returns the constant of a SIP method +// from its string +func GetSIPMethod(method string) (SIPMethod, error) { + switch strings.ToUpper(method) { + case "INVITE": + return SIPMethodInvite, nil + case "ACK": + return SIPMethodAck, nil + case "BYE": + return SIPMethodBye, nil + case "CANCEL": + return SIPMethodCancel, nil + case "OPTIONS": + return SIPMethodOptions, nil + case "REGISTER": + return SIPMethodRegister, nil + case "PRACK": + return SIPMethodPrack, nil + case "SUBSCRIBE": + return SIPMethodSubscribe, nil + case "NOTIFY": + return SIPMethodNotify, nil + case "PUBLISH": + return SIPMethodPublish, nil + case "INFO": + return SIPMethodInfo, nil + case "REFER": + return SIPMethodRefer, nil + case "MESSAGE": + return SIPMethodMessage, nil + case "UPDATE": + return SIPMethodUpdate, nil + case "PING": + return SIPMethodPing, nil + default: + return 0, fmt.Errorf("Unknown SIP method: '%s'", method) + } +} + +// Here is a correspondance between long header names and short +// as defined in rfc3261 in section 20 +var compactSipHeadersCorrespondance = map[string]string{ + "accept-contact": "a", + "allow-events": "u", + "call-id": "i", + "contact": "m", + "content-encoding": "e", + "content-length": "l", + "content-type": "c", + "event": "o", + "from": "f", + "identity": "y", + "refer-to": "r", + "referred-by": "b", + "reject-contact": "j", + "request-disposition": "d", + "session-expires": "x", + "subject": "s", + "supported": "k", + "to": "t", + "via": "v", +} + +// SIP object will contains information about decoded SIP packet. +// -> The SIP Version +// -> The SIP Headers (in a map[string][]string because of multiple headers with the same name +// -> The SIP Method +// -> The SIP Response code (if it's a response) +// -> The SIP Status line (if it's a response) +// You can easily know the type of the packet with the IsResponse boolean +type SIP struct { + BaseLayer + + // Base information + Version SIPVersion + Method SIPMethod + Headers map[string][]string + + // Request + RequestURI string + + // Response + IsResponse bool + ResponseCode int + ResponseStatus string + + // Private fields + cseq uint32 + contentLength int + lastHeaderParsed string +} + +// decodeSIP decodes the byte slice into a SIP type. It also +// setups the application Layer in PacketBuilder. +func decodeSIP(data []byte, p gopacket.PacketBuilder) error { + s := NewSIP() + err := s.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(s) + p.SetApplicationLayer(s) + return nil +} + +// NewSIP instantiates a new empty SIP object +func NewSIP() *SIP { + s := new(SIP) + s.Headers = make(map[string][]string) + s.contentLength = -1 + return s +} + +// LayerType returns gopacket.LayerTypeSIP. +func (s *SIP) LayerType() gopacket.LayerType { + return LayerTypeSIP +} + +// Payload returns the base layer payload +func (s *SIP) Payload() []byte { + return s.BaseLayer.Payload +} + +// CanDecode returns the set of layer types that this DecodingLayer can decode +func (s *SIP) CanDecode() gopacket.LayerClass { + return LayerTypeSIP +} + +// NextLayerType returns the layer type contained by this DecodingLayer +func (s *SIP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// DecodeFromBytes decodes the slice into the SIP struct. +func (s *SIP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + // Init some vars for parsing follow-up + var countLines int + var line []byte + var err error + var offset int + var eoh = false // track End Of Headers + + // Iterate on all lines of the SIP Headers + // and stop when we reach the SDP (aka when the new line + // is at index 0 of the remaining packet) + buffer := bytes.NewBuffer(data) + + for { + + // Read next line + line, err = buffer.ReadBytes(byte('\n')) + if err != nil { + if err == io.EOF { + if len(bytes.Trim(line, "\r\n")) > 0 { + df.SetTruncated() + } + break + } else { + return err + } + } + offset += len(line) + + // Trim the new line delimiters + line = bytes.Trim(line, "\r\n") + + // Empty line, we hit Body + if len(line) == 0 { + if countLines == 0 { + return fmt.Errorf("invalid first SIP line, empty") + } + eoh = true + break + } + + // First line is the SIP request/response line + // Other lines are headers + if countLines == 0 { + err = s.ParseFirstLine(line) + if err != nil { + return err + } + + } else { + err = s.ParseHeader(line) + if err != nil { + return err + } + } + + countLines++ + } + if !eoh { + df.SetTruncated() + } + s.setBaseLayer(data, offset, df) + + return nil +} + +// setBaseLayer is used to set the base layer of the SIP packet. +// +// According to "RFC3261 - 20.14 - Content-Length" the Content-Length header is mandatory +// for SIP packages transported over TCP. When transporting over UDP, the message +// body length CAN be determined by the length of the UDP datagram. +// +// So by using the Content-Length header, if present we can mark the packet as truncated if we do not +// have enough data. We are also able to limit the payload to the number bytes actually specified. +// If the header is not present, we can assume that the data was transported over UDP we can then +// use the length of the data as payload length. +func (s *SIP) setBaseLayer(data []byte, offset int, df gopacket.DecodeFeedback) { + // The content-length header was not present in the packet, we use the rest of the packet as payload + if s.contentLength == -1 { + s.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]} + } else if s.contentLength == 0 { + // We have a zero Content-Length, no payload + s.BaseLayer = BaseLayer{Contents: data[:offset], Payload: []byte{}} // no payload + } else if len(data) < offset+s.contentLength { + // Not enough data to fulfill the Content-Length. We set the packet as truncated + // and return what we have. The receiver of the packet will be able to determine this + // by comparing the SIP.ContentLength with the length of the SIP.Payload. + df.SetTruncated() + s.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]} + } else { + // we have at least enough data, to fulfill the Content-Length. But we only add the number + // of bytes specified in the Content-Length header to the payload. + s.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset : offset+s.contentLength]} + } +} + +// ParseFirstLine will compute the first line of a SIP packet. +// The first line will tell us if it's a request or a response. +// +// Examples of first line of SIP Prococol : +// +// Request : INVITE bob@example.com SIP/2.0 +// Response : SIP/2.0 200 OK +// Response : SIP/2.0 501 Not Implemented +func (s *SIP) ParseFirstLine(firstLine []byte) error { + + var err error + + // Splits line by space + splits := strings.SplitN(string(firstLine), " ", 3) + + // We must have at least 3 parts + if len(splits) < 3 { + return fmt.Errorf("invalid first SIP line: '%s'", string(firstLine)) + } + + // Determine the SIP packet type + if strings.HasPrefix(splits[0], "SIP") { + + // --> Response + s.IsResponse = true + + // Validate SIP Version + s.Version, err = GetSIPVersion(splits[0]) + if err != nil { + return err + } + + // Compute code + s.ResponseCode, err = strconv.Atoi(splits[1]) + if err != nil { + return err + } + + // Compute status line + s.ResponseStatus = splits[2] + + } else { + + // --> Request + + // Validate method + s.Method, err = GetSIPMethod(splits[0]) + if err != nil { + return err + } + + s.RequestURI = splits[1] + + // Validate SIP Version + s.Version, err = GetSIPVersion(splits[2]) + if err != nil { + return err + } + } + + return nil +} + +// ParseHeader will parse a SIP Header +// SIP Headers are quite simple, there are colon separated name and value +// Headers can be spread over multiple lines +// +// Examples of header : +// +// CSeq: 1 REGISTER +// Via: SIP/2.0/UDP there.com:5060 +// Authorization:Digest username="UserB", +// realm="MCI WorldCom SIP", +// nonce="1cec4341ae6cbe5a359ea9c8e88df84f", opaque="", +// uri="sip:ss2.wcom.com", response="71ba27c64bd01de719686aa4590d5824" +func (s *SIP) ParseHeader(header []byte) (err error) { + + // Ignore empty headers + if len(header) == 0 { + return + } + + // Check if this is the following of last header + // RFC 3261 - 7.3.1 - Header Field Format specify that following lines of + // multiline headers must begin by SP or TAB + if header[0] == '\t' || header[0] == ' ' { + + header = bytes.TrimSpace(header) + s.Headers[s.lastHeaderParsed][len(s.Headers[s.lastHeaderParsed])-1] += fmt.Sprintf(" %s", string(header)) + return + } + + // Find the ':' to separate header name and value + index := bytes.Index(header, []byte(":")) + if index >= 0 { + + headerName := strings.ToLower(string(bytes.Trim(header[:index], " "))) + headerValue := string(bytes.Trim(header[index+1:], " ")) + + // Add header to object + s.Headers[headerName] = append(s.Headers[headerName], headerValue) + s.lastHeaderParsed = headerName + + // Compute specific headers + err = s.ParseSpecificHeaders(headerName, headerValue) + if err != nil { + return err + } + } + + return nil +} + +// ParseSpecificHeaders will parse some specific key values from +// specific headers like CSeq or Content-Length integer values +func (s *SIP) ParseSpecificHeaders(headerName string, headerValue string) (err error) { + + switch headerName { + case "cseq": + // CSeq header value is formatted like that : + // CSeq: 123 INVITE + // We split the value to parse Cseq integer value, and method + splits := strings.Split(headerValue, " ") + if len(splits) > 1 { + // parse CSEQ + s.cseq, err = parseUint32(splits[0]) + if err != nil { + return fmt.Errorf("invalid CSEQ value: %w", err) + } + // Validate method + if s.IsResponse { + s.Method, err = GetSIPMethod(splits[1]) + if err != nil { + return err + } + } + } + + case "content-length": + // Parse Content-Length + s.contentLength, err = parsePositiveInt32(headerValue) + if err != nil { + return fmt.Errorf("invalid Content-Length: %w", err) + } + } + + return nil +} + +// parsePositiveInt32 will parse the string as an int, but will return error if +// value is < 0 or above the max positive value of an int32 +func parsePositiveInt32(s string) (int, error) { + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + return 0, err + } + if i < 0 { + return 0, fmt.Errorf("%d out of range", i) + } + return int(i), nil +} + +// parseUint32 parse string value to uint32, return error if not successful +func parseUint32(s string) (uint32, error) { + i, err := strconv.ParseUint(s, 10, 32) + if err != nil { + return 0, err + } + return uint32(i), nil +} + +// GetAllHeaders will return the full headers of the +// current SIP packets in a map[string][]string +func (s *SIP) GetAllHeaders() map[string][]string { + return s.Headers +} + +// GetHeader will return all the headers with +// the specified name. +func (s *SIP) GetHeader(headerName string) []string { + headerName = strings.ToLower(headerName) + h := make([]string, 0) + if _, ok := s.Headers[headerName]; ok { + return s.Headers[headerName] + } + compactHeader := compactSipHeadersCorrespondance[headerName] + if _, ok := s.Headers[compactHeader]; ok { + return s.Headers[compactHeader] + } + return h +} + +// GetFirstHeader will return the first header with +// the specified name. If the current SIP packet has multiple +// headers with the same name, it returns the first. +func (s *SIP) GetFirstHeader(headerName string) string { + headers := s.GetHeader(headerName) + if len(headers) > 0 { + return headers[0] + } + return "" +} + +// +// Some handy getters for most used SIP headers +// + +// GetAuthorization will return the Authorization +// header of the current SIP packet +func (s *SIP) GetAuthorization() string { + return s.GetFirstHeader("Authorization") +} + +// GetFrom will return the From +// header of the current SIP packet +func (s *SIP) GetFrom() string { + return s.GetFirstHeader("From") +} + +// GetTo will return the To +// header of the current SIP packet +func (s *SIP) GetTo() string { + return s.GetFirstHeader("To") +} + +// GetContact will return the Contact +// header of the current SIP packet +func (s *SIP) GetContact() string { + return s.GetFirstHeader("Contact") +} + +// GetCallID will return the Call-ID +// header of the current SIP packet +func (s *SIP) GetCallID() string { + return s.GetFirstHeader("Call-ID") +} + +// GetUserAgent will return the User-Agent +// header of the current SIP packet +func (s *SIP) GetUserAgent() string { + return s.GetFirstHeader("User-Agent") +} + +// GetContentLength will return the parsed integer +// Content-Length header of the current SIP packet +func (s *SIP) GetContentLength() int64 { + // to keep compatibility with previous versions, we return 0 if contentLength is not set by header + if s.contentLength == -1 { + return 0 + } + return int64(s.contentLength) +} + +// GetCSeq will return the parsed integer CSeq header +// header of the current SIP packet +func (s *SIP) GetCSeq() int64 { + return int64(s.cseq) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/stp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/stp.go new file mode 100644 index 0000000000..5ced412813 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/stp.go @@ -0,0 +1,150 @@ +// Copyright 2017 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + "net" + + "github.com/gopacket/gopacket" +) + +type STPSwitchID struct { + Priority uint16 // Bridge priority + SysID uint16 // VLAN ID + HwAddr net.HardwareAddr +} + +// STP decode spanning tree protocol packets to transport BPDU (bridge protocol data unit) message. +type STP struct { + BaseLayer + ProtocolID uint16 + Version uint8 + Type uint8 + TC, TCA bool // TC: Topologie change ; TCA: Topologie change ack + RouteID, BridgeID STPSwitchID + Cost uint32 + PortID uint16 + MessageAge uint16 + MaxAge uint16 + HelloTime uint16 + FDelay uint16 +} + +// LayerType returns gopacket.LayerTypeSTP. +func (s *STP) LayerType() gopacket.LayerType { return LayerTypeSTP } + +// CanDecode returns the set of layer types that this DecodingLayer can decode. +func (s *STP) CanDecode() gopacket.LayerClass { + return LayerTypeSTP +} + +// DecodeFromBytes decodes the given bytes into this layer. +func (stp *STP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + stpLength := 35 + if len(data) < stpLength { + df.SetTruncated() + return fmt.Errorf("STP length %d too short", len(data)) + } + + stp.ProtocolID = binary.BigEndian.Uint16(data[:2]) + stp.Version = uint8(data[2]) + stp.Type = uint8(data[3]) + stp.TC = data[4]&0x01 != 0 + stp.TCA = data[4]&0x80 != 0 + stp.RouteID.Priority = binary.BigEndian.Uint16(data[5:7]) & 0xf000 + stp.RouteID.SysID = binary.BigEndian.Uint16(data[5:7]) & 0x0fff + stp.RouteID.HwAddr = net.HardwareAddr(data[7:13]) + stp.Cost = binary.BigEndian.Uint32(data[13:17]) + stp.BridgeID.Priority = binary.BigEndian.Uint16(data[17:19]) & 0xf000 + stp.BridgeID.SysID = binary.BigEndian.Uint16(data[17:19]) & 0x0fff + stp.BridgeID.HwAddr = net.HardwareAddr(data[19:25]) + stp.PortID = binary.BigEndian.Uint16(data[25:27]) + stp.MessageAge = binary.BigEndian.Uint16(data[27:29]) + stp.MaxAge = binary.BigEndian.Uint16(data[29:31]) + stp.HelloTime = binary.BigEndian.Uint16(data[31:33]) + stp.FDelay = binary.BigEndian.Uint16(data[33:35]) + stp.Contents = data[:stpLength] + stp.Payload = data[stpLength:] + + return nil +} + +// NextLayerType returns the layer type contained by this DecodingLayer. +func (stp *STP) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +// Check if the priority value is correct. +func checkPriority(prio uint16) (uint16, error) { + if prio == 0 { + return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096") + } + if prio%4096 == 0 { + return prio, nil + } else { + return prio, errors.New("Invalid Priority value must be in the rage <4096-61440> with an increment of 4096") + } +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (s *STP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var flags uint8 = 0x00 + bytes, err := b.PrependBytes(35) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes, s.ProtocolID) + bytes[2] = s.Version + bytes[3] = s.Type + if s.TC { + flags |= 0x01 + } + if s.TCA { + flags |= 0x80 + } + bytes[4] = flags + + prioRoot, err := checkPriority(s.RouteID.Priority) + if err != nil { + panic(err) + } + if s.RouteID.SysID >= 4096 { + panic("Invalid VlanID value ..!") + } + binary.BigEndian.PutUint16(bytes[5:7], prioRoot|s.RouteID.SysID) + copy(bytes[7:13], s.RouteID.HwAddr) + + binary.BigEndian.PutUint32(bytes[13:17], s.Cost) + + prioBridge, err := checkPriority(s.BridgeID.Priority) + if err != nil { + panic(err) + } + if s.BridgeID.SysID >= 4096 { + panic("Invalid VlanID value ..!") + } + binary.BigEndian.PutUint16(bytes[17:19], prioBridge|s.BridgeID.SysID) + copy(bytes[19:25], s.BridgeID.HwAddr) + + binary.BigEndian.PutUint16(bytes[25:27], s.PortID) + binary.BigEndian.PutUint16(bytes[27:29], s.MessageAge) + binary.BigEndian.PutUint16(bytes[29:31], s.MaxAge) + binary.BigEndian.PutUint16(bytes[31:33], s.HelloTime) + binary.BigEndian.PutUint16(bytes[33:35], s.FDelay) + + return nil +} + +func decodeSTP(data []byte, p gopacket.PacketBuilder) error { + stp := &STP{} + return decodingLayerDecoder(stp, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcp.go new file mode 100644 index 0000000000..782c0005fb --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcp.go @@ -0,0 +1,637 @@ +// 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 layers + +import ( + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// TCP is the layer for TCP headers. +type TCP struct { + BaseLayer + SrcPort, DstPort TCPPort + Seq uint32 + Ack uint32 + DataOffset uint8 + FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool + Window uint16 + Checksum uint16 + Urgent uint16 + sPort, dPort []byte + Options []TCPOption + Padding []byte + opts [4]TCPOption + Multipath bool + tcpipchecksum +} + +// TCPOptionKind represents a TCP option code. +type TCPOptionKind uint8 + +// TCP Option Kind constonts from https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xml#tcp-parameters-1 +const ( + TCPOptionKindEndList = 0 + TCPOptionKindNop = 1 + TCPOptionKindMSS = 2 // len = 4 + TCPOptionKindWindowScale = 3 // len = 3 + TCPOptionKindSACKPermitted = 4 // len = 2 + TCPOptionKindSACK = 5 // len = n + TCPOptionKindEcho = 6 // len = 6, obsolete + TCPOptionKindEchoReply = 7 // len = 6, obsolete + TCPOptionKindTimestamps = 8 // len = 10 + TCPOptionKindPartialOrderConnectionPermitted = 9 // len = 2, obsolete + TCPOptionKindPartialOrderServiceProfile = 10 // len = 3, obsolete + TCPOptionKindCC = 11 // obsolete + TCPOptionKindCCNew = 12 // obsolete + TCPOptionKindCCEcho = 13 // obsolete + TCPOptionKindAltChecksum = 14 // len = 3, obsolete + TCPOptionKindAltChecksumData = 15 // len = n, obsolete + TCPOptionKindMultipathTCP = 30 +) + +func (k TCPOptionKind) String() string { + switch k { + case TCPOptionKindEndList: + return "EndList" + case TCPOptionKindNop: + return "NOP" + case TCPOptionKindMSS: + return "MSS" + case TCPOptionKindWindowScale: + return "WindowScale" + case TCPOptionKindSACKPermitted: + return "SACKPermitted" + case TCPOptionKindSACK: + return "SACK" + case TCPOptionKindEcho: + return "Echo" + case TCPOptionKindEchoReply: + return "EchoReply" + case TCPOptionKindTimestamps: + return "Timestamps" + case TCPOptionKindPartialOrderConnectionPermitted: + return "PartialOrderConnectionPermitted" + case TCPOptionKindPartialOrderServiceProfile: + return "PartialOrderServiceProfile" + case TCPOptionKindCC: + return "CC" + case TCPOptionKindCCNew: + return "CCNew" + case TCPOptionKindCCEcho: + return "CCEcho" + case TCPOptionKindAltChecksum: + return "AltChecksum" + case TCPOptionKindAltChecksumData: + return "AltChecksumData" + case TCPOptionKindMultipathTCP: + return "MultipathTCP" + default: + return fmt.Sprintf("Unknown(%d)", k) + } +} + +// TCPOption are the possible TCP and MPTCP Options +type TCPOption struct { + OptionType TCPOptionKind + OptionLength uint8 + OptionData []byte + OptionMultipath MPTCPSubtype + OptionMPTCPMpCapable *MPCapable + OptionMPTCPDss *Dss + OptionMPTCPMpJoin *MPJoin + OptionMPTCPMpPrio *MPPrio + OptionMPTCPAddAddr *AddAddr + OptionMTCPRemAddr *RemAddr + OptionMTCPMPFastClose *MPFClose + OptionMPTCPMPTcpRst *MPTcpRst + OptionMTCPMPFail *MPFail +} + +func (t TCPOption) String() string { + hd := hex.EncodeToString(t.OptionData) + if len(hd) > 0 { + hd = " 0x" + hd + } + switch t.OptionType { + case TCPOptionKindMSS: + if len(t.OptionData) >= 2 { + return fmt.Sprintf("TCPOption(%s:%v%s)", + t.OptionType, + binary.BigEndian.Uint16(t.OptionData), + hd) + } + + case TCPOptionKindTimestamps: + if len(t.OptionData) == 8 { + return fmt.Sprintf("TCPOption(%s:%v/%v%s)", + t.OptionType, + binary.BigEndian.Uint32(t.OptionData[:4]), + binary.BigEndian.Uint32(t.OptionData[4:8]), + hd) + } + + case TCPOptionKindMultipathTCP: + switch t.OptionMultipath { + case MPTCPSubtypeMPCAPABLE: + return fmt.Sprintf("MPTCPOption(%s Version %v)", + t.OptionMultipath, + t.OptionMPTCPMpCapable.Version) + case MPTCPSubtypeMPJOIN: + return fmt.Sprintf("MPTCPOption(%s Backup %v;Address ID %v)", + t.OptionMultipath, + t.OptionMPTCPMpJoin.Backup, + t.OptionMPTCPMpJoin.AddrID) + case MPTCPSubtypeDSS: + return fmt.Sprintf("MPTCPOption(%s)", + t.OptionMultipath) + case MPTCPSubtypeMPPRIO: + return fmt.Sprintf("MPTCPOption(%s Backup %v;Address ID %v)", + t.OptionMultipath, + t.OptionMPTCPMpPrio.Backup, + t.OptionMPTCPMpPrio.AddrID) + case MPTCPSubtypeADDADDR: + return fmt.Sprintf("MPTCPOption(%s Address ID %v;Address %v;Port %v)", + t.OptionMultipath, + t.OptionMPTCPAddAddr.AddrID, + t.OptionMPTCPAddAddr.Address, + t.OptionMPTCPAddAddr.Port) + case MPTCPSubtypeREMOVEADDR: + return fmt.Sprintf("MPTCPOption(%s Address ID %v)", + t.OptionMultipath, + t.OptionMTCPRemAddr.AddrIDs) + case MPTCPSubtypeMPFASTCLOSE: + return fmt.Sprintf("MPTCPOption(%s)", + t.OptionMultipath) + case MPTCPSubtypeMPTCPRST: + return fmt.Sprintf("MPTCPOption(%s Transient %v; Reason %v)", + t.OptionMultipath, + t.OptionMPTCPMPTcpRst.T, + t.OptionMPTCPMPTcpRst.Reason) + case MPTCPSubtypeMPFAIL: + return fmt.Sprintf("MPTCPOption(%s)", + t.OptionMultipath) + } + } + return fmt.Sprintf("TCPOption(%s:%s)", t.OptionType, hd) +} + +// LayerType returns gopacket.LayerTypeTCP +func (t *TCP) LayerType() gopacket.LayerType { return LayerTypeTCP } + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var optionLength int + for _, o := range t.Options { + switch o.OptionType { + case 0, 1: + optionLength += 1 + default: + optionLength += 2 + len(o.OptionData) + } + } + if opts.FixLengths { + if rem := optionLength % 4; rem != 0 { + t.Padding = lotsOfZeros[:4-rem] + } + t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4) + } + bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding)) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort)) + binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort)) + binary.BigEndian.PutUint32(bytes[4:], t.Seq) + binary.BigEndian.PutUint32(bytes[8:], t.Ack) + binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset()) + binary.BigEndian.PutUint16(bytes[14:], t.Window) + binary.BigEndian.PutUint16(bytes[18:], t.Urgent) + start := 20 + for _, o := range t.Options { + bytes[start] = byte(o.OptionType) + switch o.OptionType { + case 0, 1: + start++ + default: + if opts.FixLengths { + o.OptionLength = uint8(len(o.OptionData) + 2) + } + bytes[start+1] = o.OptionLength + copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData) + start += len(o.OptionData) + 2 + } + } + copy(bytes[start:], t.Padding) + if opts.ComputeChecksums { + // zero out checksum bytes in current serialization. + bytes[16] = 0 + bytes[17] = 0 + csum, err := t.computeChecksum(b.Bytes(), IPProtocolTCP) + if err != nil { + return err + } + t.Checksum = gopacket.FoldChecksum(csum) + } + binary.BigEndian.PutUint16(bytes[16:], t.Checksum) + return nil +} + +func (t *TCP) ComputeChecksum() (uint16, error) { + csum, err := t.computeChecksum(append(t.Contents, t.Payload...), IPProtocolTCP) + if err != nil { + return 0, err + } + return gopacket.FoldChecksum(csum), nil +} + +func (t *TCP) flagsAndOffset() uint16 { + f := uint16(t.DataOffset) << 12 + if t.FIN { + f |= 0x0001 + } + if t.SYN { + f |= 0x0002 + } + if t.RST { + f |= 0x0004 + } + if t.PSH { + f |= 0x0008 + } + if t.ACK { + f |= 0x0010 + } + if t.URG { + f |= 0x0020 + } + if t.ECE { + f |= 0x0040 + } + if t.CWR { + f |= 0x0080 + } + if t.NS { + f |= 0x0100 + } + return f +} + +func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 20 { + df.SetTruncated() + return fmt.Errorf("Invalid TCP header. Length %d less than 20", len(data)) + } + tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2])) + tcp.sPort = data[0:2] + tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4])) + tcp.dPort = data[2:4] + tcp.Seq = binary.BigEndian.Uint32(data[4:8]) + tcp.Ack = binary.BigEndian.Uint32(data[8:12]) + tcp.DataOffset = data[12] >> 4 + tcp.FIN = data[13]&0x01 != 0 + tcp.SYN = data[13]&0x02 != 0 + tcp.RST = data[13]&0x04 != 0 + tcp.PSH = data[13]&0x08 != 0 + tcp.ACK = data[13]&0x10 != 0 + tcp.URG = data[13]&0x20 != 0 + tcp.ECE = data[13]&0x40 != 0 + tcp.CWR = data[13]&0x80 != 0 + tcp.NS = data[12]&0x01 != 0 + tcp.Window = binary.BigEndian.Uint16(data[14:16]) + tcp.Checksum = binary.BigEndian.Uint16(data[16:18]) + tcp.Urgent = binary.BigEndian.Uint16(data[18:20]) + if tcp.Options == nil { + // Pre-allocate to avoid allocating a slice. + tcp.Options = tcp.opts[:0] + } else { + tcp.Options = tcp.Options[:0] + } + tcp.Padding = tcp.Padding[:0] + if tcp.DataOffset < 5 { + return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset) + } + dataStart := int(tcp.DataOffset) * 4 + if dataStart > len(data) { + df.SetTruncated() + tcp.Payload = nil + tcp.Contents = data + return errors.New("TCP data offset greater than packet length") + } + tcp.Contents = data[:dataStart] + tcp.Payload = data[dataStart:] + // From here on, data points just to the header options. + data = data[20:dataStart] +OPTIONS: + for len(data) > 0 { + tcp.Options = append(tcp.Options, TCPOption{OptionType: TCPOptionKind(data[0])}) + opt := &tcp.Options[len(tcp.Options)-1] + switch opt.OptionType { + case TCPOptionKindEndList: // End of options + opt.OptionLength = 1 + tcp.Padding = data[1:] + break OPTIONS + case TCPOptionKindNop: // 1 byte padding + opt.OptionLength = 1 + case TCPOptionKindMultipathTCP: + tcp.Multipath = true + opt.OptionLength = data[1] + opt.OptionMultipath = MPTCPSubtype(data[2] >> 4) + switch opt.OptionMultipath { + case MPTCPSubtypeMPCAPABLE: + if opt.OptionLength != OptionLenMpCapableSyn && opt.OptionLength != OptionLenMpCapableSynAck && opt.OptionLength != OptionLenMpCapableAck && opt.OptionLength != OptionLenMpCapableAckData && opt.OptionLength != OptionLenMpCapableAckDataCSum { + return fmt.Errorf("MP_CAPABLE bad option length %d", opt.OptionLength) + } + opt.OptionMPTCPMpCapable = &MPCapable{ + Version: data[2] & 0x0F, + A: data[3]&0x80 != 0, + B: data[3]&0x40 != 0, + C: data[3]&0x20 != 0, + D: data[3]&0x10 != 0, + E: data[3]&0x08 != 0, + F: data[3]&0x04 != 0, + G: data[3]&0x02 != 0, + H: data[3]&0x01 != 0, + } + if opt.OptionLength >= OptionLenMpCapableSynAck { + opt.OptionMPTCPMpCapable.SendKey = data[4:12] + } + if opt.OptionLength >= OptionLenMpCapableAck { + opt.OptionMPTCPMpCapable.ReceivKey = data[12:20] + } + if opt.OptionLength >= OptionLenMpCapableAckData { + opt.OptionMPTCPMpCapable.DataLength = binary.BigEndian.Uint16(data[20:22]) + } + if opt.OptionLength == OptionLenMpCapableAckDataCSum { + opt.OptionMPTCPMpCapable.Checksum = binary.BigEndian.Uint16(data[22:24]) + } + case MPTCPSubtypeMPJOIN: + if opt.OptionLength != OptionLenMpJoinSyn && opt.OptionLength != OptionLenMpJoinSynAck && opt.OptionLength != OptionLenMpJoinAck { + return fmt.Errorf("MP_JOIN bad option length %d", opt.OptionLength) + } + switch opt.OptionLength { + case OptionLenMpJoinSyn: + opt.OptionMPTCPMpJoin = &MPJoin{ + Backup: data[2]&0x01 != 0, + AddrID: data[3], + ReceivToken: binary.BigEndian.Uint32(data[4:8]), + SendRandNum: binary.BigEndian.Uint32(data[8:12]), + } + case OptionLenMpJoinSynAck: + opt.OptionMPTCPMpJoin = &MPJoin{ + Backup: data[2]&0x01 != 0, + AddrID: data[3], + SendHMAC: data[4:12], + SendRandNum: binary.BigEndian.Uint32(data[12:16]), + } + case OptionLenMpJoinAck: + opt.OptionMPTCPMpJoin = &MPJoin{ + SendHMAC: data[4:24], + } + } + case MPTCPSubtypeDSS: + opt.OptionMPTCPDss = &Dss{ + F: data[3]&0x10 != 0, + m: data[3]&0x08 != 0, + M: data[3]&0x04 != 0, + a: data[3]&0x02 != 0, + A: data[3]&0x01 != 0, + } + if opt.OptionLength != optionMptcpDsslen(opt.OptionMPTCPDss, false) && opt.OptionLength != optionMptcpDsslen(opt.OptionMPTCPDss, true) { + return fmt.Errorf("DSS bad option length %d", opt.OptionLength) + } + var lenOpt uint8 = 4 + if opt.OptionMPTCPDss.A { // Data ACK present + if opt.OptionMPTCPDss.a { // Data ACK is 8 octets + opt.OptionMPTCPDss.DataAck = data[lenOpt : lenOpt+OptionLenDssAck64] + lenOpt += OptionLenDssAck64 + } else { + opt.OptionMPTCPDss.DataAck = data[lenOpt : lenOpt+OptionLenDssAck] + lenOpt += OptionLenDssAck + } + } + if opt.OptionMPTCPDss.M { // Data Sequence Number (DSN), Subflow Sequence Number (SSN), Data-Level Length, and Checksum (if negotiated) present + if opt.OptionMPTCPDss.m { // Data Sequence Number is 8 octets + opt.OptionMPTCPDss.DSN = data[lenOpt : lenOpt+OptionLenDssDSN64] + lenOpt += OptionLenDssDSN64 + } else { + opt.OptionMPTCPDss.DSN = data[lenOpt : lenOpt+OptionLenDssDSN] + lenOpt += OptionLenDssDSN + } + opt.OptionMPTCPDss.SSN = binary.BigEndian.Uint32(data[lenOpt : lenOpt+OptionLenDssSSN]) + lenOpt += OptionLenDssSSN + opt.OptionMPTCPDss.DataLength = binary.BigEndian.Uint16(data[lenOpt : lenOpt+OptionLenDssDataLen]) + lenOpt += OptionLenDssDataLen + if opt.OptionLength-lenOpt == 2 { // Checksum present + opt.OptionMPTCPDss.Checksum = binary.BigEndian.Uint16(data[lenOpt : lenOpt+OptionLenDssCSum]) + } + } + case MPTCPSubtypeADDADDR: + var mptcpVer uint8 + var bitE bool + lenOpt := opt.OptionLength + + if data[2]&0x0F > 1 { + mptcpVer = MptcpVersion0 + } else { + mptcpVer = MptcpVersion1 + bitE = data[2]&0x01 != 0 + } + if !isValidOptionMptcpAddAddrlen(opt.OptionLength, mptcpVer, bitE) { + return fmt.Errorf("ADD_ADDR bad option length %d", opt.OptionLength) + } + switch mptcpVer { + case MptcpVersion0: + opt.OptionMPTCPAddAddr = &AddAddr{ + IPVer: data[2] & 0x0F, + AddrID: data[3], + } + case MptcpVersion1: + opt.OptionMPTCPAddAddr = &AddAddr{ + E: data[2]&0x01 != 0, + AddrID: data[3], + } + if !opt.OptionMPTCPAddAddr.E { + opt.OptionMPTCPAddAddr.SendHMAC = data[opt.OptionLength-8:] + lenOpt -= OptionLenAddAddrHmac + } + } + switch lenOpt { + case OptionLenAddAddrv4: + opt.OptionMPTCPAddAddr.Address = data[4:8] + case OptionLenAddAddrv4 + OptionLenAddAddrPort: + opt.OptionMPTCPAddAddr.Address = data[4:8] + opt.OptionMPTCPAddAddr.Port = binary.BigEndian.Uint16(data[8:10]) + case OptionLenAddAddrv6: + opt.OptionMPTCPAddAddr.Address = data[4:20] + case OptionLenAddAddrv6 + OptionLenAddAddrPort: + opt.OptionMPTCPAddAddr.Address = data[4:20] + opt.OptionMPTCPAddAddr.Port = binary.BigEndian.Uint16(data[20:22]) + } + case MPTCPSubtypeREMOVEADDR: + if opt.OptionLength < OptionLenRemAddr { + return fmt.Errorf("Rem_ADDR bad option length %d", opt.OptionLength) + } + var addrIds []uint8 + var n uint8 + for n = 0; n < opt.OptionLength-3; n++ { + addrIds = append(addrIds, data[3+n]) + } + opt.OptionMTCPRemAddr = &RemAddr{ + AddrIDs: addrIds, + } + case MPTCPSubtypeMPPRIO: + if opt.OptionLength != OptionLenMpPrio && opt.OptionLength != OptionLenMpPrioAddr { + return fmt.Errorf("MP_PRIO bad option length %d", opt.OptionLength) + } + opt.OptionMPTCPMpPrio = &MPPrio{ + Backup: data[2]&0x01 != 0, + } + if opt.OptionLength == OptionLenMpPrioAddr { + opt.OptionMPTCPMpPrio.AddrID = data[3] + } + case MPTCPSubtypeMPFAIL: + if opt.OptionLength != OptionLenMpFail { + return fmt.Errorf("MP_FAIL bad option length %d", opt.OptionLength) + } + opt.OptionMTCPMPFail = &MPFail{ + DSN: binary.BigEndian.Uint64(data[4:OptionLenMpFail]), + } + + case MPTCPSubtypeMPFASTCLOSE: + if opt.OptionLength != OptionLenMpFClose { + return fmt.Errorf("MP_FASTCLOSE bad option length %d", opt.OptionLength) + } + opt.OptionMTCPMPFastClose = &MPFClose{ + ReceivKey: data[4:OptionLenMpFClose], + } + case MPTCPSubtypeMPTCPRST: + if opt.OptionLength != OptionLenMpTcpRst { + return fmt.Errorf("MP_TCPRST bad option length %d", opt.OptionLength) + } + opt.OptionMPTCPMPTcpRst = &MPTcpRst{ + U: data[2]&0x08 != 0, + V: data[2]&0x04 != 0, + W: data[2]&0x02 != 0, + T: data[2]&0x01 != 0, + Reason: data[3], + } + } + default: + if len(data) < 2 { + df.SetTruncated() + return fmt.Errorf("Invalid TCP option length. Length %d less than 2", len(data)) + } + opt.OptionLength = data[1] + if opt.OptionLength < 2 { + return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength) + } else if int(opt.OptionLength) > len(data) { + df.SetTruncated() + return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data)) + } + opt.OptionData = data[2:opt.OptionLength] + } + data = data[opt.OptionLength:] + } + return nil +} + +func optionMptcpDsslen(OptionMPTCPDss *Dss, csum bool) uint8 { + var len uint8 = 4 + if OptionMPTCPDss.A { // Data ACK + len += 4 + if OptionMPTCPDss.a { + len += 4 + } // Data ACK 8 octets + } + if OptionMPTCPDss.M { // DSN (4)+ SSN (4) + Data-Level Length (2) = 10 + len += 10 + if OptionMPTCPDss.m { + len += 4 + } // DSN 8 octets + if csum { + len += 2 + } + } + return len +} + +func isValidOptionMptcpAddAddrlen(length uint8, mptcpVer uint8, hmac bool) bool { + var ret bool + switch mptcpVer { + case MptcpVersion0: + ret = length == OptionLenAddAddrv4 || length == OptionLenAddAddrv4+OptionLenAddAddrPort || length == OptionLenAddAddrv6 || length == OptionLenAddAddrv6+OptionLenAddAddrPort + case MptcpVersion1: + if !hmac { + length -= OptionLenAddAddrHmac + } + ret = length == OptionLenAddAddrv4 || length == OptionLenAddAddrv4+OptionLenAddAddrPort || length == OptionLenAddAddrv6 || length == OptionLenAddAddrv6+OptionLenAddAddrPort + } + return ret +} + +func (t *TCP) CanDecode() gopacket.LayerClass { + return LayerTypeTCP +} + +func (t *TCP) NextLayerType() gopacket.LayerType { + lt := t.DstPort.LayerType() + if lt == gopacket.LayerTypePayload { + lt = t.SrcPort.LayerType() + } + return lt +} + +func decodeTCP(data []byte, p gopacket.PacketBuilder) error { + tcp := &TCP{} + err := tcp.DecodeFromBytes(data, p) + p.AddLayer(tcp) + p.SetTransportLayer(tcp) + if err != nil { + return err + } + if p.DecodeOptions().DecodeStreamsAsDatagrams { + return p.NextDecoder(tcp.NextLayerType()) + } else { + return p.NextDecoder(gopacket.LayerTypePayload) + } +} + +func (t *TCP) TransportFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointTCPPort, t.sPort, t.dPort) +} + +// For testing only +func (t *TCP) SetInternalPortsForTesting() { + t.sPort = make([]byte, 2) + t.dPort = make([]byte, 2) + binary.BigEndian.PutUint16(t.sPort, uint16(t.SrcPort)) + binary.BigEndian.PutUint16(t.dPort, uint16(t.DstPort)) +} + +func (t *TCP) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + bytes := append(t.Contents, t.Payload...) + + existing := t.Checksum + verification, err := t.computeChecksum(bytes, IPProtocolTCP) + if err != nil { + return err, gopacket.ChecksumVerificationResult{} + } + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcpip.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcpip.go new file mode 100644 index 0000000000..90584b32a5 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tcpip.go @@ -0,0 +1,85 @@ +// 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 layers + +import ( + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// Checksum computation for TCP/UDP. +type tcpipchecksum struct { + pseudoheader tcpipPseudoHeader +} + +type tcpipPseudoHeader interface { + pseudoheaderChecksum() (uint32, error) +} + +func (ip *IPv4) pseudoheaderChecksum() (csum uint32, err error) { + if err := ip.AddressTo4(); err != nil { + return 0, err + } + csum += (uint32(ip.SrcIP[0]) + uint32(ip.SrcIP[2])) << 8 + csum += uint32(ip.SrcIP[1]) + uint32(ip.SrcIP[3]) + csum += (uint32(ip.DstIP[0]) + uint32(ip.DstIP[2])) << 8 + csum += uint32(ip.DstIP[1]) + uint32(ip.DstIP[3]) + return csum, nil +} + +func (ip *IPv6) pseudoheaderChecksum() (csum uint32, err error) { + if err := ip.AddressTo16(); err != nil { + return 0, err + } + for i := 0; i < 16; i += 2 { + csum += uint32(ip.SrcIP[i]) << 8 + csum += uint32(ip.SrcIP[i+1]) + csum += uint32(ip.DstIP[i]) << 8 + csum += uint32(ip.DstIP[i+1]) + } + return csum, nil +} + +// computeChecksum computes a TCP or UDP checksum. headerAndPayload is the +// serialized TCP or UDP header plus its payload, with the checksum zero'd +// out. headerProtocol is the IP protocol number of the upper-layer header. +// The returned 32bit checksum may need to be folded. +func (c *tcpipchecksum) computeChecksum(headerAndPayload []byte, headerProtocol IPProtocol) (uint32, error) { + if c.pseudoheader == nil { + return 0, errors.New("TCP/IP layer 4 checksum cannot be computed without network layer... call SetNetworkLayerForChecksum to set which layer to use") + } + length := uint32(len(headerAndPayload)) + csum, err := c.pseudoheader.pseudoheaderChecksum() + if err != nil { + return 0, err + } + csum += uint32(headerProtocol) + csum += length & 0xffff + csum += length >> 16 + + csum = gopacket.ComputeChecksum(headerAndPayload, csum) + return csum, nil +} + +// SetNetworkLayerForChecksum tells this layer which network layer is wrapping it. +// This is needed for computing the checksum when serializing, since TCP/IP transport +// layer checksums depends on fields in the IPv4 or IPv6 layer that contains it. +// The passed in layer must be an *IPv4 or *IPv6. +func (i *tcpipchecksum) SetNetworkLayerForChecksum(l gopacket.NetworkLayer) error { + switch v := l.(type) { + case *IPv4: + i.pseudoheader = v + case *IPv6: + i.pseudoheader = v + default: + return fmt.Errorf("cannot use layer type %v for tcp checksum network layer", l.LayerType()) + } + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/test_creator.py b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/test_creator.py new file mode 100644 index 0000000000..92cba4d4cf --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/test_creator.py @@ -0,0 +1,104 @@ +#!/usr/bin/python3 +# Copyright 2012 Google, Inc. All rights reserved. + +"""TestCreator creates test templates from pcap files.""" + +import argparse +import base64 +import glob +import re +import string +import subprocess + + +class Packet(object): + """Helper class encapsulating packet from a pcap file.""" + + def __init__(self, packet_lines): + self.packet_lines = packet_lines + self.data = self._DecodeText(packet_lines) + + @classmethod + def _DecodeText(cls, packet_lines): + packet_bytes = [] + # First line is timestamp and stuff, skip it. + # Format: 0x0010: 0000 0020 3aff 3ffe 0000 0000 0000 0000 ....:.?......... + + for line in packet_lines[1:]: + m = re.match(r'\s+0x[a-f\d]+:\s+((?:[\da-f]{2,4}\s)*)', line, re.IGNORECASE) + if m is None: continue + for hexpart in m.group(1).split(): + packet_bytes.append(base64.b16decode(hexpart.upper())) + return b''.join(packet_bytes) + + def Test(self, name, link_type): + """Yields a test using this packet, as a set of lines.""" + yield '// testPacket%s is the packet:' % name + for line in self.packet_lines: + yield '// ' + line + yield 'var testPacket%s = []byte{' % name + data = list(self.data) + while data: + linebytes, data = data[:16], data[16:] + b = ''.join(["0x{:02x}, ".format(c) for c in linebytes]) + yield f'\t{b}' + yield '}' + yield 'func TestPacket%s(t *testing.T) {' % name + yield '\tp := gopacket.NewPacket(testPacket%s, LinkType%s, gopacket.Default)' % (name, link_type) + yield '\tif p.ErrorLayer() != nil {' + yield '\t\tt.Error("Failed to decode packet:", p.ErrorLayer().Error())' + yield '\t}' + yield '\tcheckLayers(p, []gopacket.LayerType{LayerType%s, FILL_ME_IN_WITH_ACTUAL_LAYERS}, t)' % link_type + yield '}' + yield 'func BenchmarkDecodePacket%s(b *testing.B) {' % name + yield '\tfor i := 0; i < b.N; i++ {' + yield '\t\tgopacket.NewPacket(testPacket%s, LinkType%s, gopacket.NoCopy)' % (name, link_type) + yield '\t}' + yield '}' + + + +def GetTcpdumpOutput(filename): + """Runs tcpdump on the given file, returning output as string.""" + return subprocess.check_output( + ['tcpdump', '-XX', '-s', '0', '-n', '-r', filename]) + + +def TcpdumpOutputToPackets(output): + """Reads a pcap file with TCPDump, yielding Packet objects.""" + pdata = [] + for line in output.decode('utf-8').split('\n'): + if line and line[0] not in string.whitespace and pdata: + yield Packet(pdata) + pdata = [] + pdata.append(line) + if pdata: + yield Packet(pdata) + + +def main(): + class CustomHelpFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _format_usage(self, usage, actions, groups, prefix=None): + header =('TestCreator creates gopacket tests using a pcap file.\n\n' + 'Tests are written to standard out... they can then be \n' + 'copied into the file of your choice and modified as \n' + 'you see.\n\n') + return header + argparse.ArgumentDefaultsHelpFormatter._format_usage( + self, usage, actions, groups, prefix) + + parser = argparse.ArgumentParser(formatter_class=CustomHelpFormatter) + parser.add_argument('--link_type', default='Ethernet', help='the link type (default: %(default)s)') + parser.add_argument('--name', default='Packet%d', help='the layer type, must have "%d" inside it') + parser.add_argument('files', metavar='file.pcap', type=str, nargs='+', help='the files to process') + + args = parser.parse_args() + + for arg in args.files: + for path in glob.glob(arg): + for i, packet in enumerate(TcpdumpOutputToPackets(GetTcpdumpOutput(path))): + print('\n'.join(packet.Test( + f'{args.name}{i}', args.link_type)) + ) + +if __name__ == '__main__': + main() diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls.go new file mode 100644 index 0000000000..b5c041f6ad --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls.go @@ -0,0 +1,283 @@ +// Copyright 2018 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. + +package layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// TLSType defines the type of data after the TLS Record +type TLSType uint8 + +// TLSType known values. +const ( + TLSChangeCipherSpec TLSType = 20 + TLSAlert TLSType = 21 + TLSHandshake TLSType = 22 + TLSApplicationData TLSType = 23 + TLSUnknown TLSType = 255 +) + +// String shows the register type nicely formatted +func (tt TLSType) String() string { + switch tt { + default: + return "Unknown" + case TLSChangeCipherSpec: + return "Change Cipher Spec" + case TLSAlert: + return "Alert" + case TLSHandshake: + return "Handshake" + case TLSApplicationData: + return "Application Data" + } +} + +// TLSVersion represents the TLS version in numeric format +type TLSVersion uint16 + +// Strings shows the TLS version nicely formatted +func (tv TLSVersion) String() string { + switch tv { + default: + return "Unknown" + case 0x0200: + return "SSL 2.0" + case 0x0300: + return "SSL 3.0" + case 0x0301: + return "TLS 1.0" + case 0x0302: + return "TLS 1.1" + case 0x0303: + return "TLS 1.2" + case 0x0304: + return "TLS 1.3" + } +} + +// TLS is specified in RFC 5246 +// +// TLS Record Protocol +// 0 1 2 3 4 5 6 7 8 +// +--+--+--+--+--+--+--+--+ +// | Content Type | +// +--+--+--+--+--+--+--+--+ +// | Version (major) | +// +--+--+--+--+--+--+--+--+ +// | Version (minor) | +// +--+--+--+--+--+--+--+--+ +// | Length | +// +--+--+--+--+--+--+--+--+ +// | Length | +// +--+--+--+--+--+--+--+--+ + +// TLS is actually a slide of TLSrecord structures +type TLS struct { + BaseLayer + + // TLS Records + ChangeCipherSpec []TLSChangeCipherSpecRecord + Handshake []TLSHandshakeRecord + AppData []TLSAppDataRecord + Alert []TLSAlertRecord +} + +// TLSRecordHeader contains all the information that each TLS Record types should have +type TLSRecordHeader struct { + ContentType TLSType + Version TLSVersion + Length uint16 +} + +// LayerType returns gopacket.LayerTypeTLS. +func (t *TLS) LayerType() gopacket.LayerType { return LayerTypeTLS } + +// decodeTLS decodes the byte slice into a TLS type. It also +// setups the application Layer in PacketBuilder. +func decodeTLS(data []byte, p gopacket.PacketBuilder) error { + t := &TLS{} + err := t.DecodeFromBytes(data, p) + if err != nil { + return err + } + p.AddLayer(t) + p.SetApplicationLayer(t) + return nil +} + +// DecodeFromBytes decodes the slice into the TLS struct. +func (t *TLS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + t.BaseLayer.Contents = data + t.BaseLayer.Payload = nil + + t.ChangeCipherSpec = t.ChangeCipherSpec[:0] + t.Handshake = t.Handshake[:0] + t.AppData = t.AppData[:0] + t.Alert = t.Alert[:0] + + return t.decodeTLSRecords(data, df) +} + +func (t *TLS) decodeTLSRecords(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 5 { + df.SetTruncated() + return errors.New("TLS record too short") + } + + // since there are no further layers, the baselayer's content is + // pointing to this layer + // TODO: Consider removing this + t.BaseLayer = BaseLayer{Contents: data[:len(data)]} + + var h TLSRecordHeader + h.ContentType = TLSType(data[0]) + h.Version = TLSVersion(binary.BigEndian.Uint16(data[1:3])) + h.Length = binary.BigEndian.Uint16(data[3:5]) + + if h.ContentType.String() == "Unknown" { + return errors.New("Unknown TLS record type") + } + + hl := 5 // header length + tl := hl + int(h.Length) + if len(data) < tl { + df.SetTruncated() + return errors.New("TLS packet length mismatch") + } + + switch h.ContentType { + default: + return errors.New("Unknown TLS record type") + case TLSChangeCipherSpec: + var r TLSChangeCipherSpecRecord + e := r.decodeFromBytes(h, data[hl:tl], df) + if e != nil { + return e + } + t.ChangeCipherSpec = append(t.ChangeCipherSpec, r) + case TLSAlert: + var r TLSAlertRecord + e := r.decodeFromBytes(h, data[hl:tl], df) + if e != nil { + return e + } + t.Alert = append(t.Alert, r) + case TLSHandshake: + var r TLSHandshakeRecord + e := r.decodeFromBytes(h, data[hl:tl], df) + if e != nil { + return e + } + t.Handshake = append(t.Handshake, r) + case TLSApplicationData: + var r TLSAppDataRecord + e := r.decodeFromBytes(h, data[hl:tl], df) + if e != nil { + return e + } + t.AppData = append(t.AppData, r) + } + + if len(data) == tl { + return nil + } + return t.decodeTLSRecords(data[tl:len(data)], df) +} + +// CanDecode implements gopacket.DecodingLayer. +func (t *TLS) CanDecode() gopacket.LayerClass { + return LayerTypeTLS +} + +// NextLayerType implements gopacket.DecodingLayer. +func (t *TLS) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// Payload returns nil, since TLS encrypted payload is inside TLSAppDataRecord +func (t *TLS) Payload() []byte { + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +func (t *TLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + totalLength := 0 + for _, record := range t.ChangeCipherSpec { + if opts.FixLengths { + record.Length = 1 + } + totalLength += 5 + 1 // length of header + record + } + for range t.Handshake { + totalLength += 5 + // TODO + } + for _, record := range t.AppData { + if opts.FixLengths { + record.Length = uint16(len(record.Payload)) + } + totalLength += 5 + len(record.Payload) + } + for _, record := range t.Alert { + if len(record.EncryptedMsg) == 0 { + if opts.FixLengths { + record.Length = 2 + } + totalLength += 5 + 2 + } else { + if opts.FixLengths { + record.Length = uint16(len(record.EncryptedMsg)) + } + totalLength += 5 + len(record.EncryptedMsg) + } + } + data, err := b.PrependBytes(totalLength) + if err != nil { + return err + } + off := 0 + for _, record := range t.ChangeCipherSpec { + off = encodeHeader(record.TLSRecordHeader, data, off) + data[off] = byte(record.Message) + off++ + } + for _, record := range t.Handshake { + off = encodeHeader(record.TLSRecordHeader, data, off) + // TODO + } + for _, record := range t.AppData { + off = encodeHeader(record.TLSRecordHeader, data, off) + copy(data[off:], record.Payload) + off += len(record.Payload) + } + for _, record := range t.Alert { + off = encodeHeader(record.TLSRecordHeader, data, off) + if len(record.EncryptedMsg) == 0 { + data[off] = byte(record.Level) + data[off+1] = byte(record.Description) + off += 2 + } else { + copy(data[off:], record.EncryptedMsg) + off += len(record.EncryptedMsg) + } + } + return nil +} + +func encodeHeader(header TLSRecordHeader, data []byte, offset int) int { + data[offset] = byte(header.ContentType) + binary.BigEndian.PutUint16(data[offset+1:], uint16(header.Version)) + binary.BigEndian.PutUint16(data[offset+3:], header.Length) + + return offset + 5 +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_alert.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_alert.go new file mode 100644 index 0000000000..15cc2e16d5 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_alert.go @@ -0,0 +1,165 @@ +// Copyright 2018 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. + +package layers + +import ( + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// TLSAlertLevel defines the alert level data type +type TLSAlertLevel uint8 + +// TLSAlertDescr defines the alert descrption data type +type TLSAlertDescr uint8 + +const ( + TLSAlertWarning TLSAlertLevel = 1 + TLSAlertFatal TLSAlertLevel = 2 + TLSAlertUnknownLevel TLSAlertLevel = 255 + + TLSAlertCloseNotify TLSAlertDescr = 0 + TLSAlertUnexpectedMessage TLSAlertDescr = 10 + TLSAlertBadRecordMac TLSAlertDescr = 20 + TLSAlertDecryptionFailedRESERVED TLSAlertDescr = 21 + TLSAlertRecordOverflow TLSAlertDescr = 22 + TLSAlertDecompressionFailure TLSAlertDescr = 30 + TLSAlertHandshakeFailure TLSAlertDescr = 40 + TLSAlertNoCertificateRESERVED TLSAlertDescr = 41 + TLSAlertBadCertificate TLSAlertDescr = 42 + TLSAlertUnsupportedCertificate TLSAlertDescr = 43 + TLSAlertCertificateRevoked TLSAlertDescr = 44 + TLSAlertCertificateExpired TLSAlertDescr = 45 + TLSAlertCertificateUnknown TLSAlertDescr = 46 + TLSAlertIllegalParameter TLSAlertDescr = 47 + TLSAlertUnknownCa TLSAlertDescr = 48 + TLSAlertAccessDenied TLSAlertDescr = 49 + TLSAlertDecodeError TLSAlertDescr = 50 + TLSAlertDecryptError TLSAlertDescr = 51 + TLSAlertExportRestrictionRESERVED TLSAlertDescr = 60 + TLSAlertProtocolVersion TLSAlertDescr = 70 + TLSAlertInsufficientSecurity TLSAlertDescr = 71 + TLSAlertInternalError TLSAlertDescr = 80 + TLSAlertUserCanceled TLSAlertDescr = 90 + TLSAlertNoRenegotiation TLSAlertDescr = 100 + TLSAlertUnsupportedExtension TLSAlertDescr = 110 + TLSAlertUnknownDescription TLSAlertDescr = 255 +) + +// TLS Alert +// 0 1 2 3 4 5 6 7 8 +// +--+--+--+--+--+--+--+--+ +// | Level | +// +--+--+--+--+--+--+--+--+ +// | Description | +// +--+--+--+--+--+--+--+--+ + +// TLSAlertRecord contains all the information that each Alert Record type should have +type TLSAlertRecord struct { + TLSRecordHeader + + Level TLSAlertLevel + Description TLSAlertDescr + + EncryptedMsg []byte +} + +// DecodeFromBytes decodes the slice into the TLS struct. +func (t *TLSAlertRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error { + // TLS Record Header + t.ContentType = h.ContentType + t.Version = h.Version + t.Length = h.Length + + if len(data) < 2 { + df.SetTruncated() + return errors.New("TLS Alert packet too short") + } + + if t.Length == 2 { + t.Level = TLSAlertLevel(data[0]) + t.Description = TLSAlertDescr(data[1]) + } else { + t.Level = TLSAlertUnknownLevel + t.Description = TLSAlertUnknownDescription + t.EncryptedMsg = data + } + + return nil +} + +// Strings shows the TLS alert level nicely formatted +func (al TLSAlertLevel) String() string { + switch al { + default: + return fmt.Sprintf("Unknown(%d)", al) + case TLSAlertWarning: + return "Warning" + case TLSAlertFatal: + return "Fatal" + } +} + +// Strings shows the TLS alert description nicely formatted +func (ad TLSAlertDescr) String() string { + switch ad { + default: + return "Unknown" + case TLSAlertCloseNotify: + return "close_notify" + case TLSAlertUnexpectedMessage: + return "unexpected_message" + case TLSAlertBadRecordMac: + return "bad_record_mac" + case TLSAlertDecryptionFailedRESERVED: + return "decryption_failed_RESERVED" + case TLSAlertRecordOverflow: + return "record_overflow" + case TLSAlertDecompressionFailure: + return "decompression_failure" + case TLSAlertHandshakeFailure: + return "handshake_failure" + case TLSAlertNoCertificateRESERVED: + return "no_certificate_RESERVED" + case TLSAlertBadCertificate: + return "bad_certificate" + case TLSAlertUnsupportedCertificate: + return "unsupported_certificate" + case TLSAlertCertificateRevoked: + return "certificate_revoked" + case TLSAlertCertificateExpired: + return "certificate_expired" + case TLSAlertCertificateUnknown: + return "certificate_unknown" + case TLSAlertIllegalParameter: + return "illegal_parameter" + case TLSAlertUnknownCa: + return "unknown_ca" + case TLSAlertAccessDenied: + return "access_denied" + case TLSAlertDecodeError: + return "decode_error" + case TLSAlertDecryptError: + return "decrypt_error" + case TLSAlertExportRestrictionRESERVED: + return "export_restriction_RESERVED" + case TLSAlertProtocolVersion: + return "protocol_version" + case TLSAlertInsufficientSecurity: + return "insufficient_security" + case TLSAlertInternalError: + return "internal_error" + case TLSAlertUserCanceled: + return "user_canceled" + case TLSAlertNoRenegotiation: + return "no_renegotiation" + case TLSAlertUnsupportedExtension: + return "unsupported_extension" + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_appdata.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_appdata.go new file mode 100644 index 0000000000..cc6b095b5d --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_appdata.go @@ -0,0 +1,34 @@ +// Copyright 2018 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. + +package layers + +import ( + "errors" + + "github.com/gopacket/gopacket" +) + +// TLSAppDataRecord contains all the information that each AppData Record types should have +type TLSAppDataRecord struct { + TLSRecordHeader + Payload []byte +} + +// DecodeFromBytes decodes the slice into the TLS struct. +func (t *TLSAppDataRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error { + // TLS Record Header + t.ContentType = h.ContentType + t.Version = h.Version + t.Length = h.Length + + if len(data) != int(t.Length) { + return errors.New("TLS Application Data length mismatch") + } + + t.Payload = data + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_cipherspec.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_cipherspec.go new file mode 100644 index 0000000000..5f9312ab43 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_cipherspec.go @@ -0,0 +1,64 @@ +// Copyright 2018 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. + +package layers + +import ( + "errors" + + "github.com/gopacket/gopacket" +) + +// TLSchangeCipherSpec defines the message value inside ChangeCipherSpec Record +type TLSchangeCipherSpec uint8 + +const ( + TLSChangecipherspecMessage TLSchangeCipherSpec = 1 + TLSChangecipherspecUnknown TLSchangeCipherSpec = 255 +) + +// TLS Change Cipher Spec +// 0 1 2 3 4 5 6 7 8 +// +--+--+--+--+--+--+--+--+ +// | Message | +// +--+--+--+--+--+--+--+--+ + +// TLSChangeCipherSpecRecord defines the type of data inside ChangeCipherSpec Record +type TLSChangeCipherSpecRecord struct { + TLSRecordHeader + + Message TLSchangeCipherSpec +} + +// DecodeFromBytes decodes the slice into the TLS struct. +func (t *TLSChangeCipherSpecRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error { + // TLS Record Header + t.ContentType = h.ContentType + t.Version = h.Version + t.Length = h.Length + + if len(data) != 1 { + df.SetTruncated() + return errors.New("TLS Change Cipher Spec record incorrect length") + } + + t.Message = TLSchangeCipherSpec(data[0]) + if t.Message != TLSChangecipherspecMessage { + t.Message = TLSChangecipherspecUnknown + } + + return nil +} + +// String shows the message value nicely formatted +func (ccs TLSchangeCipherSpec) String() string { + switch ccs { + default: + return "Unknown" + case TLSChangecipherspecMessage: + return "Change Cipher Spec Message" + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_handshake.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_handshake.go new file mode 100644 index 0000000000..7c3a68b0e9 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/tls_handshake.go @@ -0,0 +1,208 @@ +// Copyright 2018 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. + +package layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +// TLS Extensions http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml +type TLSExtension uint16 + +const ( + TLSExtServerName TLSExtension = 0 + TLSExtMaxFragLen TLSExtension = 1 + TLSExtClientCertURL TLSExtension = 2 + TLSExtTrustedCAKeys TLSExtension = 3 + TLSExtTruncatedHMAC TLSExtension = 4 + TLSExtStatusRequest TLSExtension = 5 + TLSExtUserMapping TLSExtension = 6 + TLSExtClientAuthz TLSExtension = 7 + TLSExtServerAuthz TLSExtension = 8 + TLSExtCertType TLSExtension = 9 + TLSExtSupportedGroups TLSExtension = 10 + TLSExtECPointFormats TLSExtension = 11 + TLSExtSRP TLSExtension = 12 + TLSExtSignatureAlgs TLSExtension = 13 + TLSxtUseSRTP TLSExtension = 14 + TLSExtHeartbeat TLSExtension = 15 + TLSExtALPN TLSExtension = 16 + TLSExtStatusRequestV2 TLSExtension = 17 + TLSExtSignedCertTS TLSExtension = 18 + TLSExtClientCertType TLSExtension = 19 + TLSExtServerCertType TLSExtension = 20 + TLSExtPadding TLSExtension = 21 + TLSExtEncryptThenMAC TLSExtension = 22 + TLSExtExtendedMasterSecret TLSExtension = 23 + TLSExtSessionTicket TLSExtension = 35 + TLSExtNPN TLSExtension = 13172 + TLSExtRenegotiationInfo TLSExtension = 65281 +) + +/*refer to https://datatracker.ietf.org/doc/html/rfc5246#appendix-A.4*/ +const ( + TLSHandshakeHelloRequest = 0 + TLSHandshakeClientHello = 1 + TLSHandshakeServerHello = 2 + TLSHandsharkHelloVerirfyRequest = 3 + TLSHandshakeCertificate = 11 + TLSHandshakeServerKeyExchange = 12 + TLSHandshakeCertificateRequest = 13 + TLSHandshakeServerHelloDone = 14 + TLSHandshakeCertificateVerify = 15 + TLSHandshakeClientKeyExchange = 16 + TLSHandshakeFinished = 20 +) + +var handShakeTypeMap = map[uint8]string{ + TLSHandshakeHelloRequest: "Hello Request", + TLSHandshakeClientHello: "Client Hello", + TLSHandshakeServerHello: "Server Hello", + TLSHandsharkHelloVerirfyRequest: "Hello Verify Request", + TLSHandshakeCertificate: "Certificate", + TLSHandshakeServerKeyExchange: "Server Key Exchange", + TLSHandshakeCertificateRequest: "Certificate Request", + TLSHandshakeServerHelloDone: "Server Hello Done", + TLSHandshakeCertificateVerify: "Certificate Verify", + TLSHandshakeClientKeyExchange: "Client Key Exchange", + TLSHandshakeFinished: "Finished", +} + +type TLSHandshakeRecordClientHello struct { + HandshakeType uint8 + Length uint32 + ProtocolVersion TLSVersion + Random []uint8 + SessionIDLength uint8 + SessionID []uint8 + CipherSuitsLength uint16 + CipherSuits []uint8 + CompressionMethodsLength uint8 + CompressionMethods []uint8 + ExtensionsLength uint16 + Extensions []uint8 + SNI []uint8 +} + +type TLSHandshakeRecordClientKeyChange struct { +} + +// TLSHandshakeRecord defines the structure of a Handshare Record +type TLSHandshakeRecord struct { + TLSRecordHeader + ClientHello TLSHandshakeRecordClientHello + ClientKeyChange TLSHandshakeRecordClientKeyChange +} + +func (t *TLSHandshakeRecordClientHello) decodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + t.HandshakeType = data[0] + d := make([]byte, 4) + for k, v := range data[1:4] { + d[k+1] = v + } + t.Length = binary.BigEndian.Uint32(d) + t.ProtocolVersion = TLSVersion(binary.BigEndian.Uint16(data[4:6])) + t.Random = data[6:38] + t.SessionIDLength = data[38] + t.SessionID = data[39 : 39+t.SessionIDLength] + t.CipherSuitsLength = binary.BigEndian.Uint16(data[39+t.SessionIDLength : 39+t.SessionIDLength+2]) + t.CipherSuits = data[39+t.SessionIDLength+2 : (39 + uint16(t.SessionIDLength) + 2 + t.CipherSuitsLength)] + t.CompressionMethodsLength = data[(39 + uint16(t.SessionIDLength) + 2 + t.CipherSuitsLength)] + t.CompressionMethods = data[(39+uint16(t.SessionIDLength)+2+t.CipherSuitsLength)+1 : (39+uint16(t.SessionIDLength)+2+t.CipherSuitsLength)+1+uint16(t.CompressionMethodsLength)] + t.ExtensionsLength = binary.BigEndian.Uint16(data[(39+uint16(t.SessionIDLength)+2+t.CipherSuitsLength)+1+uint16(t.CompressionMethodsLength) : (39+uint16(t.SessionIDLength)+2+t.CipherSuitsLength)+1+uint16(t.CompressionMethodsLength)+2]) + + // extract extension data + data = data[((39 + uint16(t.SessionIDLength) + 2 + t.CipherSuitsLength) + 1 + uint16(t.CompressionMethodsLength) + 2) : ((39+uint16(t.SessionIDLength)+2+t.CipherSuitsLength)+1+uint16(t.CompressionMethodsLength)+2)+t.ExtensionsLength] + t.Extensions = data + for len(data) > 0 { + if len(data) < 4 { + break + } + extensionType := binary.BigEndian.Uint16(data[:2]) + length := binary.BigEndian.Uint16(data[2:4]) + if len(data) < 4+int(length) { + break + } + switch TLSExtension(extensionType) { + case TLSExtServerName: + if len(data) > 6 { + serverNameExtensionLength := binary.BigEndian.Uint16(data[4:6]) + entryType := data[6] + if serverNameExtensionLength > 0 && entryType == 0 && len(data) > 8 { // 0 = DNS hostname + hostnameLength := binary.BigEndian.Uint16(data[7:9]) + if len(data) > int(8+hostnameLength) { + t.SNI = data[9 : 9+hostnameLength] + } + } + } + } + data = data[4+length:] + } + + return nil +} +func (t *TLSHandshakeRecordClientKeyChange) decodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + /*TBD*/ + return nil +} + +/** + * Checks whether a handshake message seems encrypted and cannot be dissected. + */ +func (t TLSHandshakeRecord) isEncryptedHandshakeMessage(h TLSRecordHeader, data []byte) bool { + if h.Length < 16 { + /* + * Encrypted data has additional overhead. For TLS 1.0/1.1 with stream + * and block ciphers, there is at least a MAC which is at minimum 16 + * bytes for MD5. In TLS 1.2, AEAD adds an explicit nonce and auth tag. + * For AES-GCM/CCM the auth tag is 16 bytes. AES_CCM_8 (RFC 6655) uses 8 + * byte auth tags, but the explicit nonce is also 8 (sums up to 16). + * + * So anything smaller than 16 bytes is assumed to be plaintext. + */ + return false + } + maybeType := data[0] + d := make([]byte, 4) + for k, v := range data[1:4] { + d[k+1] = v + } + if uint32(h.Length)-binary.BigEndian.Uint32(d) != 4 { + return true + } + if _, ok := handShakeTypeMap[maybeType]; !ok { + return true + } + return false +} + +// DecodeFromBytes decodes the slice into the TLS struct. +func (t *TLSHandshakeRecord) decodeFromBytes(h TLSRecordHeader, data []byte, df gopacket.DecodeFeedback) error { + // TLS Record Header + t.ContentType = h.ContentType + t.Version = h.Version + t.Length = h.Length + + if t.isEncryptedHandshakeMessage(h, data) { + return nil + } + handshakeType := data[0] + switch handshakeType { + case TLSHandshakeClientHello: + t.ClientHello.decodeFromBytes(data, df) + case TLSHandshakeClientKeyExchange: + t.ClientKeyChange.decodeFromBytes(data, df) + default: + return errors.New("Unknown TLS handshake type") + // TODO + } + + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udp.go new file mode 100644 index 0000000000..ed489130e3 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udp.go @@ -0,0 +1,158 @@ +// 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 layers + +import ( + "encoding/binary" + "fmt" + + "github.com/gopacket/gopacket" +) + +// UDP is the layer for UDP headers. +type UDP struct { + BaseLayer + SrcPort, DstPort UDPPort + Length uint16 + Checksum uint16 + sPort, dPort []byte + tcpipchecksum +} + +// LayerType returns gopacket.LayerTypeUDP +func (u *UDP) LayerType() gopacket.LayerType { return LayerTypeUDP } + +func (udp *UDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + df.SetTruncated() + return fmt.Errorf("Invalid UDP header. Length %d less than 8", len(data)) + } + udp.SrcPort = UDPPort(binary.BigEndian.Uint16(data[0:2])) + udp.sPort = data[0:2] + udp.DstPort = UDPPort(binary.BigEndian.Uint16(data[2:4])) + udp.dPort = data[2:4] + udp.Length = binary.BigEndian.Uint16(data[4:6]) + udp.Checksum = binary.BigEndian.Uint16(data[6:8]) + udp.BaseLayer = BaseLayer{Contents: data[:8]} + switch { + case udp.Length >= 8: + hlen := int(udp.Length) + if hlen > len(data) { + df.SetTruncated() + hlen = len(data) + } + udp.Payload = data[8:hlen] + case udp.Length == 0: // Jumbogram, use entire rest of data + udp.Payload = data[8:] + default: + return fmt.Errorf("UDP packet too small: %d bytes", udp.Length) + } + return nil +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (u *UDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + var jumbo bool + + payload := b.Bytes() + if _, ok := u.pseudoheader.(*IPv6); ok { + if len(payload)+8 > 65535 { + jumbo = true + } + } + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + binary.BigEndian.PutUint16(bytes, uint16(u.SrcPort)) + binary.BigEndian.PutUint16(bytes[2:], uint16(u.DstPort)) + if opts.FixLengths { + if jumbo { + u.Length = 0 + } else { + u.Length = uint16(len(payload)) + 8 + } + } + binary.BigEndian.PutUint16(bytes[4:], u.Length) + if opts.ComputeChecksums { + // zero out checksum bytes + bytes[6] = 0 + bytes[7] = 0 + + csum, err := u.computeChecksum(b.Bytes(), IPProtocolUDP) + if err != nil { + return err + } + csumFolded := gopacket.FoldChecksum(csum) + + // RFC768: If the computed checksum is zero, it is transmitted as all ones (the + // equivalent in one's complement arithmetic). An all zero transmitted + // checksum value means that the transmitter generated no checksum. + if csumFolded == 0 { + csumFolded = 0xffff + } + u.Checksum = csumFolded + } + binary.BigEndian.PutUint16(bytes[6:], u.Checksum) + return nil +} + +func (u *UDP) CanDecode() gopacket.LayerClass { + return LayerTypeUDP +} + +// NextLayerType use the destination port to select the +// right next decoder. It tries first to decode via the +// destination port, then the source port. +func (u *UDP) NextLayerType() gopacket.LayerType { + if lt := u.DstPort.LayerType(); lt != gopacket.LayerTypePayload { + return lt + } + return u.SrcPort.LayerType() +} + +func decodeUDP(data []byte, p gopacket.PacketBuilder) error { + udp := &UDP{} + err := udp.DecodeFromBytes(data, p) + p.AddLayer(udp) + p.SetTransportLayer(udp) + if err != nil { + return err + } + return p.NextDecoder(udp.NextLayerType()) +} + +func (u *UDP) TransportFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointUDPPort, u.sPort, u.dPort) +} + +// For testing only +func (u *UDP) SetInternalPortsForTesting() { + u.sPort = make([]byte, 2) + u.dPort = make([]byte, 2) + binary.BigEndian.PutUint16(u.sPort, uint16(u.SrcPort)) + binary.BigEndian.PutUint16(u.dPort, uint16(u.DstPort)) +} + +func (u *UDP) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) { + bytes := append(u.Contents, u.Payload...) + + existing := u.Checksum + verification, err := u.computeChecksum(bytes, IPProtocolUDP) + if err != nil { + return err, gopacket.ChecksumVerificationResult{} + } + correct := gopacket.FoldChecksum(verification - uint32(existing)) + return nil, gopacket.ChecksumVerificationResult{ + Valid: existing == 0 || correct == existing, + Correct: uint32(correct), + Actual: uint32(existing), + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udplite.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udplite.go new file mode 100644 index 0000000000..6566e17b80 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/udplite.go @@ -0,0 +1,45 @@ +// 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 layers + +import ( + "encoding/binary" + + "github.com/gopacket/gopacket" +) + +// UDPLite is the layer for UDP-Lite headers (rfc 3828). +type UDPLite struct { + BaseLayer + SrcPort, DstPort UDPLitePort + ChecksumCoverage uint16 + Checksum uint16 + sPort, dPort []byte +} + +// LayerType returns gopacket.LayerTypeUDPLite +func (u *UDPLite) LayerType() gopacket.LayerType { return LayerTypeUDPLite } + +func decodeUDPLite(data []byte, p gopacket.PacketBuilder) error { + udp := &UDPLite{ + SrcPort: UDPLitePort(binary.BigEndian.Uint16(data[0:2])), + sPort: data[0:2], + DstPort: UDPLitePort(binary.BigEndian.Uint16(data[2:4])), + dPort: data[2:4], + ChecksumCoverage: binary.BigEndian.Uint16(data[4:6]), + Checksum: binary.BigEndian.Uint16(data[6:8]), + BaseLayer: BaseLayer{data[:8], data[8:]}, + } + p.AddLayer(udp) + p.SetTransportLayer(udp) + return p.NextDecoder(gopacket.LayerTypePayload) +} + +func (u *UDPLite) TransportFlow() gopacket.Flow { + return gopacket.NewFlow(EndpointUDPLitePort, u.sPort, u.dPort) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/usb.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/usb.go new file mode 100644 index 0000000000..b04791d5b9 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/usb.go @@ -0,0 +1,293 @@ +// Copyright 2014 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 layers + +import ( + "encoding/binary" + "errors" + + "github.com/gopacket/gopacket" +) + +type USBEventType uint8 + +const ( + USBEventTypeSubmit USBEventType = 'S' + USBEventTypeComplete USBEventType = 'C' + USBEventTypeError USBEventType = 'E' +) + +func (a USBEventType) String() string { + switch a { + case USBEventTypeSubmit: + return "SUBMIT" + case USBEventTypeComplete: + return "COMPLETE" + case USBEventTypeError: + return "ERROR" + default: + return "Unknown event type" + } +} + +type USBRequestBlockSetupRequest uint8 + +const ( + USBRequestBlockSetupRequestGetStatus USBRequestBlockSetupRequest = 0x00 + USBRequestBlockSetupRequestClearFeature USBRequestBlockSetupRequest = 0x01 + USBRequestBlockSetupRequestSetFeature USBRequestBlockSetupRequest = 0x03 + USBRequestBlockSetupRequestSetAddress USBRequestBlockSetupRequest = 0x05 + USBRequestBlockSetupRequestGetDescriptor USBRequestBlockSetupRequest = 0x06 + USBRequestBlockSetupRequestSetDescriptor USBRequestBlockSetupRequest = 0x07 + USBRequestBlockSetupRequestGetConfiguration USBRequestBlockSetupRequest = 0x08 + USBRequestBlockSetupRequestSetConfiguration USBRequestBlockSetupRequest = 0x09 + USBRequestBlockSetupRequestSetIdle USBRequestBlockSetupRequest = 0x0a +) + +func (a USBRequestBlockSetupRequest) String() string { + switch a { + case USBRequestBlockSetupRequestGetStatus: + return "GET_STATUS" + case USBRequestBlockSetupRequestClearFeature: + return "CLEAR_FEATURE" + case USBRequestBlockSetupRequestSetFeature: + return "SET_FEATURE" + case USBRequestBlockSetupRequestSetAddress: + return "SET_ADDRESS" + case USBRequestBlockSetupRequestGetDescriptor: + return "GET_DESCRIPTOR" + case USBRequestBlockSetupRequestSetDescriptor: + return "SET_DESCRIPTOR" + case USBRequestBlockSetupRequestGetConfiguration: + return "GET_CONFIGURATION" + case USBRequestBlockSetupRequestSetConfiguration: + return "SET_CONFIGURATION" + case USBRequestBlockSetupRequestSetIdle: + return "SET_IDLE" + default: + return "UNKNOWN" + } +} + +type USBTransportType uint8 + +const ( + USBTransportTypeTransferIn USBTransportType = 0x80 // Indicates send or receive + USBTransportTypeIsochronous USBTransportType = 0x00 // Isochronous transfers occur continuously and periodically. They typically contain time sensitive information, such as an audio or video stream. + USBTransportTypeInterrupt USBTransportType = 0x01 // Interrupt transfers are typically non-periodic, small device "initiated" communication requiring bounded latency, such as pointing devices or keyboards. + USBTransportTypeControl USBTransportType = 0x02 // Control transfers are typically used for command and status operations. + USBTransportTypeBulk USBTransportType = 0x03 // Bulk transfers can be used for large bursty data, using all remaining available bandwidth, no guarantees on bandwidth or latency, such as file transfers. +) + +type USBDirectionType uint8 + +const ( + USBDirectionTypeUnknown USBDirectionType = iota + USBDirectionTypeIn + USBDirectionTypeOut +) + +func (a USBDirectionType) String() string { + switch a { + case USBDirectionTypeIn: + return "In" + case USBDirectionTypeOut: + return "Out" + default: + return "Unknown direction type" + } +} + +// The reference at http://www.beyondlogic.org/usbnutshell/usb1.shtml contains more information about the protocol. +type USB struct { + BaseLayer + ID uint64 + EventType USBEventType + TransferType USBTransportType + Direction USBDirectionType + EndpointNumber uint8 + DeviceAddress uint8 + BusID uint16 + TimestampSec int64 + TimestampUsec int32 + Setup bool + Data bool + Status int32 + UrbLength uint32 + UrbDataLength uint32 + + UrbInterval uint32 + UrbStartFrame uint32 + UrbCopyOfTransferFlags uint32 + IsoNumDesc uint32 +} + +func (u *USB) LayerType() gopacket.LayerType { return LayerTypeUSB } + +func (m *USB) NextLayerType() gopacket.LayerType { + if m.Setup { + return LayerTypeUSBRequestBlockSetup + } else if m.Data { + } + + return m.TransferType.LayerType() +} + +func decodeUSB(data []byte, p gopacket.PacketBuilder) error { + d := &USB{} + + return decodingLayerDecoder(d, data, p) +} + +func (m *USB) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 40 { + df.SetTruncated() + return errors.New("USB < 40 bytes") + } + m.ID = binary.LittleEndian.Uint64(data[0:8]) + m.EventType = USBEventType(data[8]) + m.TransferType = USBTransportType(data[9]) + + m.EndpointNumber = data[10] & 0x7f + if data[10]&uint8(USBTransportTypeTransferIn) > 0 { + m.Direction = USBDirectionTypeIn + } else { + m.Direction = USBDirectionTypeOut + } + + m.DeviceAddress = data[11] + m.BusID = binary.LittleEndian.Uint16(data[12:14]) + + if uint(data[14]) == 0 { + m.Setup = true + } + + if uint(data[15]) == 0 { + m.Data = true + } + + m.TimestampSec = int64(binary.LittleEndian.Uint64(data[16:24])) + m.TimestampUsec = int32(binary.LittleEndian.Uint32(data[24:28])) + m.Status = int32(binary.LittleEndian.Uint32(data[28:32])) + m.UrbLength = binary.LittleEndian.Uint32(data[32:36]) + m.UrbDataLength = binary.LittleEndian.Uint32(data[36:40]) + + m.Contents = data[:40] + m.Payload = data[40:] + + if m.Setup { + m.Payload = data[40:] + } else if m.Data { + m.Payload = data[uint32(len(data))-m.UrbDataLength:] + } + + // if 64 bit, dissect_linux_usb_pseudo_header_ext + if false { + m.UrbInterval = binary.LittleEndian.Uint32(data[40:44]) + m.UrbStartFrame = binary.LittleEndian.Uint32(data[44:48]) + m.UrbDataLength = binary.LittleEndian.Uint32(data[48:52]) + m.IsoNumDesc = binary.LittleEndian.Uint32(data[52:56]) + m.Contents = data[:56] + m.Payload = data[56:] + } + + // crc5 or crc16 + // eop (end of packet) + + return nil +} + +type USBRequestBlockSetup struct { + BaseLayer + RequestType uint8 + Request USBRequestBlockSetupRequest + Value uint16 + Index uint16 + Length uint16 +} + +func (u *USBRequestBlockSetup) LayerType() gopacket.LayerType { return LayerTypeUSBRequestBlockSetup } + +func (m *USBRequestBlockSetup) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func (m *USBRequestBlockSetup) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.RequestType = data[0] + m.Request = USBRequestBlockSetupRequest(data[1]) + m.Value = binary.LittleEndian.Uint16(data[2:4]) + m.Index = binary.LittleEndian.Uint16(data[4:6]) + m.Length = binary.LittleEndian.Uint16(data[6:8]) + m.Contents = data[:8] + m.Payload = data[8:] + return nil +} + +func decodeUSBRequestBlockSetup(data []byte, p gopacket.PacketBuilder) error { + d := &USBRequestBlockSetup{} + return decodingLayerDecoder(d, data, p) +} + +type USBControl struct { + BaseLayer +} + +func (u *USBControl) LayerType() gopacket.LayerType { return LayerTypeUSBControl } + +func (m *USBControl) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func (m *USBControl) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +func decodeUSBControl(data []byte, p gopacket.PacketBuilder) error { + d := &USBControl{} + return decodingLayerDecoder(d, data, p) +} + +type USBInterrupt struct { + BaseLayer +} + +func (u *USBInterrupt) LayerType() gopacket.LayerType { return LayerTypeUSBInterrupt } + +func (m *USBInterrupt) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func (m *USBInterrupt) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +func decodeUSBInterrupt(data []byte, p gopacket.PacketBuilder) error { + d := &USBInterrupt{} + return decodingLayerDecoder(d, data, p) +} + +type USBBulk struct { + BaseLayer +} + +func (u *USBBulk) LayerType() gopacket.LayerType { return LayerTypeUSBBulk } + +func (m *USBBulk) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypePayload +} + +func (m *USBBulk) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + m.Contents = data + return nil +} + +func decodeUSBBulk(data []byte, p gopacket.PacketBuilder) error { + d := &USBBulk{} + return decodingLayerDecoder(d, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vrrp.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vrrp.go new file mode 100644 index 0000000000..b512e6f827 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vrrp.go @@ -0,0 +1,156 @@ +// Copyright 2016 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 layers + +import ( + "encoding/binary" + "errors" + "net" + + "github.com/gopacket/gopacket" +) + +/* + This layer provides decoding for Virtual Router Redundancy Protocol (VRRP) v2. + https://tools.ietf.org/html/rfc3768#section-5 + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Version| Type | Virtual Rtr ID| Priority | Count IP Addrs| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Auth Type | Adver Int | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IP Address (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | . | + | . | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IP Address (n) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Authentication Data (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Authentication Data (2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +type VRRPv2Type uint8 +type VRRPv2AuthType uint8 + +const ( + VRRPv2Advertisement VRRPv2Type = 0x01 // router advertisement +) + +// String conversions for VRRP message types +func (v VRRPv2Type) String() string { + switch v { + case VRRPv2Advertisement: + return "VRRPv2 Advertisement" + default: + return "" + } +} + +const ( + VRRPv2AuthNoAuth VRRPv2AuthType = 0x00 // No Authentication + VRRPv2AuthReserved1 VRRPv2AuthType = 0x01 // Reserved field 1 + VRRPv2AuthReserved2 VRRPv2AuthType = 0x02 // Reserved field 2 +) + +func (v VRRPv2AuthType) String() string { + switch v { + case VRRPv2AuthNoAuth: + return "No Authentication" + case VRRPv2AuthReserved1: + return "Reserved" + case VRRPv2AuthReserved2: + return "Reserved" + default: + return "" + } +} + +// VRRPv2 represents an VRRP v2 message. +type VRRPv2 struct { + BaseLayer + Version uint8 // The version field specifies the VRRP protocol version of this packet (v2) + Type VRRPv2Type // The type field specifies the type of this VRRP packet. The only type defined in v2 is ADVERTISEMENT + VirtualRtrID uint8 // identifies the virtual router this packet is reporting status for + Priority uint8 // specifies the sending VRRP router's priority for the virtual router (100 = default) + CountIPAddr uint8 // The number of IP addresses contained in this VRRP advertisement. + AuthType VRRPv2AuthType // identifies the authentication method being utilized + AdverInt uint8 // The Advertisement interval indicates the time interval (in seconds) between ADVERTISEMENTS. The default is 1 second + Checksum uint16 // used to detect data corruption in the VRRP message. + IPAddress []net.IP // one or more IP addresses associated with the virtual router. Specified in the CountIPAddr field. +} + +// LayerType returns LayerTypeVRRP for VRRP v2 message. +func (v *VRRPv2) LayerType() gopacket.LayerType { return LayerTypeVRRP } + +func (v *VRRPv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + + v.BaseLayer = BaseLayer{Contents: data[:len(data)]} + v.Version = data[0] >> 4 // high nibble == VRRP version. We're expecting v2 + + v.Type = VRRPv2Type(data[0] & 0x0F) // low nibble == VRRP type. Expecting 1 (advertisement) + if v.Type != 1 { + // rfc3768: A packet with unknown type MUST be discarded. + return errors.New("Unrecognized VRRPv2 type field.") + } + + v.VirtualRtrID = data[1] + v.Priority = data[2] + + v.CountIPAddr = data[3] + if v.CountIPAddr < 1 { + return errors.New("VRRPv2 number of IP addresses is not valid.") + } + + v.AuthType = VRRPv2AuthType(data[4]) + v.AdverInt = uint8(data[5]) + v.Checksum = binary.BigEndian.Uint16(data[6:8]) + + // populate the IPAddress field. The number of addresses is specified in the v.CountIPAddr field + // offset references the starting byte containing the list of ip addresses + offset := 8 + for i := uint8(0); i < v.CountIPAddr; i++ { + v.IPAddress = append(v.IPAddress, data[offset:offset+4]) + offset += 4 + } + + // any trailing packets here may be authentication data and *should* be ignored in v2 as per RFC + // + // 5.3.10. Authentication Data + // + // The authentication string is currently only used to maintain + // backwards compatibility with RFC 2338. It SHOULD be set to zero on + // transmission and ignored on reception. + return nil +} + +// CanDecode specifies the layer type in which we are attempting to unwrap. +func (v *VRRPv2) CanDecode() gopacket.LayerClass { + return LayerTypeVRRP +} + +// NextLayerType specifies the next layer that should be decoded. VRRP does not contain any further payload, so we set to 0 +func (v *VRRPv2) NextLayerType() gopacket.LayerType { + return gopacket.LayerTypeZero +} + +// The VRRP packet does not include payload data. Setting byte slice to nil +func (v *VRRPv2) Payload() []byte { + return nil +} + +// decodeVRRP will parse VRRP v2 +func decodeVRRP(data []byte, p gopacket.PacketBuilder) error { + if len(data) < 8 { + return errors.New("Not a valid VRRP packet. Packet length is too small.") + } + v := &VRRPv2{} + return decodingLayerDecoder(v, data, p) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vxlan.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vxlan.go new file mode 100644 index 0000000000..f7cdc040a9 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers/vxlan.go @@ -0,0 +1,123 @@ +// Copyright 2016 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 layers + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/gopacket/gopacket" +) + +// VXLAN is specifed in RFC 7348 https://tools.ietf.org/html/rfc7348 +// G, D, A, Group Policy ID from https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00 +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// 0 8 16 24 32 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |G|R|R|R|I|R|R|R|R|D|R|R|A|R|R|R| Group Policy ID | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | 24 bit VXLAN Network Identifier | Reserved | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// VXLAN is a VXLAN packet header +type VXLAN struct { + BaseLayer + ValidIDFlag bool // 'I' bit per RFC 7348 + VNI uint32 // 'VXLAN Network Identifier' 24 bits per RFC 7348 + GBPExtension bool // 'G' bit per Group Policy https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00 + GBPDontLearn bool // 'D' bit per Group Policy + GBPApplied bool // 'A' bit per Group Policy + GBPGroupPolicyID uint16 // 'Group Policy ID' 16 bits per Group Policy +} + +// LayerType returns LayerTypeVXLAN +func (vx *VXLAN) LayerType() gopacket.LayerType { return LayerTypeVXLAN } + +// CanDecode returns the layer type this DecodingLayer can decode +func (vx *VXLAN) CanDecode() gopacket.LayerClass { + return LayerTypeVXLAN +} + +// NextLayerType retuns the next layer we should see after vxlan +func (vx *VXLAN) NextLayerType() gopacket.LayerType { + return LayerTypeEthernet +} + +// DecodeFromBytes takes a byte buffer and decodes +func (vx *VXLAN) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { + if len(data) < 8 { + return errors.New("vxlan packet too small") + } + // VNI is a 24bit number, Uint32 requires 32 bits + var buf [4]byte + copy(buf[1:], data[4:7]) + + // RFC 7348 https://tools.ietf.org/html/rfc7348 + vx.ValidIDFlag = data[0]&0x08 > 0 // 'I' bit per RFC7348 + vx.VNI = binary.BigEndian.Uint32(buf[:]) // VXLAN Network Identifier per RFC7348 + + // Group Based Policy https://tools.ietf.org/html/draft-smith-vxlan-group-policy-00 + vx.GBPExtension = data[0]&0x80 > 0 // 'G' bit per the group policy draft + vx.GBPDontLearn = data[1]&0x40 > 0 // 'D' bit - the egress VTEP MUST NOT learn the source address of the encapsulated frame. + vx.GBPApplied = data[1]&0x80 > 0 // 'A' bit - indicates that the group policy has already been applied to this packet. + vx.GBPGroupPolicyID = binary.BigEndian.Uint16(data[2:4]) // Policy ID as per the group policy draft + + // Layer information + const vxlanLength = 8 + vx.Contents = data[:vxlanLength] + vx.Payload = data[vxlanLength:] + + return nil + +} + +func decodeVXLAN(data []byte, p gopacket.PacketBuilder) error { + vx := &VXLAN{} + err := vx.DecodeFromBytes(data, p) + if err != nil { + return err + } + + p.AddLayer(vx) + return p.NextDecoder(LinkTypeEthernet) +} + +// SerializeTo writes the serialized form of this layer into the +// SerializationBuffer, implementing gopacket.SerializableLayer. +// See the docs for gopacket.SerializableLayer for more info. +func (vx *VXLAN) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { + bytes, err := b.PrependBytes(8) + if err != nil { + return err + } + + // PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero + bytes[0] = 0 + bytes[1] = 0 + + if vx.ValidIDFlag { + bytes[0] |= 0x08 + } + if vx.GBPExtension { + bytes[0] |= 0x80 + } + if vx.GBPDontLearn { + bytes[1] |= 0x40 + } + if vx.GBPApplied { + bytes[1] |= 0x80 + } + + binary.BigEndian.PutUint16(bytes[2:4], vx.GBPGroupPolicyID) + if vx.VNI >= 1<<24 { + return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", vx.VNI) + } + binary.BigEndian.PutUint32(bytes[4:8], vx.VNI<<8) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers_decoder.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers_decoder.go new file mode 100644 index 0000000000..8c1f108cfc --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layers_decoder.go @@ -0,0 +1,101 @@ +// Copyright 2019 The GoPacket Authors. All rights reserved. + +package gopacket + +// Created by gen.go, don't edit manually +// Generated at 2019-06-18 11:37:31.308731293 +0600 +06 m=+0.000842599 + +// LayersDecoder returns DecodingLayerFunc for specified +// DecodingLayerContainer, LayerType value to start decoding with and +// some DecodeFeedback. +func LayersDecoder(dl DecodingLayerContainer, first LayerType, df DecodeFeedback) DecodingLayerFunc { + firstDec, ok := dl.Decoder(first) + if !ok { + return func([]byte, *[]LayerType) (LayerType, error) { + return first, nil + } + } + if dlc, ok := dl.(DecodingLayerSparse); ok { + return func(data []byte, decoded *[]LayerType) (LayerType, error) { + *decoded = (*decoded)[:0] // Truncated decoded layers. + typ := first + decoder := firstDec + for { + if err := decoder.DecodeFromBytes(data, df); err != nil { + return LayerTypeZero, err + } + *decoded = append(*decoded, typ) + typ = decoder.NextLayerType() + if data = decoder.LayerPayload(); len(data) == 0 { + break + } + if decoder, ok = dlc.Decoder(typ); !ok { + return typ, nil + } + } + return LayerTypeZero, nil + } + } + if dlc, ok := dl.(DecodingLayerArray); ok { + return func(data []byte, decoded *[]LayerType) (LayerType, error) { + *decoded = (*decoded)[:0] // Truncated decoded layers. + typ := first + decoder := firstDec + for { + if err := decoder.DecodeFromBytes(data, df); err != nil { + return LayerTypeZero, err + } + *decoded = append(*decoded, typ) + typ = decoder.NextLayerType() + if data = decoder.LayerPayload(); len(data) == 0 { + break + } + if decoder, ok = dlc.Decoder(typ); !ok { + return typ, nil + } + } + return LayerTypeZero, nil + } + } + if dlc, ok := dl.(DecodingLayerMap); ok { + return func(data []byte, decoded *[]LayerType) (LayerType, error) { + *decoded = (*decoded)[:0] // Truncated decoded layers. + typ := first + decoder := firstDec + for { + if err := decoder.DecodeFromBytes(data, df); err != nil { + return LayerTypeZero, err + } + *decoded = append(*decoded, typ) + typ = decoder.NextLayerType() + if data = decoder.LayerPayload(); len(data) == 0 { + break + } + if decoder, ok = dlc.Decoder(typ); !ok { + return typ, nil + } + } + return LayerTypeZero, nil + } + } + dlc := dl + return func(data []byte, decoded *[]LayerType) (LayerType, error) { + *decoded = (*decoded)[:0] // Truncated decoded layers. + typ := first + decoder := firstDec + for { + if err := decoder.DecodeFromBytes(data, df); err != nil { + return LayerTypeZero, err + } + *decoded = append(*decoded, typ) + typ = decoder.NextLayerType() + if data = decoder.LayerPayload(); len(data) == 0 { + break + } + if decoder, ok = dlc.Decoder(typ); !ok { + return typ, nil + } + } + return LayerTypeZero, nil + } +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layertype.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layertype.go new file mode 100644 index 0000000000..3abfee1e9b --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/layertype.go @@ -0,0 +1,111 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" + "strconv" +) + +// LayerType is a unique identifier for each type of layer. This enumeration +// does not match with any externally available numbering scheme... it's solely +// usable/useful within this library as a means for requesting layer types +// (see Packet.Layer) and determining which types of layers have been decoded. +// +// New LayerTypes may be created by calling gopacket.RegisterLayerType. +type LayerType int64 + +// LayerTypeMetadata contains metadata associated with each LayerType. +type LayerTypeMetadata struct { + // Name is the string returned by each layer type's String method. + Name string + // Decoder is the decoder to use when the layer type is passed in as a + // Decoder. + Decoder Decoder +} + +type layerTypeMetadata struct { + inUse bool + LayerTypeMetadata +} + +// DecodersByLayerName maps layer names to decoders for those layers. +// This allows users to specify decoders by name to a program and have that +// program pick the correct decoder accordingly. +var DecodersByLayerName = map[string]Decoder{} + +const maxLayerType = 2000 + +var ltMeta [maxLayerType]layerTypeMetadata +var ltMetaMap = map[LayerType]layerTypeMetadata{} + +// RegisterLayerType creates a new layer type and registers it globally. +// The number passed in must be unique, or a runtime panic will occur. Numbers +// 0-999 are reserved for the gopacket library. Numbers 1000-1999 should be +// used for common application-specific types, and are very fast. Any other +// number (negative or >= 2000) may be used for uncommon application-specific +// types, and are somewhat slower (they require a map lookup over an array +// index). +func RegisterLayerType(num int, meta LayerTypeMetadata) LayerType { + if 0 <= num && num < maxLayerType { + if ltMeta[num].inUse { + panic("Layer type already exists") + } + } else { + if ltMetaMap[LayerType(num)].inUse { + panic("Layer type already exists") + } + } + return OverrideLayerType(num, meta) +} + +// OverrideLayerType acts like RegisterLayerType, except that if the layer type +// has already been registered, it overrides the metadata with the passed-in +// metadata intead of panicing. +func OverrideLayerType(num int, meta LayerTypeMetadata) LayerType { + if 0 <= num && num < maxLayerType { + ltMeta[num] = layerTypeMetadata{ + inUse: true, + LayerTypeMetadata: meta, + } + } else { + ltMetaMap[LayerType(num)] = layerTypeMetadata{ + inUse: true, + LayerTypeMetadata: meta, + } + } + DecodersByLayerName[meta.Name] = meta.Decoder + return LayerType(num) +} + +// Decode decodes the given data using the decoder registered with the layer +// type. +func (t LayerType) Decode(data []byte, c PacketBuilder) error { + var d Decoder + if 0 <= int(t) && int(t) < maxLayerType { + d = ltMeta[int(t)].Decoder + } else { + d = ltMetaMap[t].Decoder + } + if d != nil { + return d.Decode(data, c) + } + return fmt.Errorf("Layer type %v has no associated decoder", t) +} + +// String returns the string associated with this layer type. +func (t LayerType) String() (s string) { + if 0 <= int(t) && int(t) < maxLayerType { + s = ltMeta[int(t)].Name + } else { + s = ltMetaMap[t].Name + } + if s == "" { + s = strconv.Itoa(int(t)) + } + return +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/packet.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/packet.go new file mode 100644 index 0000000000..d2f41f535a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/packet.go @@ -0,0 +1,1035 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "bytes" + "context" + "encoding/hex" + "errors" + "fmt" + "io" + "net" + "os" + "reflect" + "runtime/debug" + "strings" + "sync" + "syscall" + "time" +) + +const maximumMTU = 1500 + +var ( + ErrNoLayersAdded = errors.New("NextDecoder called, but no layers added yet") + poolPackedPool = &sync.Pool{ + New: func() interface{} { + b := make([]byte, maximumMTU) + return &b + }, + } +) + +// CaptureInfo provides standardized information about a packet captured off +// the wire or read from a file. +type CaptureInfo struct { + // Timestamp is the time the packet was captured, if that is known. + Timestamp time.Time + // CaptureLength is the total number of bytes read off of the wire. + CaptureLength int + // Length is the size of the original packet. Should always be >= + // CaptureLength. + Length int + // InterfaceIndex + InterfaceIndex int + // The packet source can place ancillary data of various types here. + // For example, the afpacket source can report the VLAN of captured + // packets this way. + AncillaryData []interface{} +} + +// PacketMetadata contains metadata for a packet. +type PacketMetadata struct { + CaptureInfo + // Truncated is true if packet decoding logic detects that there are fewer + // bytes in the packet than are detailed in various headers (for example, if + // the number of bytes in the IPv4 contents/payload is less than IPv4.Length). + // This is also set automatically for packets captured off the wire if + // CaptureInfo.CaptureLength < CaptureInfo.Length. + Truncated bool +} + +// Packet is the primary object used by gopacket. Packets are created by a +// Decoder's Decode call. A packet is made up of a set of Data, which +// is broken into a number of Layers as it is decoded. +type Packet interface { + //// Functions for outputting the packet as a human-readable string: + //// ------------------------------------------------------------------ + // String returns a human-readable string representation of the packet. + // It uses LayerString on each layer to output the layer. + String() string + // Dump returns a verbose human-readable string representation of the packet, + // including a hex dump of all layers. It uses LayerDump on each layer to + // output the layer. + Dump() string + + //// Functions for accessing arbitrary packet layers: + //// ------------------------------------------------------------------ + // Layers returns all layers in this packet, computing them as necessary + Layers() []Layer + // Layer returns the first layer in this packet of the given type, or nil + Layer(LayerType) Layer + // LayerClass returns the first layer in this packet of the given class, + // or nil. + LayerClass(LayerClass) Layer + + //// Functions for accessing specific types of packet layers. These functions + //// return the first layer of each type found within the packet. + //// ------------------------------------------------------------------ + // LinkLayer returns the first link layer in the packet + LinkLayer() LinkLayer + // NetworkLayer returns the first network layer in the packet + NetworkLayer() NetworkLayer + // TransportLayer returns the first transport layer in the packet + TransportLayer() TransportLayer + // ApplicationLayer returns the first application layer in the packet + ApplicationLayer() ApplicationLayer + // ErrorLayer is particularly useful, since it returns nil if the packet + // was fully decoded successfully, and non-nil if an error was encountered + // in decoding and the packet was only partially decoded. Thus, its output + // can be used to determine if the entire packet was able to be decoded. + ErrorLayer() ErrorLayer + + //// Functions for accessing data specific to the packet: + //// ------------------------------------------------------------------ + // Data returns the set of bytes that make up this entire packet. + Data() []byte + // Metadata returns packet metadata associated with this packet. + Metadata() *PacketMetadata + + //// Functions for verifying specific aspects of the packet: + //// ------------------------------------------------------------------ + // VerifyChecksums verifies the checksums of all layers in this packet, + // that have one, and returns all found checksum mismatches. + VerifyChecksums() (error, []ChecksumMismatch) +} + +type PooledPacket interface { + Packet + Dispose() +} + +// packet contains all the information we need to fulfill the Packet interface, +// and its two "subclasses" (yes, no such thing in Go, bear with me), +// eagerPacket and lazyPacket, provide eager and lazy decoding logic around the +// various functions needed to access this information. +type packet struct { + // data contains the entire packet data for a packet + data []byte + // initialLayers is space for an initial set of layers already created inside + // the packet. + initialLayers [6]Layer + // layers contains each layer we've already decoded + layers []Layer + // last is the last layer added to the packet + last Layer + // metadata is the PacketMetadata for this packet + metadata PacketMetadata + + decodeOptions DecodeOptions + + // Pointers to the various important layers + link LinkLayer + network NetworkLayer + transport TransportLayer + application ApplicationLayer + failure ErrorLayer +} + +func (p *packet) SetTruncated() { + p.metadata.Truncated = true +} + +func (p *packet) SetLinkLayer(l LinkLayer) { + if p.link == nil { + p.link = l + } +} + +func (p *packet) SetNetworkLayer(l NetworkLayer) { + if p.network == nil { + p.network = l + } +} + +func (p *packet) SetTransportLayer(l TransportLayer) { + if p.transport == nil { + p.transport = l + } +} + +func (p *packet) SetApplicationLayer(l ApplicationLayer) { + if p.application == nil { + p.application = l + } +} + +func (p *packet) SetErrorLayer(l ErrorLayer) { + if p.failure == nil { + p.failure = l + } +} + +func (p *packet) AddLayer(l Layer) { + p.layers = append(p.layers, l) + p.last = l +} + +func (p *packet) DumpPacketData() { + fmt.Fprint(os.Stderr, p.packetDump()) + os.Stderr.Sync() +} + +func (p *packet) Metadata() *PacketMetadata { + return &p.metadata +} + +func (p *packet) Data() []byte { + return p.data +} + +func (p *packet) DecodeOptions() *DecodeOptions { + return &p.decodeOptions +} + +func (p *packet) VerifyChecksums() (error, []ChecksumMismatch) { + mismatches := make([]ChecksumMismatch, 0) + for i, l := range p.layers { + if lwc, ok := l.(LayerWithChecksum); ok { + // Verify checksum for that layer + err, res := lwc.VerifyChecksum() + if err != nil { + return fmt.Errorf("couldn't verify checksum for layer %d (%s): %w", + i+1, l.LayerType(), err), nil + } + + if !res.Valid { + mismatches = append(mismatches, ChecksumMismatch{ + ChecksumVerificationResult: res, + Layer: l, + LayerIndex: i, + }) + } + } + } + + return nil, mismatches +} + +func (p *packet) addFinalDecodeError(err error, stack []byte) { + fail := &DecodeFailure{err: err, stack: stack} + if p.last == nil { + fail.data = p.data + } else { + fail.data = p.last.LayerPayload() + } + p.AddLayer(fail) + p.SetErrorLayer(fail) +} + +func (p *packet) recoverDecodeError() { + if !p.decodeOptions.SkipDecodeRecovery { + if r := recover(); r != nil { + p.addFinalDecodeError(fmt.Errorf("%v", r), debug.Stack()) + } + } +} + +type pooledPacket struct { + Packet + origData *[]byte +} + +func (p pooledPacket) Dispose() { + poolPackedPool.Put(p.origData) +} + +// LayerString outputs an individual layer as a string. The layer is output +// in a single line, with no trailing newline. This function is specifically +// designed to do the right thing for most layers... it follows the following +// rules: +// - If the Layer has a String function, just output that. +// - Otherwise, output all exported fields in the layer, recursing into +// exported slices and structs. +// +// NOTE: This is NOT THE SAME AS fmt's "%#v". %#v will output both exported +// and unexported fields... many times packet layers contain unexported stuff +// that would just mess up the output of the layer, see for example the +// Payload layer and it's internal 'data' field, which contains a large byte +// array that would really mess up formatting. +func LayerString(l Layer) string { + return fmt.Sprintf("%v\t%s", l.LayerType(), layerString(reflect.ValueOf(l), false, false)) +} + +// Dumper dumps verbose information on a value. If a layer type implements +// Dumper, then its LayerDump() string will include the results in its output. +type Dumper interface { + Dump() string +} + +// LayerDump outputs a very verbose string representation of a layer. Its +// output is a concatenation of LayerString(l) and hex.Dump(l.LayerContents()). +// It contains newlines and ends with a newline. +func LayerDump(l Layer) string { + var b bytes.Buffer + b.WriteString(LayerString(l)) + b.WriteByte('\n') + if d, ok := l.(Dumper); ok { + dump := d.Dump() + if dump != "" { + b.WriteString(dump) + if dump[len(dump)-1] != '\n' { + b.WriteByte('\n') + } + } + } + b.WriteString(hex.Dump(l.LayerContents())) + return b.String() +} + +// layerString outputs, recursively, a layer in a "smart" way. See docs for +// LayerString for more details. +// +// Params: +// +// i - value to write out +// anonymous: if we're currently recursing an anonymous member of a struct +// writeSpace: if we've already written a value in a struct, and need to +// write a space before writing more. This happens when we write various +// anonymous values, and need to keep writing more. +func layerString(v reflect.Value, anonymous bool, writeSpace bool) string { + // Let String() functions take precedence. + if v.CanInterface() { + if v.CanAddr() && v.Addr().CanInterface() { + if s, ok := v.Addr().Interface().(fmt.Stringer); ok { + return s.String() + } + } else { + if s, ok := v.Interface().(fmt.Stringer); ok { + return s.String() + } + } + } + // Reflect, and spit out all the exported fields as key=value. + switch v.Type().Kind() { + case reflect.Interface, reflect.Ptr: + if v.IsNil() { + return "nil" + } + r := v.Elem() + return layerString(r, anonymous, writeSpace) + case reflect.Struct: + var b bytes.Buffer + typ := v.Type() + if !anonymous { + b.WriteByte('{') + } + for i := 0; i < v.NumField(); i++ { + // Check if this is upper-case. + ftype := typ.Field(i) + f := v.Field(i) + if ftype.Anonymous { + anonStr := layerString(f, true, writeSpace) + writeSpace = writeSpace || anonStr != "" + b.WriteString(anonStr) + } else if ftype.PkgPath == "" { // exported + if writeSpace { + b.WriteByte(' ') + } + writeSpace = true + fmt.Fprintf(&b, "%s=%s", typ.Field(i).Name, layerString(f, false, writeSpace)) + } + } + if !anonymous { + b.WriteByte('}') + } + return b.String() + case reflect.Slice: + var b bytes.Buffer + b.WriteByte('[') + if v.Len() > 4 { + fmt.Fprintf(&b, "..%d..", v.Len()) + } else { + for j := 0; j < v.Len(); j++ { + if j != 0 { + b.WriteString(", ") + } + b.WriteString(layerString(v.Index(j), false, false)) + } + } + b.WriteByte(']') + return b.String() + } + return fmt.Sprintf("%v", v.Interface()) +} + +const ( + longBytesLength = 128 +) + +// LongBytesGoString returns a string representation of the byte slice shortened +// using the format '{ ... ( bytes)}' if it +// exceeds a predetermined length. Can be used to avoid filling the display with +// very long byte strings. +func LongBytesGoString(buf []byte) string { + if len(buf) < longBytesLength { + return fmt.Sprintf("%#v", buf) + } + s := fmt.Sprintf("%#v", buf[:longBytesLength-1]) + s = strings.TrimSuffix(s, "}") + return fmt.Sprintf("%s ... (%d bytes)}", s, len(buf)) +} + +func baseLayerString(value reflect.Value) string { + t := value.Type() + content := value.Field(0) + c := make([]byte, content.Len()) + for i := range c { + c[i] = byte(content.Index(i).Uint()) + } + payload := value.Field(1) + p := make([]byte, payload.Len()) + for i := range p { + p[i] = byte(payload.Index(i).Uint()) + } + return fmt.Sprintf("%s{Contents:%s, Payload:%s}", t.String(), + LongBytesGoString(c), + LongBytesGoString(p)) +} + +func layerGoString(i interface{}, b *bytes.Buffer) { + if s, ok := i.(fmt.GoStringer); ok { + b.WriteString(s.GoString()) + return + } + + var v reflect.Value + var ok bool + if v, ok = i.(reflect.Value); !ok { + v = reflect.ValueOf(i) + } + switch v.Kind() { + case reflect.Ptr, reflect.Interface: + if v.Kind() == reflect.Ptr { + b.WriteByte('&') + } + layerGoString(v.Elem().Interface(), b) + case reflect.Struct: + t := v.Type() + b.WriteString(t.String()) + b.WriteByte('{') + for i := 0; i < v.NumField(); i++ { + if i > 0 { + b.WriteString(", ") + } + if t.Field(i).Name == "BaseLayer" { + fmt.Fprintf(b, "BaseLayer:%s", baseLayerString(v.Field(i))) + } else if v.Field(i).Kind() == reflect.Struct { + fmt.Fprintf(b, "%s:", t.Field(i).Name) + layerGoString(v.Field(i), b) + } else if v.Field(i).Kind() == reflect.Ptr { + b.WriteByte('&') + layerGoString(v.Field(i), b) + } else { + fmt.Fprintf(b, "%s:%#v", t.Field(i).Name, v.Field(i)) + } + } + b.WriteByte('}') + default: + fmt.Fprintf(b, "%#v", i) + } +} + +// LayerGoString returns a representation of the layer in Go syntax, +// taking care to shorten "very long" BaseLayer byte slices +func LayerGoString(l Layer) string { + b := new(bytes.Buffer) + layerGoString(l, b) + return b.String() +} + +func (p *packet) packetString() string { + var b bytes.Buffer + fmt.Fprintf(&b, "PACKET: %d bytes", len(p.Data())) + if p.metadata.Truncated { + b.WriteString(", truncated") + } + if p.metadata.Length > 0 { + fmt.Fprintf(&b, ", wire length %d cap length %d", p.metadata.Length, p.metadata.CaptureLength) + } + if !p.metadata.Timestamp.IsZero() { + fmt.Fprintf(&b, " @ %v", p.metadata.Timestamp) + } + b.WriteByte('\n') + for i, l := range p.layers { + fmt.Fprintf(&b, "- Layer %d (%02d bytes) = %s\n", i+1, len(l.LayerContents()), LayerString(l)) + } + return b.String() +} + +func (p *packet) packetDump() string { + var b bytes.Buffer + fmt.Fprintf(&b, "-- FULL PACKET DATA (%d bytes) ------------------------------------\n%s", len(p.data), hex.Dump(p.data)) + for i, l := range p.layers { + fmt.Fprintf(&b, "--- Layer %d ---\n%s", i+1, LayerDump(l)) + } + return b.String() +} + +// eagerPacket is a packet implementation that does eager decoding. Upon +// initial construction, it decodes all the layers it can from packet data. +// eagerPacket implements Packet and PacketBuilder. +type eagerPacket struct { + packet +} + +var errNilDecoder = errors.New("NextDecoder passed nil decoder, probably an unsupported decode type") + +func (p *eagerPacket) NextDecoder(next Decoder) error { + if next == nil { + return errNilDecoder + } + if p.last == nil { + return ErrNoLayersAdded + } + d := p.last.LayerPayload() + if len(d) == 0 { + return nil + } + // Since we're eager, immediately call the next decoder. + return next.Decode(d, p) +} +func (p *eagerPacket) initialDecode(dec Decoder) { + defer p.recoverDecodeError() + err := dec.Decode(p.data, p) + if err != nil { + p.addFinalDecodeError(err, nil) + } +} +func (p *eagerPacket) LinkLayer() LinkLayer { + return p.link +} +func (p *eagerPacket) NetworkLayer() NetworkLayer { + return p.network +} +func (p *eagerPacket) TransportLayer() TransportLayer { + return p.transport +} +func (p *eagerPacket) ApplicationLayer() ApplicationLayer { + return p.application +} +func (p *eagerPacket) ErrorLayer() ErrorLayer { + return p.failure +} +func (p *eagerPacket) Layers() []Layer { + return p.layers +} +func (p *eagerPacket) Layer(t LayerType) Layer { + for _, l := range p.layers { + if l.LayerType() == t { + return l + } + } + return nil +} +func (p *eagerPacket) LayerClass(lc LayerClass) Layer { + for _, l := range p.layers { + if lc.Contains(l.LayerType()) { + return l + } + } + return nil +} +func (p *eagerPacket) String() string { return p.packetString() } +func (p *eagerPacket) Dump() string { return p.packetDump() } + +// lazyPacket does lazy decoding on its packet data. On construction it does +// no initial decoding. For each function call, it decodes only as many layers +// as are necessary to compute the return value for that function. +// lazyPacket implements Packet and PacketBuilder. +type lazyPacket struct { + packet + next Decoder +} + +func (p *lazyPacket) NextDecoder(next Decoder) error { + if next == nil { + return errNilDecoder + } + p.next = next + return nil +} +func (p *lazyPacket) decodeNextLayer() { + if p.next == nil { + return + } + d := p.data + if p.last != nil { + d = p.last.LayerPayload() + } + next := p.next + p.next = nil + // We've just set p.next to nil, so if we see we have no data, this should be + // the final call we get to decodeNextLayer if we return here. + if len(d) == 0 { + return + } + defer p.recoverDecodeError() + err := next.Decode(d, p) + if err != nil { + p.addFinalDecodeError(err, nil) + } +} +func (p *lazyPacket) LinkLayer() LinkLayer { + for p.link == nil && p.next != nil { + p.decodeNextLayer() + } + return p.link +} +func (p *lazyPacket) NetworkLayer() NetworkLayer { + for p.network == nil && p.next != nil { + p.decodeNextLayer() + } + return p.network +} +func (p *lazyPacket) TransportLayer() TransportLayer { + for p.transport == nil && p.next != nil { + p.decodeNextLayer() + } + return p.transport +} +func (p *lazyPacket) ApplicationLayer() ApplicationLayer { + for p.application == nil && p.next != nil { + p.decodeNextLayer() + } + return p.application +} +func (p *lazyPacket) ErrorLayer() ErrorLayer { + for p.failure == nil && p.next != nil { + p.decodeNextLayer() + } + return p.failure +} +func (p *lazyPacket) Layers() []Layer { + for p.next != nil { + p.decodeNextLayer() + } + return p.layers +} +func (p *lazyPacket) Layer(t LayerType) Layer { + for _, l := range p.layers { + if l.LayerType() == t { + return l + } + } + numLayers := len(p.layers) + for p.next != nil { + p.decodeNextLayer() + for _, l := range p.layers[numLayers:] { + if l.LayerType() == t { + return l + } + } + numLayers = len(p.layers) + } + return nil +} +func (p *lazyPacket) LayerClass(lc LayerClass) Layer { + for _, l := range p.layers { + if lc.Contains(l.LayerType()) { + return l + } + } + numLayers := len(p.layers) + for p.next != nil { + p.decodeNextLayer() + for _, l := range p.layers[numLayers:] { + if lc.Contains(l.LayerType()) { + return l + } + } + numLayers = len(p.layers) + } + return nil +} +func (p *lazyPacket) String() string { p.Layers(); return p.packetString() } +func (p *lazyPacket) Dump() string { p.Layers(); return p.packetDump() } + +// DecodeOptions tells gopacket how to decode a packet. +type DecodeOptions struct { + // Lazy decoding decodes the minimum number of layers needed to return data + // for a packet at each function call. Be careful using this with concurrent + // packet processors, as each call to packet.* could mutate the packet, and + // two concurrent function calls could interact poorly. + Lazy bool + // NoCopy decoding doesn't copy its input buffer into storage that's owned by + // the packet. If you can guarantee that the bytes underlying the slice + // passed into NewPacket aren't going to be modified, this can be faster. If + // there's any chance that those bytes WILL be changed, this will invalidate + // your packets. + NoCopy bool + // Pool decoding only applies if NoCopy is false. + // Instead of always allocating new memory it takes the memory from a pool. + // NewPacket then will return a PooledPacket instead of a Packet. + // As soon as you're done with the PooledPacket you should call PooledPacket.Dispose() to return it to the pool. + Pool bool + // SkipDecodeRecovery skips over panic recovery during packet decoding. + // Normally, when packets decode, if a panic occurs, that panic is captured + // by a recover(), and a DecodeFailure layer is added to the packet detailing + // the issue. If this flag is set, panics are instead allowed to continue up + // the stack. + SkipDecodeRecovery bool + // DecodeStreamsAsDatagrams enables routing of application-level layers in the TCP + // decoder. If true, we should try to decode layers after TCP in single packets. + // This is disabled by default because the reassembly package drives the decoding + // of TCP payload data after reassembly. + DecodeStreamsAsDatagrams bool +} + +// Default decoding provides the safest (but slowest) method for decoding +// packets. It eagerly processes all layers (so it's concurrency-safe) and it +// copies its input buffer upon creation of the packet (so the packet remains +// valid if the underlying slice is modified. Both of these take time, +// though, so beware. If you can guarantee that the packet will only be used +// by one goroutine at a time, set Lazy decoding. If you can guarantee that +// the underlying slice won't change, set NoCopy decoding. +var Default = DecodeOptions{} + +// Lazy is a DecodeOptions with just Lazy set. +var Lazy = DecodeOptions{Lazy: true} + +// NoCopy is a DecodeOptions with just NoCopy set. +var NoCopy = DecodeOptions{NoCopy: true} + +// DecodeStreamsAsDatagrams is a DecodeOptions with just DecodeStreamsAsDatagrams set. +var DecodeStreamsAsDatagrams = DecodeOptions{DecodeStreamsAsDatagrams: true} + +// NewPacket creates a new Packet object from a set of bytes. The +// firstLayerDecoder tells it how to interpret the first layer from the bytes, +// future layers will be generated from that first layer automatically. +func NewPacket(data []byte, firstLayerDecoder Decoder, options DecodeOptions) (p Packet) { + if !options.NoCopy { + var ( + poolMemory *[]byte + dataCopy []byte + ) + if options.Pool && len(data) <= maximumMTU { + poolMemory = poolPackedPool.Get().(*[]byte) + dataCopy = (*poolMemory)[:len(data)] + copy(dataCopy, data) + data = dataCopy + defer func() { + p = &pooledPacket{Packet: p, origData: poolMemory} + }() + } else { + dataCopy = make([]byte, len(data)) + copy(dataCopy, data) + data = dataCopy + } + } + if options.Lazy { + lp := &lazyPacket{ + packet: packet{data: data, decodeOptions: options}, + next: firstLayerDecoder, + } + lp.layers = lp.initialLayers[:0] + // Crazy craziness: + // If the following return statemet is REMOVED, and Lazy is FALSE, then + // eager packet processing becomes 17% FASTER. No, there is no logical + // explanation for this. However, it's such a hacky micro-optimization that + // we really can't rely on it. It appears to have to do with the size the + // compiler guesses for this function's stack space, since one symptom is + // that with the return statement in place, we more than double calls to + // runtime.morestack/runtime.lessstack. We'll hope the compiler gets better + // over time and we get this optimization for free. Until then, we'll have + // to live with slower packet processing. + return lp + } + ep := &eagerPacket{ + packet: packet{data: data, decodeOptions: options}, + } + ep.layers = ep.initialLayers[:0] + ep.initialDecode(firstLayerDecoder) + return ep +} + +// PacketDataSource is an interface for some source of packet data. Users may +// create their own implementations, or use the existing implementations in +// gopacket/pcap (libpcap, allows reading from live interfaces or from +// pcap files) or gopacket/pfring (PF_RING, allows reading from live +// interfaces). +type PacketDataSource interface { + // ReadPacketData returns the next packet available from this data source. + // It returns: + // data: The bytes of an individual packet. + // ci: Metadata about the capture + // err: An error encountered while reading packet data. If err != nil, + // then data/ci will be ignored. + ReadPacketData() (data []byte, ci CaptureInfo, err error) +} + +// ConcatFinitePacketDataSources returns a PacketDataSource that wraps a set +// of internal PacketDataSources, each of which will stop with io.EOF after +// reading a finite number of packets. The returned PacketDataSource will +// return all packets from the first finite source, followed by all packets from +// the second, etc. Once all finite sources have returned io.EOF, the returned +// source will as well. +func ConcatFinitePacketDataSources(pds ...PacketDataSource) PacketDataSource { + c := concat(pds) + return &c +} + +type concat []PacketDataSource + +func (c *concat) ReadPacketData() (data []byte, ci CaptureInfo, err error) { + for len(*c) > 0 { + data, ci, err = (*c)[0].ReadPacketData() + if errors.Is(err, io.EOF) { + *c = (*c)[1:] + continue + } + return + } + return nil, CaptureInfo{}, io.EOF +} + +// ZeroCopyPacketDataSource is an interface to pull packet data from sources +// that allow data to be returned without copying to a user-controlled buffer. +// It's very similar to PacketDataSource, except that the caller must be more +// careful in how the returned buffer is handled. +type ZeroCopyPacketDataSource interface { + // ZeroCopyReadPacketData returns the next packet available from this data source. + // It returns: + // data: The bytes of an individual packet. Unlike with + // PacketDataSource's ReadPacketData, the slice returned here points + // to a buffer owned by the data source. In particular, the bytes in + // this buffer may be changed by future calls to + // ZeroCopyReadPacketData. Do not use the returned buffer after + // subsequent ZeroCopyReadPacketData calls. + // ci: Metadata about the capture + // err: An error encountered while reading packet data. If err != nil, + // then data/ci will be ignored. + ZeroCopyReadPacketData() (data []byte, ci CaptureInfo, err error) +} + +type PacketSourceOption interface { + apply(ps *PacketSource) +} + +type packetSourceOptionFunc func(ps *PacketSource) + +func (f packetSourceOptionFunc) apply(ps *PacketSource) { + f(ps) +} + +func WithLazy(lazy bool) packetSourceOptionFunc { + return func(ps *PacketSource) { + ps.Lazy = lazy + } +} + +func WithNoCopy(noCopy bool) packetSourceOptionFunc { + return func(ps *PacketSource) { + ps.NoCopy = noCopy + } +} + +func WithPool(pool bool) packetSourceOptionFunc { + return func(ps *PacketSource) { + ps.Pool = pool + } +} + +func WithSkipDecodeRecovery(skipDecodeRecovery bool) packetSourceOptionFunc { + return func(ps *PacketSource) { + ps.SkipDecodeRecovery = skipDecodeRecovery + } +} + +func WithDecodeStreamsAsDatagrams(decodeStreamsAsDatagrams bool) packetSourceOptionFunc { + return func(ps *PacketSource) { + ps.DecodeStreamsAsDatagrams = decodeStreamsAsDatagrams + } +} + +// PacketSource reads in packets from a PacketDataSource, decodes them, and +// returns them. +// +// There are currently two different methods for reading packets in through +// a PacketSource: +// +// # Reading With Packets Function +// +// This method is the most convenient and easiest to code, but lacks +// flexibility. Packets returns a 'chan Packet', then asynchronously writes +// packets into that channel. Packets uses a blocking channel, and closes +// it if an io.EOF is returned by the underlying PacketDataSource. All other +// PacketDataSource errors are ignored and discarded. +// +// for packet := range packetSource.Packets() { +// ... +// } +// +// # Reading With NextPacket Function +// +// This method is the most flexible, and exposes errors that may be +// encountered by the underlying PacketDataSource. It's also the fastest +// in a tight loop, since it doesn't have the overhead of a channel +// read/write. However, it requires the user to handle errors, most +// importantly the io.EOF error in cases where packets are being read from +// a file. +// +// for { +// packet, err := packetSource.NextPacket() +// if err == io.EOF { +// break +// } else if err != nil { +// log.Println("Error:", err) +// continue +// } +// handlePacket(packet) // Do something with each packet. +// } +type PacketSource struct { + zeroCopy bool + source func() (data []byte, ci CaptureInfo, err error) + decoder Decoder + // DecodeOptions is the set of options to use for decoding each piece + // of packet data. This can/should be changed by the user to reflect the + // way packets should be decoded. + DecodeOptions + c chan Packet +} + +// NewZeroCopyPacketSource creates a zero copy packet data source. +func NewZeroCopyPacketSource(source ZeroCopyPacketDataSource, decoder Decoder, opts ...PacketSourceOption) *PacketSource { + ps := &PacketSource{ + source: source.ZeroCopyReadPacketData, + decoder: decoder, + } + + for idx := range opts { + opts[idx].apply(ps) + } + + return ps +} + +// NewPacketSource creates a packet data source. +func NewPacketSource(source PacketDataSource, decoder Decoder, opts ...PacketSourceOption) *PacketSource { + ps := &PacketSource{ + source: source.ReadPacketData, + decoder: decoder, + } + + for idx := range opts { + opts[idx].apply(ps) + } + + return ps +} + +// NextPacket returns the next decoded packet from the PacketSource. On error, +// it returns a nil packet and a non-nil error. +func (p *PacketSource) NextPacket() (Packet, error) { + data, ci, err := p.source() + if err != nil { + return nil, err + } + packet := NewPacket(data, p.decoder, p.DecodeOptions) + m := packet.Metadata() + m.CaptureInfo = ci + m.Truncated = m.Truncated || ci.CaptureLength < ci.Length + return packet, nil +} + +// packetsToChannel reads in all packets from the packet source and sends them +// to the given channel. This routine terminates when a non-temporary error +// is returned by NextPacket(). +func (p *PacketSource) packetsToChannel(ctx context.Context) { + defer close(p.c) + for ctx.Err() == nil { + packet, err := p.NextPacket() + if err == nil { + select { + case p.c <- packet: + continue + case <-ctx.Done(): + return + } + } + + // if timeout error sleep briefly and retry + var netErr net.Error + if ok := errors.As(err, &netErr); ok && netErr.Timeout() { + time.Sleep(time.Millisecond * time.Duration(5)) + continue + } + + // Immediately break for known unrecoverable errors + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) || + errors.Is(err, io.ErrNoProgress) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, io.ErrShortBuffer) || + errors.Is(err, syscall.EBADF) || + strings.Contains(err.Error(), "use of closed file") { + break + } + + // Sleep briefly and try again + time.Sleep(time.Millisecond * time.Duration(5)) + } +} + +// Packets returns a channel of packets, allowing easy iterating over +// packets. Packets will be asynchronously read in from the underlying +// PacketDataSource and written to the returned channel. If the underlying +// PacketDataSource returns an io.EOF error, the channel will be closed. +// If any other error is encountered, it is ignored. +// +// for packet := range packetSource.Packets() { +// handlePacket(packet) // Do something with each packet +// } +// +// If called more than once, returns the same channel. +func (p *PacketSource) Packets() chan Packet { + return p.PacketsCtx(context.Background()) +} + +// PacketsCtx returns a channel of packets, allowing easy iterating over +// packets. Packets will be asynchronously read in from the underlying +// PacketDataSource and written to the returned channel. If the underlying +// PacketDataSource returns an io.EOF error, the channel will be closed. +// If any other error is encountered, it is ignored. +// The background Go routine will be canceled as soon as the given context +// returns an error either because it got canceled or it has reached its deadline. +// +// for packet := range packetSource.PacketsCtx(context.Background()) { +// handlePacket(packet) // Do something with each packet. +// } +// +// If called more than once, returns the same channel. +func (p *PacketSource) PacketsCtx(ctx context.Context) chan Packet { + if p.DecodeOptions.NoCopy && p.zeroCopy { + panic("PacketSource uses a zero copy datasource and NoCopy decoder option activated - Packets() uses a buffered channel hence packets are most likely overwritten") + } + + const defaultPacketChannelSize = 1000 + if p.c == nil { + p.c = make(chan Packet, defaultPacketChannelSize) + go p.packetsToChannel(ctx) + } + return p.c +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/parser.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/parser.go new file mode 100644 index 0000000000..8bc6a68d4a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/parser.go @@ -0,0 +1,351 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// A container for single LayerType->DecodingLayer mapping. +type decodingLayerElem struct { + typ LayerType + dec DecodingLayer +} + +// DecodingLayer is an interface for packet layers that can decode themselves. +// +// The important part of DecodingLayer is that they decode themselves in-place. +// Calling DecodeFromBytes on a DecodingLayer totally resets the entire layer to +// the new state defined by the data passed in. A returned error leaves the +// DecodingLayer in an unknown intermediate state, thus its fields should not be +// trusted. +// +// Because the DecodingLayer is resetting its own fields, a call to +// DecodeFromBytes should normally not require any memory allocation. +type DecodingLayer interface { + // DecodeFromBytes resets the internal state of this layer to the state + // defined by the passed-in bytes. Slices in the DecodingLayer may + // reference the passed-in data, so care should be taken to copy it + // first should later modification of data be required before the + // DecodingLayer is discarded. + DecodeFromBytes(data []byte, df DecodeFeedback) error + // CanDecode returns the set of LayerTypes this DecodingLayer can + // decode. For Layers that are also DecodingLayers, this will most + // often be that Layer's LayerType(). + CanDecode() LayerClass + // NextLayerType returns the LayerType which should be used to decode + // the LayerPayload. + NextLayerType() LayerType + // LayerPayload is the set of bytes remaining to decode after a call to + // DecodeFromBytes. + LayerPayload() []byte +} + +// DecodingLayerFunc decodes given packet and stores decoded LayerType +// values into specified slice. Returns either first encountered +// unsupported LayerType value or decoding error. In case of success, +// returns (LayerTypeZero, nil). +type DecodingLayerFunc func([]byte, *[]LayerType) (LayerType, error) + +// DecodingLayerContainer stores all DecodingLayer-s and serves as a +// searching tool for DecodingLayerParser. +type DecodingLayerContainer interface { + // Put adds new DecodingLayer to container. The new instance of + // the same DecodingLayerContainer is returned so it may be + // implemented as a value receiver. + Put(DecodingLayer) DecodingLayerContainer + // Decoder returns DecodingLayer to decode given LayerType and + // true if it was found. If no decoder found, return false. + Decoder(LayerType) (DecodingLayer, bool) + // LayersDecoder returns DecodingLayerFunc which decodes given + // packet, starting with specified LayerType and DecodeFeedback. + LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc +} + +// DecodingLayerSparse is a sparse array-based implementation of +// DecodingLayerContainer. Each DecodingLayer is addressed in an +// allocated slice by LayerType value itself. Though this is the +// fastest container it may be memory-consuming if used with big +// LayerType values. +type DecodingLayerSparse []DecodingLayer + +// Put implements DecodingLayerContainer interface. +func (dl DecodingLayerSparse) Put(d DecodingLayer) DecodingLayerContainer { + maxLayerType := LayerType(len(dl) - 1) + for _, typ := range d.CanDecode().LayerTypes() { + if typ > maxLayerType { + maxLayerType = typ + } + } + + if extra := maxLayerType - LayerType(len(dl)) + 1; extra > 0 { + dl = append(dl, make([]DecodingLayer, extra)...) + } + + for _, typ := range d.CanDecode().LayerTypes() { + dl[typ] = d + } + return dl +} + +// LayersDecoder implements DecodingLayerContainer interface. +func (dl DecodingLayerSparse) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { + return LayersDecoder(dl, first, df) +} + +// Decoder implements DecodingLayerContainer interface. +func (dl DecodingLayerSparse) Decoder(typ LayerType) (DecodingLayer, bool) { + if int64(typ) < int64(len(dl)) { + decoder := dl[typ] + return decoder, decoder != nil + } + return nil, false +} + +// DecodingLayerArray is an array-based implementation of +// DecodingLayerContainer. Each DecodingLayer is searched linearly in +// an allocated slice in one-by-one fashion. +type DecodingLayerArray []decodingLayerElem + +// Put implements DecodingLayerContainer interface. +func (dl DecodingLayerArray) Put(d DecodingLayer) DecodingLayerContainer { +TYPES: + for _, typ := range d.CanDecode().LayerTypes() { + for i := range dl { + if dl[i].typ == typ { + dl[i].dec = d + continue TYPES + } + } + dl = append(dl, decodingLayerElem{typ, d}) + } + return dl +} + +// Decoder implements DecodingLayerContainer interface. +func (dl DecodingLayerArray) Decoder(typ LayerType) (DecodingLayer, bool) { + for i := range dl { + if dl[i].typ == typ { + return dl[i].dec, true + } + } + return nil, false +} + +// LayersDecoder implements DecodingLayerContainer interface. +func (dl DecodingLayerArray) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { + return LayersDecoder(dl, first, df) +} + +// DecodingLayerMap is an map-based implementation of +// DecodingLayerContainer. Each DecodingLayer is searched in a map +// hashed by LayerType value. +type DecodingLayerMap map[LayerType]DecodingLayer + +// Put implements DecodingLayerContainer interface. +func (dl DecodingLayerMap) Put(d DecodingLayer) DecodingLayerContainer { + for _, typ := range d.CanDecode().LayerTypes() { + if dl == nil { + dl = make(map[LayerType]DecodingLayer) + } + dl[typ] = d + } + return dl +} + +// Decoder implements DecodingLayerContainer interface. +func (dl DecodingLayerMap) Decoder(typ LayerType) (DecodingLayer, bool) { + d, ok := dl[typ] + return d, ok +} + +// LayersDecoder implements DecodingLayerContainer interface. +func (dl DecodingLayerMap) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { + return LayersDecoder(dl, first, df) +} + +// Static code check. +var ( + _ = []DecodingLayerContainer{ + DecodingLayerSparse(nil), + DecodingLayerMap(nil), + DecodingLayerArray(nil), + } +) + +// DecodingLayerParser parses a given set of layer types. See DecodeLayers for +// more information on how DecodingLayerParser should be used. +type DecodingLayerParser struct { + // DecodingLayerParserOptions is the set of options available to the + // user to define the parser's behavior. + DecodingLayerParserOptions + dlc DecodingLayerContainer + first LayerType + df DecodeFeedback + + decodeFunc DecodingLayerFunc + + // Truncated is set when a decode layer detects that the packet has been + // truncated. + Truncated bool +} + +// AddDecodingLayer adds a decoding layer to the parser. This adds support for +// the decoding layer's CanDecode layers to the parser... should they be +// encountered, they'll be parsed. +func (l *DecodingLayerParser) AddDecodingLayer(d DecodingLayer) { + l.SetDecodingLayerContainer(l.dlc.Put(d)) +} + +// SetTruncated is used by DecodingLayers to set the Truncated boolean in the +// DecodingLayerParser. Users should simply read Truncated after calling +// DecodeLayers. +func (l *DecodingLayerParser) SetTruncated() { + l.Truncated = true +} + +// NewDecodingLayerParser creates a new DecodingLayerParser and adds in all +// of the given DecodingLayers with AddDecodingLayer. +// +// Each call to DecodeLayers will attempt to decode the given bytes first by +// treating them as a 'first'-type layer, then by using NextLayerType on +// subsequently decoded layers to find the next relevant decoder. Should a +// deoder not be available for the layer type returned by NextLayerType, +// decoding will stop. +// +// NewDecodingLayerParser uses DecodingLayerMap container by +// default. +func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser { + dlp := &DecodingLayerParser{first: first} + dlp.df = dlp // Cast this once to the interface + // default container + dlc := DecodingLayerContainer(DecodingLayerMap(make(map[LayerType]DecodingLayer))) + for _, d := range decoders { + dlc = dlc.Put(d) + } + + dlp.SetDecodingLayerContainer(dlc) + return dlp +} + +// SetDecodingLayerContainer specifies container with decoders. This +// call replaces all decoders already registered in given instance of +// DecodingLayerParser. +func (l *DecodingLayerParser) SetDecodingLayerContainer(dlc DecodingLayerContainer) { + l.dlc = dlc + l.decodeFunc = l.dlc.LayersDecoder(l.first, l.df) +} + +// DecodeLayers decodes as many layers as possible from the given data. It +// initially treats the data as layer type 'typ', then uses NextLayerType on +// each subsequent decoded layer until it gets to a layer type it doesn't know +// how to parse. +// +// For each layer successfully decoded, DecodeLayers appends the layer type to +// the decoded slice. DecodeLayers truncates the 'decoded' slice initially, so +// there's no need to empty it yourself. +// +// This decoding method is about an order of magnitude faster than packet +// decoding, because it only decodes known layers that have already been +// allocated. This means it doesn't need to allocate each layer it returns... +// instead it overwrites the layers that already exist. +// +// Example usage: +// +// func main() { +// var eth layers.Ethernet +// var ip4 layers.IPv4 +// var ip6 layers.IPv6 +// var tcp layers.TCP +// var udp layers.UDP +// var payload gopacket.Payload +// parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp, &udp, &payload) +// var source gopacket.PacketDataSource = getMyDataSource() +// decodedLayers := make([]gopacket.LayerType, 0, 10) +// for { +// data, _, err := source.ReadPacketData() +// if err != nil { +// fmt.Println("Error reading packet data: ", err) +// continue +// } +// fmt.Println("Decoding packet") +// err = parser.DecodeLayers(data, &decodedLayers) +// for _, typ := range decodedLayers { +// fmt.Println(" Successfully decoded layer type", typ) +// switch typ { +// case layers.LayerTypeEthernet: +// fmt.Println(" Eth ", eth.SrcMAC, eth.DstMAC) +// case layers.LayerTypeIPv4: +// fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP) +// case layers.LayerTypeIPv6: +// fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP) +// case layers.LayerTypeTCP: +// fmt.Println(" TCP ", tcp.SrcPort, tcp.DstPort) +// case layers.LayerTypeUDP: +// fmt.Println(" UDP ", udp.SrcPort, udp.DstPort) +// } +// } +// if decodedLayers.Truncated { +// fmt.Println(" Packet has been truncated") +// } +// if err != nil { +// fmt.Println(" Error encountered:", err) +// } +// } +// } +// +// If DecodeLayers is unable to decode the next layer type, it will return the +// error UnsupportedLayerType. +func (l *DecodingLayerParser) DecodeLayers(data []byte, decoded *[]LayerType) (err error) { + l.Truncated = false + if !l.IgnorePanic { + defer panicToError(&err) + } + typ, err := l.decodeFunc(data, decoded) + if typ != LayerTypeZero { + // no decoder + if l.IgnoreUnsupported { + return nil + } + return UnsupportedLayerType(typ) + } + return err +} + +// UnsupportedLayerType is returned by DecodingLayerParser if DecodeLayers +// encounters a layer type that the DecodingLayerParser has no decoder for. +type UnsupportedLayerType LayerType + +// Error implements the error interface, returning a string to say that the +// given layer type is unsupported. +func (e UnsupportedLayerType) Error() string { + return fmt.Sprintf("No decoder for layer type %v", LayerType(e)) +} + +func panicToError(e *error) { + if r := recover(); r != nil { + *e = fmt.Errorf("panic: %v", r) + } +} + +// DecodingLayerParserOptions provides options to affect the behavior of a given +// DecodingLayerParser. +type DecodingLayerParserOptions struct { + // IgnorePanic determines whether a DecodingLayerParser should stop + // panics on its own (by returning them as an error from DecodeLayers) + // or should allow them to raise up the stack. Handling errors does add + // latency to the process of decoding layers, but is much safer for + // callers. IgnorePanic defaults to false, thus if the caller does + // nothing decode panics will be returned as errors. + IgnorePanic bool + // IgnoreUnsupported will stop parsing and return a nil error when it + // encounters a layer it doesn't have a parser for, instead of returning an + // UnsupportedLayerType error. If this is true, it's up to the caller to make + // sure that all expected layers have been parsed (by checking the decoded + // slice). + IgnoreUnsupported bool +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/defs_windows.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/defs_windows.go new file mode 100644 index 0000000000..774e907e8e --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/defs_windows.go @@ -0,0 +1,74 @@ +// 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/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/doc.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/doc.go new file mode 100644 index 0000000000..7cdc7a83a3 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/doc.go @@ -0,0 +1,114 @@ +// 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/gopacket/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/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap.go new file mode 100644 index 0000000000..f36179b891 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap.go @@ -0,0 +1,879 @@ +// 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/gopacket/gopacket" + "github.com/gopacket/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 +} + +// bpfFilter keeps C.struct_bpf_program separate from BPF.orig which might be a pointer to go memory. +// This is a workaround for https://github.com/golang/go/issues/32970 which will be fixed in go1.14. +// (type conversion is in pcap_unix.go pcapOfflineFilter) +type bpfFilter struct { + bpf pcapBpfProgram // takes a finalizer, not overriden by outsiders +} + +// BPF is a compiled filter program, useful for offline packet matching. +type BPF struct { + orig string + bpf *bpfFilter + 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) + aeError = activateError(pcapError) +) + +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()) + case aeError: + return fmt.Sprintf("Error: %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, bpf: new(bpfFilter)} + + var err error + bpf.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: new(bpfFilter)} + + bpf.bpf.bpf, err = bpfInstructionFilter(bpfInstructions) + if err != nil { + return nil, err + } + + runtime.SetFinalizer(bpf, destroyBPF) + return bpf, nil +} +func destroyBPF(bpf *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 == 1000 { + 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 || err == aeError { + 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/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_unix.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_unix.go new file mode 100644 index 0000000000..f270638a7f --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_unix.go @@ -0,0 +1,723 @@ +// 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. +// +//go:build !windows +// +build !windows + +package pcap + +import ( + "errors" + "os" + "sync" + "syscall" + "time" + "unsafe" + + "github.com/gopacket/gopacket" + + "github.com/gopacket/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 +#include +#include +#include + +// 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 + #ifdef __OpenBSD__ + #define gopacket_time_secs_t u_int32_t + #define gopacket_time_usecs_t u_int32_t + #else + #ifdef __time64_t + #define gopacket_time_secs_t __time64_t + #define gopacket_time_usecs_t __suseconds64_t + #else + #define gopacket_time_secs_t time_t + #define gopacket_time_usecs_t suseconds_t + #endif + #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 msec) { + struct pollfd fds[1]; + int fd; + + fd = pcap_get_selectable_fd(p); + if(fd < 0) { + return fd; + } + + fds[0].fd = fd; + fds[0].events = POLLIN; + + if(msec != 0) { + return poll(fds, 1, msec); + } + + // block indefinitely if no timeout provided + return poll(fds, 1, -1); +} + +*/ +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 + pcapError = C.PCAP_ERROR + 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.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() { + // According to pcap_get_selectable_fd() man page, there are some cases where it will + // return a file descriptor, but a simple call of select() or poll() will not indicate + // that the descriptor is readable until a full buffer's worth of packets is received, + // so the call must have a timeout less than *or equal* to the packet buffer timeout. + // The packet buffer timeout is set to timeoutMillis(p.timeout) in pcapOpenLive(), + // so we should be fine to use it here too. + C.pcap_wait(p.cptr, C.int(timeoutMillis(p.timeout))) +} + +// 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/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_windows.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_windows.go new file mode 100644 index 0000000000..587e4aa5ec --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/pcap_windows.go @@ -0,0 +1,898 @@ +// 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/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" + "golang.org/x/sys/windows" +) + +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 := windows.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 := windows.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 windows.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) + + if haveSearch, _ := syscall.GetProcAddress(kernel32, "AddDllDirectory"); haveSearch != 0 { + // if AddDllDirectory is present, we can use LOAD_LIBRARY_* stuff with LoadLibraryEx to avoid wpcap.dll hijacking + // see: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx + const LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400 + const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 + wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32) + if err != nil { + return fmt.Errorf("couldn't load wpcap.dll") + } + } else { + // otherwise fall back to load it with the unsafe search cause by SetDllDirectory + wpcapHandle, err = windows.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.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/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_dns.pcap b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_dns.pcap new file mode 100644 index 0000000000..3a79f928a5 Binary files /dev/null and b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_dns.pcap differ diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_ethernet.pcap b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_ethernet.pcap new file mode 100644 index 0000000000..1d01bd9185 Binary files /dev/null and b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_ethernet.pcap differ diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_loopback.pcap b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_loopback.pcap new file mode 100644 index 0000000000..ddeb82cd78 Binary files /dev/null and b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcap/test_loopback.pcap differ diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/capture.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/capture.go new file mode 100644 index 0000000000..f8c0a4f84f --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/capture.go @@ -0,0 +1,339 @@ +// 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. +//go:build linux + +package pcapgo + +import ( + "fmt" + "net" + "os" + "sync" + "syscall" + "time" + "unsafe" + + "golang.org/x/net/bpf" + "golang.org/x/sys/unix" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/endian" +) + +var hdrLen = unix.CmsgSpace(0) +var auxLen = unix.CmsgSpace(int(unsafe.Sizeof(unix.TpacketAuxdata{}))) +var timensLen = unix.CmsgSpace(int(unsafe.Sizeof(unix.Timespec{}))) +var timeLen = unix.CmsgSpace(int(unsafe.Sizeof(unix.Timeval{}))) + +// EthernetHandle holds shared buffers and file descriptor of af_packet socket +type EthernetHandle struct { + file *os.File + buffer []byte + oob []byte + ancil []interface{} + mu sync.Mutex + intf int + addr net.HardwareAddr +} + +// readOne reads a packet from the handle and returns a capture info + vlan info +func (h *EthernetHandle) readOne() (ci gopacket.CaptureInfo, vlan int, haveVlan bool, err error) { + // we could use unix.Recvmsg, but that does a memory allocation (for the returned sockaddr) :( + var msg unix.Msghdr + var sa unix.RawSockaddrLinklayer + + msg.Name = (*byte)(unsafe.Pointer(&sa)) + msg.Namelen = uint32(unsafe.Sizeof(sa)) + + var iov unix.Iovec + if len(h.buffer) > 0 { + iov.Base = &h.buffer[0] + iov.SetLen(len(h.buffer)) + } + msg.Iov = &iov + msg.Iovlen = 1 + + if len(h.oob) > 0 { + msg.Control = &h.oob[0] + msg.SetControllen(len(h.oob)) + } + + rawConn, err := h.file.SyscallConn() + if err != nil { + return + } + + var ( + e syscall.Errno + n uintptr + ) + err = rawConn.Read(func(fd uintptr) bool { + // use msg_trunc so we know packet size without auxdata, which might be missing + n, _, e = syscall.Syscall(unix.SYS_RECVMSG, fd, uintptr(unsafe.Pointer(&msg)), uintptr(unix.MSG_TRUNC)) + switch e { + case 0: + return true + case syscall.EAGAIN: + return false + default: + // some other error + return true + } + }) + if err != nil { + return + } + + switch { + case e.Temporary() || e.Timeout(): + return ci, 0, false, e + case e != 0: + return ci, 0, false, fmt.Errorf("couldn't read packet: %w", e) + } + + if sa.Family == unix.AF_PACKET { + ci.InterfaceIndex = int(sa.Ifindex) + } else { + ci.InterfaceIndex = h.intf + } + + // custom aux parsing so we don't allocate stuff (unix.ParseSocketControlMessage allocates a slice) + // we're getting at most 2 cmsgs anyway and know which ones they are (auxdata + timestamp(ns)) + oob := h.oob[:msg.Controllen] + gotAux := false + + for len(oob) > hdrLen { // > hdrLen, because we also need something after the cmsg header + hdr := (*unix.Cmsghdr)(unsafe.Pointer(&oob[0])) + switch { + case hdr.Level == unix.SOL_PACKET && hdr.Type == unix.PACKET_AUXDATA && len(oob) >= auxLen: + aux := (*unix.TpacketAuxdata)(unsafe.Pointer(&oob[hdrLen])) + ci.CaptureLength = int(n) + ci.Length = int(aux.Len) + vlan = int(aux.Vlan_tci) + haveVlan = (aux.Status & unix.TP_STATUS_VLAN_VALID) != 0 + gotAux = true + case hdr.Level == unix.SOL_SOCKET && hdr.Type == unix.SO_TIMESTAMPNS && len(oob) >= timensLen: + tstamp := (*unix.Timespec)(unsafe.Pointer(&oob[hdrLen])) + ci.Timestamp = time.Unix(int64(tstamp.Sec), int64(tstamp.Nsec)) + case hdr.Level == unix.SOL_SOCKET && hdr.Type == unix.SO_TIMESTAMP && len(oob) >= timeLen: + tstamp := (*unix.Timeval)(unsafe.Pointer(&oob[hdrLen])) + ci.Timestamp = time.Unix(int64(tstamp.Sec), int64(tstamp.Usec)*1000) + } + oob = oob[unix.CmsgSpace(int(hdr.Len))-hdrLen:] + } + + if !gotAux { + // fallback for no aux cmsg + ci.CaptureLength = int(n) + ci.Length = int(n) + haveVlan = false + } + + // fix up capture length if we needed to truncate + if ci.CaptureLength > len(h.buffer) { + ci.CaptureLength = len(h.buffer) + } + + if ci.Timestamp.IsZero() { + // we got no timestamp info -> emulate it + ci.Timestamp = time.Now() + } + + return ci, vlan, haveVlan, nil +} + +// ReadPacketData implements gopacket.PacketDataSource. If this was captured on a vlan, the vlan id will be in the AncillaryData[0] +func (h *EthernetHandle) ReadPacketData() ([]byte, gopacket.CaptureInfo, error) { + h.mu.Lock() + ci, vlan, haveVlan, err := h.readOne() + if err != nil { + h.mu.Unlock() + return nil, gopacket.CaptureInfo{}, fmt.Errorf("couldn't read packet data: %s", err) + } + + b := make([]byte, ci.CaptureLength) + copy(b, h.buffer) + h.mu.Unlock() + + if haveVlan { + ci.AncillaryData = []interface{}{vlan} + + } + + return b, ci, nil +} + +// ZeroCopyReadPacketData implements gopacket.ZeroCopyPacketDataSource. If this was captured on a vlan, the vlan id will be in the AncillaryData[0]. +// This function does not allocate memory. Beware that the next call to ZeroCopyReadPacketData will overwrite existing slices (returned data AND AncillaryData)! +// Due to shared buffers this must not be called concurrently +func (h *EthernetHandle) ZeroCopyReadPacketData() ([]byte, gopacket.CaptureInfo, error) { + ci, vlan, haveVlan, err := h.readOne() + if err != nil { + return nil, gopacket.CaptureInfo{}, fmt.Errorf("couldn't read packet data: %s", err) + } + + if haveVlan { + h.ancil[0] = vlan + ci.AncillaryData = h.ancil + } + + return h.buffer[:ci.CaptureLength], ci, nil +} + +// Close closes the underlying socket +func (h *EthernetHandle) Close() error { + return h.file.Close() +} + +// SetCaptureLength sets the maximum capture length to the given value +func (h *EthernetHandle) SetCaptureLength(len int) error { + if len < 0 { + return fmt.Errorf("illegal capture length %d. Must be at least 0", len) + } + h.buffer = make([]byte, len) + return nil +} + +// GetCaptureLength returns the maximum capture length +func (h *EthernetHandle) GetCaptureLength() int { + return len(h.buffer) +} + +// SetBPF attaches the given BPF filter to the socket. After this, only the packets for which the filter returns a value greater than zero are received. +// If a filter was already attached, it will be overwritten. To remove the filter, provide an empty slice. +func (h *EthernetHandle) SetBPF(filter []bpf.RawInstruction) (err error) { + rawConn, err := h.file.SyscallConn() + if err != nil { + return + } + + err2 := rawConn.Control(func(fd uintptr) { + if len(filter) == 0 { + err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_DETACH_FILTER, 0) + return + } + f := make([]unix.SockFilter, len(filter)) + for i := range filter { + f[i].Code = filter[i].Op + f[i].Jf = filter[i].Jf + f[i].Jt = filter[i].Jt + f[i].K = filter[i].K + } + fprog := &unix.SockFprog{ + Len: uint16(len(filter)), + Filter: &f[0], + } + err = unix.SetsockoptSockFprog(int(fd), unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, fprog) + }) + if err2 != nil { + return err2 + } + return +} + +// LocalAddr returns the local network address +func (h *EthernetHandle) LocalAddr() net.HardwareAddr { + // Hardware Address might have changed. Fetch new one and fall back to the stored one if fetching interface fails + intf, err := net.InterfaceByIndex(h.intf) + if err == nil { + h.addr = intf.HardwareAddr + } + return h.addr +} + +// SetPromiscuous sets promiscous mode to the required value. If it is enabled, traffic not destined for the interface will also be captured. +func (h *EthernetHandle) SetPromiscuous(b bool) (err error) { + rawConn, err := h.file.SyscallConn() + if err != nil { + return + } + + mreq := unix.PacketMreq{ + Ifindex: int32(h.intf), + Type: unix.PACKET_MR_PROMISC, + } + + opt := unix.PACKET_ADD_MEMBERSHIP + if !b { + opt = unix.PACKET_DROP_MEMBERSHIP + } + + err2 := rawConn.Control(func(fd uintptr) { + err = unix.SetsockoptPacketMreq(int(fd), unix.SOL_PACKET, opt, &mreq) + }) + if err2 != nil { + return err2 + } + return +} + +// Stats returns number of packets and dropped packets. This will be the number of packets/dropped packets since the last call to stats (not the cummulative sum!). +func (h *EthernetHandle) Stats() (res *unix.TpacketStats, err error) { + rawConn, err := h.file.SyscallConn() + if err != nil { + return + } + err2 := rawConn.Control(func(fd uintptr) { + res, err = unix.GetsockoptTpacketStats(int(fd), unix.SOL_PACKET, unix.PACKET_STATISTICS) + }) + if err2 != nil { + return nil, err2 + } + return +} + +// NewEthernetHandle implements pcap.OpenLive for network devices. +// If you want better performance have a look at github.com/gopacket/gopacket/afpacket. +// SetCaptureLength can be used to limit the maximum capture length. +func NewEthernetHandle(ifname string) (*EthernetHandle, error) { + intf, err := net.InterfaceByName(ifname) + if err != nil { + return nil, fmt.Errorf("couldn't query interface %s: %s", ifname, err) + } + + fd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW|unix.SOCK_CLOEXEC|unix.SOCK_NONBLOCK, int(endian.Htons(unix.ETH_P_ALL))) + if err != nil { + return nil, fmt.Errorf("couldn't open packet socket: %s", err) + } + + addr := unix.SockaddrLinklayer{ + Protocol: endian.Htons(unix.ETH_P_ALL), + Ifindex: intf.Index, + } + + if err := unix.Bind(fd, &addr); err != nil { + return nil, fmt.Errorf("couldn't bind to interface %s: %s", ifname, err) + } + + ooblen := 0 + + if err := unix.SetsockoptInt(fd, unix.SOL_PACKET, unix.PACKET_AUXDATA, 1); err != nil { + // we can't get auxdata -> no vlan info + } else { + ooblen += auxLen + } + + if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_TIMESTAMPNS, 1); err != nil { + // no nanosecond resolution :( -> try ms + if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_TIMESTAMP, 1); err != nil { + // if this doesn't work we well use time.Now() -> ignore errors here + } else { + ooblen += timeLen + } + } else { + ooblen += timensLen + } + + handle := &EthernetHandle{ + file: os.NewFile(uintptr(fd), ""), + buffer: make([]byte, intf.MTU), + oob: make([]byte, ooblen), + ancil: make([]interface{}, 1), + intf: intf.Index, + addr: intf.HardwareAddr, + } + return handle, nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/doc.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/doc.go new file mode 100644 index 0000000000..7808107c92 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/doc.go @@ -0,0 +1,62 @@ +// Copyright 2018 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. + +/* +Package pcapgo provides some native PCAP support, not requiring C libpcap to be installed. + +# Overview + +This package contains implementations for native PCAP support. Currently supported are + + - pcap-files read/write: Reader, Writer + - pcapng-files read/write: NgReader, NgWriter + - raw socket capture (linux only): EthernetHandle + +# Basic Usage pcapng + +Pcapng files can be read and written. Reading supports both big and little endian files, packet blocks, +simple packet blocks, enhanced packets blocks, interface blocks, and interface statistics blocks. All +the options also by Wireshark are supported. The default reader options match libpcap behaviour. Have +a look at NgReaderOptions for more advanced usage. Both ReadPacketData and ZeroCopyReadPacketData is +supported (which means PacketDataSource and ZeroCopyPacketDataSource is supported). + + f, err := os.Open("somefile.pcapng") + if err != nil { + ... + } + defer f.Close() + + r, err := NewNgReader(f, DefaultNgReaderOptions) + if err != nil { + ... + } + + data, ci, err := r.ReadPacketData() + ... + +Write supports only little endian, enhanced packets blocks, interface blocks, and interface statistics +blocks. The same options as with writing are supported. Interface timestamp resolution is fixed to +10^-9s to match time.Time. Any other values are ignored. Upon creating a writer, a section, and an +interface block is automatically written. Additional interfaces can be added at any time. Since +the writer uses a bufio.Writer internally, Flush must be called before closing the file! Have a look +at NewNgWriterInterface for more advanced usage. + + f, err := os.Create("somefile.pcapng") + if err != nil { + ... + } + defer f.Close() + + r, err = NewNgWriter(f, layers.LinkTypeEthernet) + if err != nil { + ... + } + defer r.Flush() + + err = r.WritePacket(ci, data) + ... +*/ +package pcapgo diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread.go new file mode 100644 index 0000000000..bbcd939894 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread.go @@ -0,0 +1,742 @@ +// Copyright 2018 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. + +package pcapgo + +import ( + "bufio" + "compress/gzip" + "encoding/binary" + "errors" + "fmt" + "io" + "time" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +// NgReaderOptions holds options for reading a pcapng file +type NgReaderOptions struct { + // WantMixedLinkType enables reading a pcapng file containing multiple interfaces with varying link types. If false all link types must match, which is the libpcap behaviour and LinkType returns the link type of the first interface. + // If true the link type of the packet is also exposed via ci.AncillaryData[0]. + WantMixedLinkType bool + // ErrorOnMismatchingLinkType enables returning an error if a packet with a link type not matching the first interface is encountered and WantMixedLinkType == false. + // If false packets those packets are just silently ignored, which is the libpcap behaviour. + ErrorOnMismatchingLinkType bool + // SkipUnknownVersion enables automatically skipping sections with an unknown version, which is recommended by the pcapng standard. Otherwise ErrVersionMismatch is returned. + SkipUnknownVersion bool + // SectionEndCallback gets called at the end of a section (execept for the last section, which is ends on EOF). The current list of interfaces and additional section information is provided. + // This is a good way to read interface statistics. + SectionEndCallback func([]NgInterface, NgSectionInfo) + // StatisticsCallback is called when a interface statistics block is read. The interface id and the read statistics are provided. + StatisticsCallback func(int, NgInterfaceStatistics) +} + +// DefaultNgReaderOptions provides sane defaults for a pcapng reader. +var DefaultNgReaderOptions = NgReaderOptions{} + +// NgReader wraps an underlying bufio.NgReader to read packet data in pcapng. +type NgReader struct { + r *bufio.Reader + options NgReaderOptions + sectionInfo NgSectionInfo + linkType layers.LinkType + ifaces []NgInterface + currentBlock ngBlock + currentOption ngOption + buf [24]byte + packetBuf []byte + ci gopacket.CaptureInfo + ancil [1]interface{} + blen int + firstSectionFound bool + activeSection bool + bigEndian bool + decryptionSecrets []decryptionSecret + nameRecords []NgNameRecord +} + +// NewNgReader initializes a new reader, reads the first section header, and if necessary according to the options the first interface. +func NewNgReader(r io.Reader, options NgReaderOptions) (*NgReader, error) { + reader := &NgReader{ + currentOption: ngOption{ + value: make([]byte, 1024), + }, + decryptionSecrets: make([]decryptionSecret, 0), + nameRecords: make([]NgNameRecord, 0), + options: options, + r: bufio.NewReader(r), + } + + gzipMagic, err := reader.r.Peek(2) + if err != nil { + return nil, err + } + + if gzipMagic[0] == magicGzip1 && gzipMagic[1] == magicGzip2 { + gzipReader, err := gzip.NewReader(reader.r) + if err != nil { + return nil, err + } + + reader.r = bufio.NewReader(gzipReader) + } + + // pcapng _must_ start with a section header + if err = reader.readBlock(); err != nil { + return nil, err + } + + if reader.currentBlock.typ != ngBlockTypeSectionHeader { + return nil, fmt.Errorf("Unknown magic %x", reader.currentBlock.typ) + } + + if err = reader.readSectionHeader(); err != nil { + return nil, err + } + + return reader, nil +} + +// First a couple of helper functions to speed things up + +// This is way faster than calling io.ReadFull since io.ReadFull needs an itab lookup, does an additional function call into ReadAtLeast, and ReadAtLeast does additional stuff we don't need +// Additionally this removes the bounds check compared to io.ReadFull due to the use of uint +func (r *NgReader) readBytes(buffer []byte) error { + n := uint(0) + for n < uint(len(buffer)) { + nn, err := r.r.Read(buffer[n:]) + n += uint(nn) + if err != nil { + return err + } + } + return nil +} + +// The following functions make the binary.* functions inlineable (except for getUint64, which is too big, but not in any hot path anyway) +// Compared to storing binary.*Endian in a binary.ByteOrder this shaves off about 20% for (ZeroCopy)ReadPacketData, which is caused by the needed itab lookup + indirect go call +func (r *NgReader) getUint16(buffer []byte) uint16 { + if r.bigEndian { + return binary.BigEndian.Uint16(buffer) + } + return binary.LittleEndian.Uint16(buffer) +} + +func (r *NgReader) getUint32(buffer []byte) uint32 { + if r.bigEndian { + return binary.BigEndian.Uint32(buffer) + } + return binary.LittleEndian.Uint32(buffer) +} + +func (r *NgReader) getUint64(buffer []byte) uint64 { + if r.bigEndian { + return binary.BigEndian.Uint64(buffer) + } + return binary.LittleEndian.Uint64(buffer) +} + +// Now the pcapng implementation + +// readBlock reads a the blocktype and length from the file. If the type is a section header, endianess is also read. +func (r *NgReader) readBlock() error { + if err := r.readBytes(r.buf[0:8]); err != nil { + return err + } + r.currentBlock.typ = ngBlockType(r.getUint32(r.buf[0:4])) + // The next part is a bit fucked up since a section header could change the endianess... + // So first read then length just into a buffer, check if its a section header and then do the endianess part... + if r.currentBlock.typ == ngBlockTypeSectionHeader { + if err := r.readBytes(r.buf[8:12]); err != nil { + return err + } + if binary.BigEndian.Uint32(r.buf[8:12]) == ngByteOrderMagic { + r.bigEndian = true + } else if binary.LittleEndian.Uint32(r.buf[8:12]) == ngByteOrderMagic { + r.bigEndian = false + } else { + return errors.New("Wrong byte order value in Section Header") + } + // Set length to remaining length (length - (type + lengthfield = 8) - 4 for byteOrderMagic) + r.currentBlock.length = r.getUint32(r.buf[4:8]) - 8 - 4 + return nil + } + // Set length to remaining length (length - (type + lengthfield = 8) + r.currentBlock.length = r.getUint32(r.buf[4:8]) - 8 + return nil +} + +// readOption reads a single arbitrary option (type and value). If there is no space left for options and end of options is missing, it is faked. +func (r *NgReader) readOption() error { + if r.currentBlock.length == 4 { + // no more options + r.currentOption.code = ngOptionCodeEndOfOptions + return nil + } + if err := r.readBytes(r.buf[:4]); err != nil { + return err + } + r.currentBlock.length -= 4 + r.currentOption.code = ngOptionCode(r.getUint16(r.buf[:2])) + length := r.getUint16(r.buf[2:4]) + if r.currentOption.code == ngOptionCodeEndOfOptions { + if length != 0 { + return errors.New("End of Options must be zero length") + } + return nil + } + if length != 0 { + if length < uint16(cap(r.currentOption.value)) { + r.currentOption.value = r.currentOption.value[:length] + } else { + r.currentOption.value = make([]byte, length) + } + if err := r.readBytes(r.currentOption.value); err != nil { + return err + } + //consume padding + padding := length % 4 + if padding > 0 { + padding = 4 - padding + if _, err := r.r.Discard(int(padding)); err != nil { + return err + } + } + r.currentBlock.length -= uint32(length + padding) + } + return nil +} + +// readSectionHeader parses the full section header and implements section skipping in case of version mismatch +// if needed, the first interface is read +func (r *NgReader) readSectionHeader() error { + if r.options.SectionEndCallback != nil && r.activeSection { + interfaces := make([]NgInterface, len(r.ifaces)) + for i := range r.ifaces { + interfaces[i] = r.ifaces[i] + } + r.options.SectionEndCallback(interfaces, r.sectionInfo) + } + // clear interfaces, decryption secrets and name records + r.ifaces = r.ifaces[:0] + r.decryptionSecrets = r.decryptionSecrets[:0] + r.nameRecords = r.nameRecords[:0] + r.activeSection = false + +RESTART: + // read major, minor, section length + if err := r.readBytes(r.buf[:12]); err != nil { + return err + } + r.currentBlock.length -= 12 + + vMajor := r.getUint16(r.buf[0:2]) + vMinor := r.getUint16(r.buf[2:4]) + if vMajor != ngVersionMajor || vMinor != ngVersionMinor { + if !r.options.SkipUnknownVersion { + // Well the standard actually says to skip unknown version section headers, + // but this would mean user would be kept in the dark about whats going on... + return ErrNgVersionMismatch + } + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + if err := r.skipSection(); err != nil { + return err + } + goto RESTART + } + + var section NgSectionInfo + +OPTIONS: + for { + if err := r.readOption(); err != nil { + return err + } + switch r.currentOption.code { + case ngOptionCodeEndOfOptions: + break OPTIONS + case ngOptionCodeComment: + section.Comment = string(r.currentOption.value) + case ngOptionCodeHardware: + section.Hardware = string(r.currentOption.value) + case ngOptionCodeOS: + section.OS = string(r.currentOption.value) + case ngOptionCodeUserApplication: + section.Application = string(r.currentOption.value) + } + } + + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + r.activeSection = true + r.sectionInfo = section + + if !r.options.WantMixedLinkType { + // If we don't want mixed link type, we need the first interface to fill Reader.LinkType() + // This handles most of the pcapngs out there, since they start with an IDB + if err := r.firstInterface(); err != nil { + return err + } + } + + return nil +} + +// skipSection skips blocks until the next section +func (r *NgReader) skipSection() error { + for { + if err := r.readBlock(); err != nil { + return err + } + if r.currentBlock.typ == ngBlockTypeSectionHeader { + return nil + } + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + } +} + +// SkipSection skips the contents of the rest of the current section and reads the next section header. +func (r *NgReader) SkipSection() error { + if err := r.skipSection(); err != nil { + return err + } + return r.readSectionHeader() +} + +// firstInterface reads the first interface from the section and panics if a packet is encountered. +func (r *NgReader) firstInterface() error { + for { + if err := r.readBlock(); err != nil { + return err + } + switch r.currentBlock.typ { + case ngBlockTypeInterfaceDescriptor: + if err := r.readInterfaceDescriptor(); err != nil { + return err + } + if !r.firstSectionFound { + r.linkType = r.ifaces[0].LinkType + r.firstSectionFound = true + } else if r.linkType != r.ifaces[0].LinkType { + if r.options.ErrorOnMismatchingLinkType { + return ErrNgLinkTypeMismatch + } + continue + } + return nil + case ngBlockTypePacket, ngBlockTypeEnhancedPacket, ngBlockTypeSimplePacket, ngBlockTypeInterfaceStatistics: + return errors.New("A section must have an interface before a packet block") + case ngBlockTypeDecryptionSecrets: + if err := r.readDecryptionSecretsBlock(); err != nil { + return err + } + case ngBlockTypeNameResolution: + if err := r.readNameResolutionBlock(); err != nil { + return err + } + } + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + } +} + +// readInterfaceDescriptor parses an interface descriptor, prepares timing calculation, and adds the interface details to the current list +func (r *NgReader) readInterfaceDescriptor() error { + if err := r.readBytes(r.buf[:8]); err != nil { + return err + } + r.currentBlock.length -= 8 + var intf NgInterface + intf.LinkType = layers.LinkType(r.getUint16(r.buf[:2])) + intf.SnapLength = r.getUint32(r.buf[4:8]) + +OPTIONS: + for { + if err := r.readOption(); err != nil { + return err + } + switch r.currentOption.code { + case ngOptionCodeEndOfOptions: + break OPTIONS + case ngOptionCodeInterfaceName: + intf.Name = string(r.currentOption.value) + case ngOptionCodeComment: + intf.Comment = string(r.currentOption.value) + case ngOptionCodeInterfaceDescription: + intf.Description = string(r.currentOption.value) + case ngOptionCodeInterfaceFilter: + // ignore filter type (first byte) since it is not specified + intf.Filter = string(r.currentOption.value[1:]) + case ngOptionCodeInterfaceOS: + intf.OS = string(r.currentOption.value) + case ngOptionCodeInterfaceTimestampOffset: + intf.TimestampOffset = r.getUint64(r.currentOption.value[:8]) + case ngOptionCodeInterfaceTimestampResolution: + intf.TimestampResolution = NgResolution(r.currentOption.value[0]) + } + } + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + if intf.TimestampResolution == 0 { + intf.TimestampResolution = 6 + } + + //parse options + if intf.TimestampResolution.Binary() { + //negative power of 2 + intf.secondMask = 1 << intf.TimestampResolution.Exponent() + } else { + //negative power of 10 + intf.secondMask = 1 + for j := uint8(0); j < intf.TimestampResolution.Exponent(); j++ { + intf.secondMask *= 10 + } + } + intf.scaleDown = 1 + intf.scaleUp = 1 + if intf.secondMask < 1e9 { + intf.scaleUp = 1e9 / intf.secondMask + } else { + intf.scaleDown = intf.secondMask / 1e9 + } + r.ifaces = append(r.ifaces, intf) + return nil +} + +// convertTime adds offset + shifts the given time value according to the given interface +func (r *NgReader) convertTime(ifaceID int, ts uint64) (int64, int64) { + iface := r.ifaces[ifaceID] + return int64(ts/iface.secondMask + iface.TimestampOffset), int64(ts % iface.secondMask * iface.scaleUp / iface.scaleDown) +} + +// readInterfaceStatistics updates the statistics of the given interface +func (r *NgReader) readInterfaceStatistics() error { + if err := r.readBytes(r.buf[:12]); err != nil { + return err + } + r.currentBlock.length -= 12 + ifaceID := int(r.getUint32(r.buf[:4])) + ts := uint64(r.getUint32(r.buf[4:8]))<<32 | uint64(r.getUint32(r.buf[8:12])) + if int(ifaceID) >= len(r.ifaces) { + return fmt.Errorf("Interface id %d not present in section (have only %d interfaces)", ifaceID, len(r.ifaces)) + } + stats := &r.ifaces[ifaceID].Statistics + *stats = ngEmptyStatistics + stats.LastUpdate = time.Unix(r.convertTime(ifaceID, ts)).UTC() + +OPTIONS: + for { + if err := r.readOption(); err != nil { + return err + } + switch r.currentOption.code { + case ngOptionCodeEndOfOptions: + break OPTIONS + case ngOptionCodeComment: + stats.Comment = string(r.currentOption.value) + case ngOptionCodeInterfaceStatisticsStartTime: + ts = uint64(r.getUint32(r.currentOption.value[:4]))<<32 | uint64(r.getUint32(r.currentOption.value[4:8])) + stats.StartTime = time.Unix(r.convertTime(ifaceID, ts)).UTC() + case ngOptionCodeInterfaceStatisticsEndTime: + ts = uint64(r.getUint32(r.currentOption.value[:4]))<<32 | uint64(r.getUint32(r.currentOption.value[4:8])) + stats.EndTime = time.Unix(r.convertTime(ifaceID, ts)).UTC() + case ngOptionCodeInterfaceStatisticsInterfaceReceived: + stats.PacketsReceived = r.getUint64(r.currentOption.value[:8]) + case ngOptionCodeInterfaceStatisticsInterfaceDropped: + stats.PacketsDropped = r.getUint64(r.currentOption.value[:8]) + } + } + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + if r.options.StatisticsCallback != nil { + r.options.StatisticsCallback(ifaceID, *stats) + } + return nil +} + +// readPacketHeader looks for a packet (enhanced, simple, or packet) and parses the header. +// If an interface descriptor, an interface statistics block, or a section header is encountered, those are handled accordingly. +// All other block types are skipped. New block types must be added here. +func (r *NgReader) readPacketHeader() error { +RESTART: +FIND_PACKET: + for { + if err := r.readBlock(); err != nil { + return err + } + switch r.currentBlock.typ { + case ngBlockTypeEnhancedPacket: + if err := r.readBytes(r.buf[:20]); err != nil { + return err + } + r.currentBlock.length -= 20 + r.ci.InterfaceIndex = int(r.getUint32(r.buf[:4])) + if r.ci.InterfaceIndex >= len(r.ifaces) { + return fmt.Errorf("Interface id %d not present in section (have only %d interfaces)", r.ci.InterfaceIndex, len(r.ifaces)) + } + r.ci.Timestamp = time.Unix(r.convertTime(r.ci.InterfaceIndex, uint64(r.getUint32(r.buf[4:8]))<<32|uint64(r.getUint32(r.buf[8:12])))).UTC() + r.ci.CaptureLength = int(r.getUint32(r.buf[12:16])) + r.ci.Length = int(r.getUint32(r.buf[16:20])) + break FIND_PACKET + case ngBlockTypeSimplePacket: + if err := r.readBytes(r.buf[:4]); err != nil { + return err + } + r.currentBlock.length -= 4 + r.ci.Timestamp = time.Time{} + r.ci.InterfaceIndex = 0 + r.ci.Length = int(r.getUint32(r.buf[:4])) + r.ci.CaptureLength = r.ci.Length + if len(r.ifaces) == 0 { + return errors.New("At least one Interface is needed for a packet") + } + if r.ifaces[0].SnapLength != 0 && uint32(r.ci.CaptureLength) > r.ifaces[0].SnapLength { + r.ci.CaptureLength = int(r.ifaces[0].SnapLength) + } + break FIND_PACKET + case ngBlockTypeInterfaceDescriptor: + if err := r.readInterfaceDescriptor(); err != nil { + return err + } + case ngBlockTypeInterfaceStatistics: + if err := r.readInterfaceStatistics(); err != nil { + return err + } + case ngBlockTypeSectionHeader: + if err := r.readSectionHeader(); err != nil { + return err + } + case ngBlockTypePacket: + if err := r.readBytes(r.buf[:20]); err != nil { + return err + } + r.currentBlock.length -= 20 + r.ci.InterfaceIndex = int(r.getUint16(r.buf[0:2])) + if r.ci.InterfaceIndex >= len(r.ifaces) { + return fmt.Errorf("Interface id %d not present in section (have only %d interfaces)", r.ci.InterfaceIndex, len(r.ifaces)) + } + r.ci.Timestamp = time.Unix(r.convertTime(r.ci.InterfaceIndex, uint64(r.getUint32(r.buf[4:8]))<<32|uint64(r.getUint32(r.buf[8:12])))).UTC() + r.ci.CaptureLength = int(r.getUint32(r.buf[12:16])) + r.ci.Length = int(r.getUint32(r.buf[16:20])) + break FIND_PACKET + case ngBlockTypeNameResolution: + if err := r.readNameResolutionBlock(); err != nil { + return err + } + default: + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + } + } + if !r.options.WantMixedLinkType { + if r.ifaces[r.ci.InterfaceIndex].LinkType != r.linkType { + if _, err := r.r.Discard(int(r.currentBlock.length)); err != nil { + return err + } + if r.options.ErrorOnMismatchingLinkType { + return ErrNgLinkTypeMismatch + } + goto RESTART + } + return nil + } + r.ancil[0] = r.ifaces[r.ci.InterfaceIndex].LinkType + return nil +} + +func (r *NgReader) readPacketOptions() (NgPacketOptions, error) { + opts := NgPacketOptions{} + +OPTIONS: + for { + if err := r.readOption(); err != nil { + return opts, err + } + switch r.currentOption.code { + case ngOptionCodeEndOfOptions: + break OPTIONS + case ngOptionCodeComment: + opts.Comments = append(opts.Comments, string(r.currentOption.value)) + case ngOptionCodeEpbFlags: + flags := NgEpbFlags{} + flags.FromUint32(binary.LittleEndian.Uint32(r.currentOption.value)) + opts.Flags = &flags + case ngOptionCodeEpbHash: + v := make([]byte, len(r.currentOption.value)-1) + copy(v, r.currentOption.value[1:]) + opts.Hashes = append(opts.Hashes, NgEpbHash{ + Algorithm: NgEpbHashAlgorithm(r.currentOption.value[0]), + Hash: v, + }) + case ngOptionCodeEpbDropCount: + v := binary.LittleEndian.Uint64(r.currentOption.value) + opts.DropCount = &v + case ngOptionCodeEpbPacketID: + v := binary.LittleEndian.Uint64(r.currentOption.value) + opts.PacketID = &v + case ngOptionCodeEpbQueue: + v := binary.LittleEndian.Uint32(r.currentOption.value) + opts.Queue = &v + case ngOptionCodeEpbVerdict: + v := make([]byte, len(r.currentOption.value)-1) + copy(v, r.currentOption.value[1:]) + opts.Verdicts = append(opts.Verdicts, NgEpbVerdict{ + Type: NgEpbVerdictType(r.currentOption.value[0]), + Data: v, + }) + } + } + return opts, nil +} + +// ReadPacketData returns the next packet available from this data source. +// If WantMixedLinkType is true, ci.AncillaryData[0] contains the link type. +func (r *NgReader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + data, ci, _, err = r.ReadPacketDataWithOptions() + return +} + +// ReadPacketDataWithOptions returns the next packet available from this data source. +// If WantMixedLinkType is true, ci.AncillaryData[0] contains the link type. +func (r *NgReader) ReadPacketDataWithOptions() (data []byte, ci gopacket.CaptureInfo, opts NgPacketOptions, err error) { + if err = r.readPacketHeader(); err != nil { + return + } + ci = r.ci + if r.options.WantMixedLinkType { + ci.AncillaryData = make([]interface{}, 1) + ci.AncillaryData[0] = r.ancil[0] + } + data = make([]byte, r.ci.CaptureLength) + if err = r.readBytes(data); err != nil { + return + } + r.currentBlock.length -= uint32(r.ci.CaptureLength) + padding := (4 - r.ci.CaptureLength&3) & 3 + if padding > 0 { + if _, err = r.r.Discard(int(padding)); err != nil { + return + } + r.currentBlock.length -= uint32(padding) + } + + if r.currentBlock.typ == ngBlockTypeEnhancedPacket { + if opts, err = r.readPacketOptions(); err != nil { + return + } + } + _, err = r.r.Discard(int(r.currentBlock.length)) + return +} + +// ZeroCopyReadPacketData returns the next packet available from this data source. +// If WantMixedLinkType is true, ci.AncillaryData[0] contains the link type. +// Warning: Like data, ci.AncillaryData is also reused and overwritten on the next call to ZeroCopyReadPacketData. +// +// It is not true zero copy, as data is still copied from the underlying reader. However, +// this method avoids allocating heap memory for every packet. +func (r *NgReader) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + data, ci, _, err = r.ZeroCopyReadPacketDataWithOptions() + return +} + +// ZeroCopyReadPacketDataWithOptions returns the next packet available from this data source. +// If WantMixedLinkType is true, ci.AncillaryData[0] contains the link type. +// Warning: Like data, ci.AncillaryData is also reused and overwritten on the next call to ZeroCopyReadPacketData. +// +// It is not true zero copy, as data is still copied from the underlying reader. However, +// this method avoids allocating heap memory for every packet. +func (r *NgReader) ZeroCopyReadPacketDataWithOptions() (data []byte, ci gopacket.CaptureInfo, opts NgPacketOptions, err error) { + if err = r.readPacketHeader(); err != nil { + return + } + ci = r.ci + if r.options.WantMixedLinkType { + ci.AncillaryData = r.ancil[:] + } + if cap(r.packetBuf) < ci.CaptureLength { + snaplen := int(r.ifaces[ci.InterfaceIndex].SnapLength) + if snaplen < ci.CaptureLength { + snaplen = ci.CaptureLength + } + r.packetBuf = make([]byte, snaplen) + } + data = r.packetBuf[:ci.CaptureLength] + if err = r.readBytes(data); err != nil { + return + } + r.currentBlock.length -= uint32(r.ci.CaptureLength) + padding := (4 - r.ci.CaptureLength&3) & 3 + if padding > 0 { + if _, err = r.r.Discard(int(padding)); err != nil { + return + } + r.currentBlock.length -= uint32(padding) + } + + if r.currentBlock.typ == ngBlockTypeEnhancedPacket { + if opts, err = r.readPacketOptions(); err != nil { + return + } + } + _, err = r.r.Discard(int(r.currentBlock.length)) + return +} + +// LinkType returns the link type of the first interface, as a layers.LinkType. This is only valid, if WantMixedLinkType is false. +func (r *NgReader) LinkType() layers.LinkType { + return r.linkType +} + +// SectionInfo returns information about the current section. +func (r *NgReader) SectionInfo() NgSectionInfo { + return r.sectionInfo +} + +// Interface returns interface information and statistics of interface with the given id. +func (r *NgReader) Interface(i int) (NgInterface, error) { + if i >= len(r.ifaces) || i < 0 { + return NgInterface{}, fmt.Errorf("Interface %d invalid. There are only %d interfaces", i, len(r.ifaces)) + } + return r.ifaces[i], nil +} + +// NInterfaces returns the current number of interfaces. +func (r *NgReader) NInterfaces() int { + return len(r.ifaces) +} + +// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution. +func (r *NgReader) Resolution() gopacket.TimestampResolution { + if r.options.WantMixedLinkType { + return gopacket.TimestampResolution{} + } + return r.ifaces[0].Resolution() +} + +// Interface returns interface information and statistics of interface with the given id. +func (r *NgReader) Name(i int) (NgNameRecord, error) { + if i >= len(r.nameRecords) || i < 0 { + return NgNameRecord{}, fmt.Errorf("Interface %d invalid. There are only %d interfaces", i, len(r.nameRecords)) + } + return r.nameRecords[i], nil +} + +// NInterfaces returns the current number of interfaces. +func (r *NgReader) NNames() int { + return len(r.nameRecords) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_dsb.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_dsb.go new file mode 100644 index 0000000000..3bcdfa21de --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_dsb.go @@ -0,0 +1,39 @@ +// Copyright 2018 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. +// author: CFC4N + +package pcapgo + +import "fmt" + +type decryptionSecret struct { + blockInfo pcapngDecryptionSecretsBlock + payload []byte +} + +// readDecryptionSecrets parses an encryption secrets section from the given +func (r *NgReader) readDecryptionSecretsBlock() error { + if err := r.readBytes(r.buf[:8]); err != nil { + return fmt.Errorf("could not read DecryptionSecret Header block length: %v", err) + } + r.currentBlock.length -= 8 + + var decryptionSecretsBlock = &pcapngDecryptionSecretsBlock{} + decryptionSecretsBlock.secretsType = r.getUint32(r.buf[0:4]) + decryptionSecretsBlock.secretsLength = r.getUint32(r.buf[4:8]) + var payload = make([]byte, decryptionSecretsBlock.secretsLength) + if err := r.readBytes(payload); err != nil { + return fmt.Errorf("could not read %d bytes from DecryptionSecret payload: %v", decryptionSecretsBlock.secretsLength, err) + } + r.currentBlock.length -= uint32(len(payload)) + + // save decryption secrets + var decryptSecret decryptionSecret + decryptSecret.blockInfo = *decryptionSecretsBlock + decryptSecret.payload = payload + r.decryptionSecrets = append(r.decryptionSecrets, decryptSecret) + return nil +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_nrb.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_nrb.go new file mode 100644 index 0000000000..3b14e7bd28 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngread_nrb.go @@ -0,0 +1,138 @@ +// Copyright 2018 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. +// author: Raphael Coeffic + +package pcapgo + +import ( + "bytes" + "fmt" + "net/netip" +) + +type nameRecordHeader struct { + recordType uint16 + recordLength uint16 +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func paddingBytes32b(length int) int { + padding := length % 4 + if padding > 0 { + padding = 4 - padding + } + return padding +} + +func newIPAddress(data []byte) *NgIPAddress { + addr := &NgIPAddress{} + addr.Addr, _ = netip.AddrFromSlice(data) + return addr +} + +func newHWAddress(data []byte) *NgEUIAddress { + addr := &NgEUIAddress{} + addr.Addr = bytes.Clone(data) + return addr +} + +func (r *NgReader) readIPAddr(nr *NgNameRecord, length int) error { + if err := r.readBytes(r.buf[:length]); err != nil { + return fmt.Errorf("could not read IP address: %v", err) + } + nr.Addr = newIPAddress(r.buf[:length]) + return nil +} + +func (r *NgReader) readHWAddr(nr *NgNameRecord, length int) error { + if err := r.readBytes(r.buf[:length]); err != nil { + return fmt.Errorf("could not read EUI address: %v", err) + } + nr.Addr = newHWAddress(r.buf[:]) + return nil +} + +func (r *NgReader) discard(length int) error { + if _, err := r.r.Discard(length); err != nil { + return fmt.Errorf("could not discard %d bytes: %v", length, err) + } + r.currentBlock.length -= uint32(length) + return nil +} + +func (r *NgReader) readNameResolutionBlock() error { + + for r.currentBlock.length > 0 { + // Read name record header + if err := r.readBytes(r.buf[:4]); err != nil { + return fmt.Errorf("could not read NameRecord Header block length: %v", err) + } + r.currentBlock.length -= 4 + + var nrh = &nameRecordHeader{} + nrh.recordType = r.getUint16(r.buf[0:2]) + nrh.recordLength = r.getUint16(r.buf[2:4]) + + var nameRecord = NgNameRecord{} + length := min(int(nrh.recordLength), int(r.currentBlock.length)) + padding := paddingBytes32b(length) + + switch nrh.recordType { + case ngNameRecordIPv4: + if err := r.readIPAddr(&nameRecord, 4); err != nil { + return fmt.Errorf("could not read IPv4 address: %v", err) + } + case ngNameRecordIPv6: + if err := r.readIPAddr(&nameRecord, 16); err != nil { + return fmt.Errorf("could not read IPv6 address: %v", err) + } + case ngNameRecordEUI48: + if err := r.readHWAddr(&nameRecord, 6); err != nil { + return fmt.Errorf("could not read EUI-48 address: %v", err) + } + case ngNameRecordEUI64: + if err := r.readHWAddr(&nameRecord, 8); err != nil { + return fmt.Errorf("could not read EUI-64 address: %v", err) + } + case ngNameRecordEnd: + goto DONE + default: + // discard record length + if err := r.discard(length + padding); err != nil { + return fmt.Errorf("could not discard unknown name record: %v", err) + } + continue + } + r.currentBlock.length -= uint32(length) + length -= nameRecord.Addr.Len() + + for length > 0 { + bstr, err := r.r.ReadBytes(0) + if err != nil { + return fmt.Errorf("could not read name: %v", err) + } + length -= len(bstr) + name := string(bytes.Trim(bstr, "\x00")) + nameRecord.Names = append(nameRecord.Names, name) + } + r.nameRecords = append(r.nameRecords, nameRecord) + + //consume padding + if err := r.discard(padding); err != nil { + return err + } + } + +DONE: + // discard everything after 'nrb_record_end' (including options) + return r.discard(int(r.currentBlock.length)) +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite.go new file mode 100644 index 0000000000..c123104b71 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite.go @@ -0,0 +1,416 @@ +// Copyright 2018 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. + +package pcapgo + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "runtime" + "time" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +// NgWriterOptions holds options for creating a pcapng file +type NgWriterOptions struct { + // SectionInfo will be written to the section header + SectionInfo NgSectionInfo +} + +// DefaultNgWriterOptions contain defaults for a pcapng writer used by NewWriter +var DefaultNgWriterOptions = NgWriterOptions{ + SectionInfo: NgSectionInfo{ + Hardware: runtime.GOARCH, + OS: runtime.GOOS, + Application: "gopacket", //spread the word + }, +} + +// DefaultNgInterface contains default interface options used by NewWriter +var DefaultNgInterface = NgInterface{ + Name: "intf0", + OS: runtime.GOOS, + SnapLength: 0, //unlimited + TimestampResolution: 9, +} + +// NgWriter holds the internal state of a pcapng file writer. Internally a bufio.NgWriter is used, therefore Flush must be called before closing the underlying file. +type NgWriter struct { + w *bufio.Writer + options NgWriterOptions + intf uint32 + buf [28]byte +} + +// NewNgWriter initializes and returns a new writer. Additionally, one section and one interface (without statistics) is written to the file. Interface and section options are used from DefaultNgInterface and DefaultNgWriterOptions. +// Flush must be called before the file is closed, or if eventual unwritten information should be written out to the storage device. +// +// Written files are in little endian format. Interface timestamp resolution is fixed to 9 (to match time.Time). +func NewNgWriter(w io.Writer, linkType layers.LinkType) (*NgWriter, error) { + intf := DefaultNgInterface + intf.LinkType = linkType + return NewNgWriterInterface(w, intf, DefaultNgWriterOptions) +} + +// NewNgWriterInterface initializes and returns a new writer. Additionally, one section and one interface (without statistics) is written to the file. +// Flush must be called before the file is closed, or if eventual unwritten information should be written out to the storage device. +// +// Written files are in little endian format. Interface timestamp resolution is fixed to 9 (to match time.Time). +func NewNgWriterInterface(w io.Writer, intf NgInterface, options NgWriterOptions) (*NgWriter, error) { + ret := &NgWriter{ + w: bufio.NewWriter(w), + options: options, + } + if err := ret.writeSectionHeader(); err != nil { + return nil, err + } + + if _, err := ret.AddInterface(intf); err != nil { + return nil, err + } + return ret, nil +} + +// ngOptionLength returns the needed length for one option value (without padding) +func ngOptionLength(option ngOption) int { + switch val := option.raw.(type) { + case []byte: + return len(val) + case string: + return len(val) + case time.Time: + return 8 + case uint64: + return 8 + case uint32: + return 4 + case uint8: + return 1 + default: + panic("This should never happen") + } +} + +// prepareNgOptions fills out the length value of the given options and returns the number of octets needed for all the given options including padding. +func prepareNgOptions(options []ngOption) uint32 { + var ret uint32 + for i, option := range options { + length := ngOptionLength(option) + options[i].length = uint16(length) + length += (4-length&3)&3 + // padding + 4 //header + ret += uint32(length) + } + if ret > 0 { + ret += 4 // end of options + } + return ret +} + +// writeOptions writes the given options to the file. prepareOptions must be called beforehand. +func (w *NgWriter) writeOptions(options []ngOption) error { + if len(options) == 0 { + return nil + } + + var zero [4]byte + for _, option := range options { + binary.LittleEndian.PutUint16(w.buf[0:2], uint16(option.code)) + binary.LittleEndian.PutUint16(w.buf[2:4], option.length) + if _, err := w.w.Write(w.buf[:4]); err != nil { + return err + } + switch val := option.raw.(type) { + case []byte: + if _, err := w.w.Write(val); err != nil { + return err + } + padding := uint8((4 - option.length&3) & 3) + if padding < 4 { + if _, err := w.w.Write(zero[:padding]); err != nil { + return err + } + } + case string: + if _, err := w.w.Write([]byte(val)); err != nil { + return err + } + padding := uint8((4 - option.length&3) & 3) + if padding < 4 { + if _, err := w.w.Write(zero[:padding]); err != nil { + return err + } + } + case time.Time: + ts := val.UnixNano() + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ts>>32)) + binary.LittleEndian.PutUint32(w.buf[4:8], uint32(ts)) + if _, err := w.w.Write(w.buf[:8]); err != nil { + return err + } + case uint64: + binary.LittleEndian.PutUint64(w.buf[:8], val) + if _, err := w.w.Write(w.buf[:8]); err != nil { + return err + } + case uint32: + binary.LittleEndian.PutUint32(w.buf[:4], val) + if _, err := w.w.Write(w.buf[:4]); err != nil { + return err + } + case uint8: + binary.LittleEndian.PutUint32(w.buf[:4], 0) // padding + w.buf[0] = val + if _, err := w.w.Write(w.buf[:4]); err != nil { + return err + } + default: + panic("This should never happen") + } + } + + // options must be folled by an end of options option + binary.LittleEndian.PutUint16(w.buf[0:2], uint16(ngOptionCodeEndOfOptions)) + binary.LittleEndian.PutUint16(w.buf[2:4], 0) + _, err := w.w.Write(w.buf[:4]) + return err +} + +// writeSectionHeader writes a section header to the file +func (w *NgWriter) writeSectionHeader() error { + var scratch [4]ngOption + i := 0 + info := w.options.SectionInfo + if info.Application != "" { + scratch[i].code = ngOptionCodeUserApplication + scratch[i].raw = info.Application + i++ + } + if info.Comment != "" { + scratch[i].code = ngOptionCodeComment + scratch[i].raw = info.Comment + i++ + } + if info.Hardware != "" { + scratch[i].code = ngOptionCodeHardware + scratch[i].raw = info.Hardware + i++ + } + if info.OS != "" { + scratch[i].code = ngOptionCodeOS + scratch[i].raw = info.OS + i++ + } + options := scratch[:i] + + length := prepareNgOptions(options) + + 24 + // header + 4 // trailer + + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ngBlockTypeSectionHeader)) + binary.LittleEndian.PutUint32(w.buf[4:8], length) + binary.LittleEndian.PutUint32(w.buf[8:12], ngByteOrderMagic) + binary.LittleEndian.PutUint16(w.buf[12:14], ngVersionMajor) + binary.LittleEndian.PutUint16(w.buf[14:16], ngVersionMinor) + binary.LittleEndian.PutUint64(w.buf[16:24], 0xFFFFFFFFFFFFFFFF) // unspecified + if _, err := w.w.Write(w.buf[:24]); err != nil { + return err + } + + if err := w.writeOptions(options); err != nil { + return err + } + + binary.LittleEndian.PutUint32(w.buf[0:4], length) + _, err := w.w.Write(w.buf[:4]) + return err +} + +// AddInterface adds the specified interface to the file, excluding statistics. Interface timestamp resolution is fixed to 9 (to match time.Time). Empty values are not written. +func (w *NgWriter) AddInterface(intf NgInterface) (id int, err error) { + id = int(w.intf) + w.intf++ + + var scratch [7]ngOption + i := 0 + if intf.Name != "" { + scratch[i].code = ngOptionCodeInterfaceName + scratch[i].raw = intf.Name + i++ + } + if intf.Comment != "" { + scratch[i].code = ngOptionCodeComment + scratch[i].raw = intf.Comment + i++ + } + if intf.Description != "" { + scratch[i].code = ngOptionCodeInterfaceDescription + scratch[i].raw = intf.Description + i++ + } + if intf.Filter != "" { + scratch[i].code = ngOptionCodeInterfaceFilter + scratch[i].raw = append([]byte{0}, []byte(intf.Filter)...) + i++ + } + if intf.OS != "" { + scratch[i].code = ngOptionCodeInterfaceOS + scratch[i].raw = intf.OS + i++ + } + if intf.TimestampOffset != 0 { + scratch[i].code = ngOptionCodeInterfaceTimestampOffset + scratch[i].raw = intf.TimestampOffset + i++ + } + scratch[i].code = ngOptionCodeInterfaceTimestampResolution + scratch[i].raw = uint8(9) // fix resolution to nanoseconds (time.Time) in decimal + i++ + options := scratch[:i] + + length := prepareNgOptions(options) + + 16 + // header + 4 // trailer + + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ngBlockTypeInterfaceDescriptor)) + binary.LittleEndian.PutUint32(w.buf[4:8], length) + binary.LittleEndian.PutUint16(w.buf[8:10], uint16(intf.LinkType)) + binary.LittleEndian.PutUint16(w.buf[10:12], 0) // reserved value + binary.LittleEndian.PutUint32(w.buf[12:16], intf.SnapLength) + if _, err := w.w.Write(w.buf[:16]); err != nil { + return 0, err + } + + if err := w.writeOptions(options); err != nil { + return 0, err + } + + binary.LittleEndian.PutUint32(w.buf[0:4], length) + _, err = w.w.Write(w.buf[:4]) + return id, err +} + +// WriteInterfaceStats writes the given interface statistics for the given interface id to the file. Empty values are not written. +func (w *NgWriter) WriteInterfaceStats(intf int, stats NgInterfaceStatistics) error { + if intf >= int(w.intf) || intf < 0 { + return fmt.Errorf("Can't send statistics for non existent interface %d; have only %d interfaces", intf, w.intf) + } + + var scratch [4]ngOption + i := 0 + if !stats.StartTime.IsZero() { + scratch[i].code = ngOptionCodeInterfaceStatisticsStartTime + scratch[i].raw = stats.StartTime + i++ + } + if !stats.EndTime.IsZero() { + scratch[i].code = ngOptionCodeInterfaceStatisticsEndTime + scratch[i].raw = stats.EndTime + i++ + } + if stats.PacketsDropped != NgNoValue64 { + scratch[i].code = ngOptionCodeInterfaceStatisticsInterfaceDropped + scratch[i].raw = stats.PacketsDropped + i++ + } + if stats.PacketsReceived != NgNoValue64 { + scratch[i].code = ngOptionCodeInterfaceStatisticsInterfaceReceived + scratch[i].raw = stats.PacketsReceived + i++ + } + options := scratch[:i] + + length := prepareNgOptions(options) + 24 + + ts := stats.LastUpdate.UnixNano() + if stats.LastUpdate.IsZero() { + ts = 0 + } + + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ngBlockTypeInterfaceStatistics)) + binary.LittleEndian.PutUint32(w.buf[4:8], length) + binary.LittleEndian.PutUint32(w.buf[8:12], uint32(intf)) + binary.LittleEndian.PutUint32(w.buf[12:16], uint32(ts>>32)) + binary.LittleEndian.PutUint32(w.buf[16:20], uint32(ts)) + if _, err := w.w.Write(w.buf[:20]); err != nil { + return err + } + + if err := w.writeOptions(options); err != nil { + return err + } + + binary.LittleEndian.PutUint32(w.buf[0:4], length) + _, err := w.w.Write(w.buf[:4]) + return err +} + +// WritePacket writes out packet with the given data and capture info. The given InterfaceIndex must already be added to the file. InterfaceIndex 0 is automatically added by the NewWriter* methods. +func (w *NgWriter) WritePacket(ci gopacket.CaptureInfo, data []byte) error { + return w.WritePacketWithOptions(ci, data, NgPacketOptions{}) +} + +// WritePacketWithOptions writes out packet with the given data, capture info and options. The given InterfaceIndex must already be added to the file. InterfaceIndex 0 is automatically added by the NewWriter* methods. +func (w *NgWriter) WritePacketWithOptions(ci gopacket.CaptureInfo, data []byte, opts NgPacketOptions) error { + if ci.InterfaceIndex >= int(w.intf) || ci.InterfaceIndex < 0 { + return fmt.Errorf("Can't send statistics for non existent interface %d; have only %d interfaces", ci.InterfaceIndex, w.intf) + } + if ci.CaptureLength != len(data) { + return fmt.Errorf("capture length %d does not match data length %d", ci.CaptureLength, len(data)) + } + if ci.CaptureLength > ci.Length { + return fmt.Errorf("invalid capture info %+v: capture length > length", ci) + } + + options := opts.toNgOptions() + length := prepareNgOptions(options) + + 28 + // metadata + uint32(len(data)) + + 4 // trailer + padding := (4 - length&3) & 3 + length += padding + + ts := ci.Timestamp.UnixNano() + + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ngBlockTypeEnhancedPacket)) + binary.LittleEndian.PutUint32(w.buf[4:8], length) + binary.LittleEndian.PutUint32(w.buf[8:12], uint32(ci.InterfaceIndex)) + binary.LittleEndian.PutUint32(w.buf[12:16], uint32(ts>>32)) + binary.LittleEndian.PutUint32(w.buf[16:20], uint32(ts)) + binary.LittleEndian.PutUint32(w.buf[20:24], uint32(ci.CaptureLength)) + binary.LittleEndian.PutUint32(w.buf[24:28], uint32(ci.Length)) + + if _, err := w.w.Write(w.buf[:28]); err != nil { + return err + } + + if _, err := w.w.Write(data); err != nil { + return err + } + if padding > 0 { + binary.LittleEndian.PutUint32(w.buf[:4], 0) + if _, err := w.w.Write(w.buf[:padding]); err != nil { + return err + } + } + + if err := w.writeOptions(options); err != nil { + return err + } + + binary.LittleEndian.PutUint32(w.buf[:4], length) + _, err := w.w.Write(w.buf[:4]) + return err +} + +// Flush writes out buffered data to the storage media. Must be called before closing the underlying file. +func (w *NgWriter) Flush() error { + return w.w.Flush() +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite_dsb.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite_dsb.go new file mode 100644 index 0000000000..f0c258e760 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/ngwrite_dsb.go @@ -0,0 +1,110 @@ +// Copyright 2018 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. +// author: CFC4N + +package pcapgo + +import ( + "encoding/binary" +) + +/* + Decryption Secrets Block (DSB) memory layout. + via https://github.com/pcapng/pcapng/blob/master/draft-tuexen-opsawg-pcapng.md + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 0 | Block Type = 0x0000000A | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 | Block Total Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 8 | Secrets Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +12 | Secrets Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +16 / / + / Secrets Data / + / (variable length, padded to 32 bits) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + / Options (variable) / + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / Block Total Length / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Block Type: The block type of the Decryption Secrets Block is 10. + + Block Total Length: total size of this block, as described in {{section_block}}. + + Secrets Type (32 bits): an unsigned integer identifier that describes the format of the following Secrets field. Requests for new Secrets Type codes should be made by creating a pull request to update this document as described in {{section_block_code_registry}}. + + Secrets Length (32 bits): an unsigned integer that indicates the size of the following Secrets field, without any padding octets. + + Secrets Data: binary data containing secrets, padded to a 32 bit boundary. + + Options: optionally, a list of options (formatted according to the rules defined in {{section_opt}}) can be present. No DSB-specific options are currently defined. +*/ + +const ( + PcapngBlockHeadersize = 8 // block type + block total length + PcapngDecryptionSecretsBlockSize = 8 // Secrets type + Secrets length +) + +// pcapngBlockHeader is the header of a pcapng block. +type pcapngBlockHeader struct { + blockType uint32 + blockTotalLength uint32 +} + +// pcapngDecryptionSecretsBlock is the header of a section. +type pcapngDecryptionSecretsBlock struct { + secretsType uint32 + secretsLength uint32 +} + +// WriteDecryptionSecretsBlock writes a Decryption Secrets Block to the writer. +func (w *NgWriter) WriteDecryptionSecretsBlock(secretType uint32, secretPayload []byte) error { + + switch secretType { + case DSB_SECRETS_TYPE_SSH, DSB_SECRETS_TYPE_ZIGBEE_NWK_KEY, DSB_SECRETS_TYPE_WIREGUARD, DSB_SECRETS_TYPE_ZIGBEE_APS_KEY, DSB_SECRETS_TYPE_TLS: + default: + // unknown secrets type + return ErrUnknownSecretsType + } + + secretPayloadLen := len(secretPayload) + padding := (4 - secretPayloadLen&3) & 3 + + // via https://github.com/wireshark/wireshark/blob/885d6b7f731760f4a76e0f257af57d03934986ed/wiretap/pcapng.c#L5233 + // langth = MIN_DSB_SIZE + secretPayloadLen + padding + // MIN_DSB_SIZE = MIN_BLOCK_SIZE + PcapngDecryptionSecretsBlockSize + // MIN_BLOCK_SIZE = PcapngBlockHeadersize + 4 + // + length := uint32(PcapngBlockHeadersize + 4 + PcapngDecryptionSecretsBlockSize + secretPayloadLen + padding) + + // write block header + binary.LittleEndian.PutUint32(w.buf[:4], uint32(ngBlockTypeDecryptionSecrets)) + binary.LittleEndian.PutUint32(w.buf[4:8], length) + + // write decryption secrets block + binary.LittleEndian.PutUint32(w.buf[8:12], secretType) + binary.LittleEndian.PutUint32(w.buf[12:16], uint32(secretPayloadLen)) + + if _, err := w.w.Write(w.buf[:16]); err != nil { + return err + } + + // write secrets data + if _, err := w.w.Write(secretPayload); err != nil { + return err + } + + binary.LittleEndian.PutUint32(w.buf[:4], 0) + _, err := w.w.Write(w.buf[4-padding : 8]) // padding + length + return err +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/pcapng.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/pcapng.go new file mode 100644 index 0000000000..fea6467875 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/pcapng.go @@ -0,0 +1,444 @@ +// Copyright 2018 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. + +package pcapgo + +import ( + "errors" + "math" + "net" + "net/netip" + "time" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +// ErrNgVersionMismatch gets returned for unknown pcapng section versions. This can only happen if ReaderOptions.SkipUnknownVersion == false +var ErrNgVersionMismatch = errors.New("Unknown pcapng Version in Section Header") + +// ErrNgLinkTypeMismatch gets returned if the link type of an interface is not the same as the link type from the first interface. This can only happen if ReaderOptions.ErrorOnMismatchingLinkType == true && ReaderOptions.WantMixedLinkType == false +var ErrNgLinkTypeMismatch = errors.New("Link type of current interface is different from first one") + +const ( + ngByteOrderMagic = 0x1A2B3C4D + + // We can handle only version 1.0 + ngVersionMajor = 1 + ngVersionMinor = 0 +) + +type ngBlockType uint32 + +const ( + ngBlockTypeInterfaceDescriptor ngBlockType = 1 // Interface description block + ngBlockTypePacket ngBlockType = 2 // Packet block (deprecated) + ngBlockTypeSimplePacket ngBlockType = 3 // Simple packet block + ngBlockTypeNameResolution ngBlockType = 4 // Name resolution block + ngBlockTypeInterfaceStatistics ngBlockType = 5 // Interface statistics block + ngBlockTypeEnhancedPacket ngBlockType = 6 // Enhanced packet block + ngBlockTypeDecryptionSecrets ngBlockType = 0x0000000A // Decryption secrets block + ngBlockTypeSectionHeader ngBlockType = 0x0A0D0D0A // Section header block (same in both endians) +) + +const ( + /* + * Type describing the format of Decryption Secrets Block (DSB). + */ + DSB_SECRETS_TYPE_TLS uint32 = 0x544c534b /* TLS Key Log */ + DSB_SECRETS_TYPE_SSH uint32 = 0x5353484b /* SSH Key Log */ + DSB_SECRETS_TYPE_WIREGUARD uint32 = 0x57474b4c /* WireGuard Key Log */ + DSB_SECRETS_TYPE_ZIGBEE_NWK_KEY uint32 = 0x5a4e574b /* Zigbee NWK Key */ + DSB_SECRETS_TYPE_ZIGBEE_APS_KEY uint32 = 0x5a415053 /* Zigbee APS Key */ +) + +// define error types for DSB +var ( + ErrUnknownSecretsType = errors.New("Unknown Decryption Secrets Block (DSB) type") +) + +type ngOptionCode uint16 + +const ( + ngOptionCodeEndOfOptions ngOptionCode = iota // end of options. must be at the end of options in a block + ngOptionCodeComment // comment + ngOptionCodeHardware // description of the hardware + ngOptionCodeOS // name of the operating system + ngOptionCodeUserApplication // name of the application +) + +const ( + ngOptionCodeInterfaceName ngOptionCode = iota + 2 // interface name + ngOptionCodeInterfaceDescription // interface description + ngOptionCodeInterfaceIPV4Address // IPv4 network address and netmask for the interface + ngOptionCodeInterfaceIPV6Address // IPv6 network address and prefix length for the interface + ngOptionCodeInterfaceMACAddress // interface hardware MAC address + ngOptionCodeInterfaceEUIAddress // interface hardware EUI address + ngOptionCodeInterfaceSpeed // interface speed in bits/s + ngOptionCodeInterfaceTimestampResolution // timestamp resolution + ngOptionCodeInterfaceTimezone // time zone + ngOptionCodeInterfaceFilter // capture filter + ngOptionCodeInterfaceOS // operating system + ngOptionCodeInterfaceFCSLength // length of the Frame Check Sequence in bits + ngOptionCodeInterfaceTimestampOffset // offset (in seconds) that must be added to packet timestamp +) + +const ( + ngOptionCodeInterfaceStatisticsStartTime ngOptionCode = iota + 2 // Start of capture + ngOptionCodeInterfaceStatisticsEndTime // End of capture + ngOptionCodeInterfaceStatisticsInterfaceReceived // Packets received by physical interface + ngOptionCodeInterfaceStatisticsInterfaceDropped // Packets dropped by physical interface + ngOptionCodeInterfaceStatisticsFilterAccept // Packets accepted by filter + ngOptionCodeInterfaceStatisticsOSDrop // Packets dropped by operating system + ngOptionCodeInterfaceStatisticsDelivered // Packets delivered to user +) + +const ( + // Name Resolution Block: record types + ngNameRecordEnd uint16 = iota // End of name resolution records + ngNameRecordIPv4 // IPv4 record + ngNameRecordIPv6 // IPv6 record + ngNameRecordEUI48 // EUI-48 record + ngNameRecordEUI64 // EUI-64 record +) + +const ( + // Enhanced Packet Block + ngOptionCodeEpbFlags ngOptionCode = iota + 2 // link-layer information + ngOptionCodeEpbHash // hash of the packet + ngOptionCodeEpbDropCount // number of packets lost + ngOptionCodeEpbPacketID // uniquely identifies the packet + ngOptionCodeEpbQueue // identifies on which queue of the interface the specific packet was received + ngOptionCodeEpbVerdict // a verdict of the packet +) + +// NgEpbFlag Enhanced Packet Block Flags Word +type NgEpbFlag uint32 + +const ( + NgEpbFlagDirectionMask NgEpbFlag = 0b11 // bits 0-1 + NgEpbFlagDirectionUnknown NgEpbFlag = 0b00 // 00 = information not available + NgEpbFlagDirectionInbound NgEpbFlag = 0b01 // 01 = inbound + NgEpbFlagDirectionOutbound NgEpbFlag = 0b10 // 10 = outbound +) + +const ( + NgEpbFlagReceptionTypeMask NgEpbFlag = 0b11100 // bits 2-4 + NgEpbFlagReceptionTypeNotSpecified NgEpbFlag = 0b00000 // 000 = not specified + NgEpbFlagReceptionTypeUnicast NgEpbFlag = 0b00100 // 001 = unicast + NgEpbFlagReceptionTypeMulticast NgEpbFlag = 0b01000 // 010 = multicast + NgEpbFlagReceptionTypeBroadcast NgEpbFlag = 0b01100 // 011 = broadcast + NgEpbFlagReceptionTypePromiscuous NgEpbFlag = 0b10000 // 100 = promiscuous +) + +const ( + NgEpbFlagFCSLengthMask NgEpbFlag = 0b1111100000 // bits 5-8 + NgEpbFlagFCSLengthNotAvailable NgEpbFlag = 0 // 0000 if this information is not available +) + +const ( + NgEpbFlagLinkLayerDependentErrorMask NgEpbFlag = 0xFFFF0000 // bits 16-31 + NgEpbFlagLinkLayerDependentErrorSymbol NgEpbFlag = 1 << 31 // Bit 31 = symbol error + NgEpbFlagLinkLayerDependentErrorPreamble NgEpbFlag = 1 << 30 // Bit 30 = preamble error + NgEpbFlagLinkLayerDependentErrorStartFrameDelimiter NgEpbFlag = 1 << 29 // Bit 29 = Start Frame Delimiter error + NgEpbFlagLinkLayerDependentErrorUnalignedFrame NgEpbFlag = 1 << 28 // Bit 28 = unaligned frame error + NgEpbFlagLinkLayerDependentErrorInterFrameGap NgEpbFlag = 1 << 27 // Bit 27 = wrong Inter Frame Gap error + NgEpbFlagLinkLayerDependentErrorPacketTooShort NgEpbFlag = 1 << 26 // Bit 26 = packet too short error + NgEpbFlagLinkLayerDependentErrorPacketTooLong NgEpbFlag = 1 << 25 // Bit 25 = packet too long error + NgEpbFlagLinkLayerDependentErrorCRC NgEpbFlag = 1 << 24 // Bit 24 = CRC error +) + +type NgEpbFlags struct { + Direction NgEpbFlag + Reception NgEpbFlag + FCSLen NgEpbFlag + LinkLayerErr NgEpbFlag +} + +func NewNgEpbFlagFCSLength(n uint8) NgEpbFlag { + return NgEpbFlag(n<<5) & NgEpbFlagFCSLengthMask +} + +func (f *NgEpbFlags) ToUint32() uint32 { + var result uint32 + result = uint32(f.Direction) & uint32(NgEpbFlagDirectionMask) + result |= uint32(f.Reception) & uint32(NgEpbFlagReceptionTypeMask) + result |= uint32(f.FCSLen) & uint32(NgEpbFlagFCSLengthMask) + result |= uint32(f.LinkLayerErr) & uint32(NgEpbFlagLinkLayerDependentErrorMask) + return result +} + +func (f *NgEpbFlags) FromUint32(value uint32) { + f.Direction = NgEpbFlag(value & uint32(NgEpbFlagDirectionMask)) + f.Reception = NgEpbFlag(value & uint32(NgEpbFlagReceptionTypeMask)) + f.FCSLen = NgEpbFlag(value & uint32(NgEpbFlagFCSLengthMask)) + f.LinkLayerErr = NgEpbFlag(value & uint32(NgEpbFlagLinkLayerDependentErrorMask)) +} + +type NgEpbHashAlgorithm uint8 + +const ( + NgEpbHashAlgorithm2sComplement NgEpbHashAlgorithm = iota // 2s complement (algorithm octet = 0, size = XXX) + NgEpbHashAlgorithmXOR // XOR (algorithm octet = 1, size=XXX) + NgEpbHashAlgorithmCRC32 // CRC32 (algorithm octet = 2, size = 4) + NgEpbHashAlgorithmMD5 // MD-5 (algorithm octet = 3, size = 16) + NgEpbHashAlgorithmSHA1 // SHA-1 (algorithm octet = 4, size = 20) + NgEpbHashAlgorithmToeplitz // Toeplitz (algorithm octet = 5, size = 4) +) + +type NgEpbHash struct { + Algorithm NgEpbHashAlgorithm + Hash []byte +} + +func (h NgEpbHash) toBytes() []byte { + v := []byte{byte(h.Algorithm)} + v = append(v, h.Hash...) + return v +} + +type NgEpbVerdictType uint8 + +const ( + NgEpbVerdictTypeHardware NgEpbVerdictType = iota // Hardware (type octet = 0, size = variable) + NgEpbVerdictTypeLinuxeBPFTC // Linux_eBPF_TC (type octet = 1, size = 8 (64-bit unsigned integer) + NgEpbVerdictTypeLinuxeBPFXDP // Linux_eBPF_XDP (type octet = 2, size = 8 (64-bit unsigned integer) +) + +type NgEpbVerdict struct { + Type NgEpbVerdictType + Data []byte +} + +func (vd NgEpbVerdict) toBytes() []byte { + v := []byte{byte(vd.Type)} + v = append(v, vd.Data...) + return v +} + +// ngOption is a pcapng option +type ngOption struct { + code ngOptionCode + value []byte + raw interface{} + length uint16 +} + +// ngBlock is a pcapng block header +type ngBlock struct { + typ ngBlockType + length uint32 // remaining length of block +} + +// NgResolution represents a pcapng timestamp resolution +type NgResolution uint8 + +// Binary returns true if the timestamp resolution is a negative power of two. Otherwise NgResolution is a negative power of 10. +func (r NgResolution) Binary() bool { + if r&0x80 == 0x80 { + return true + } + return false +} + +// Exponent returns the negative exponent of the resolution. +func (r NgResolution) Exponent() uint8 { + return uint8(r) & 0x7f +} + +// ToTimestampResolution converts an NgResolution to a gopaket.TimestampResolution +func (r NgResolution) ToTimestampResolution() (ret gopacket.TimestampResolution) { + if r.Binary() { + ret.Base = 2 + } else { + ret.Base = 10 + } + ret.Exponent = -int(r.Exponent()) + return +} + +// NgNoValue64 is a placeholder for an empty numeric 64 bit value. +const NgNoValue64 = math.MaxUint64 + +// NgInterfaceStatistics hold the statistic for an interface at a single point in time. These values are already supposed to be accumulated. Most pcapng files contain this information at the end of the file/section. +type NgInterfaceStatistics struct { + // LastUpdate is the last time the statistics were updated. + LastUpdate time.Time + // StartTime is the time packet capture started on this interface. This value might be zero if this option is missing. + StartTime time.Time + // EndTime is the time packet capture ended on this interface This value might be zero if this option is missing. + EndTime time.Time + // Comment can be an arbitrary comment. This value might be empty if this option is missing. + Comment string + // PacketsReceived are the number of received packets. This value might be NoValue64 if this option is missing. + PacketsReceived uint64 + // PacketsReceived are the number of received packets. This value might be NoValue64 if this option is missing. + PacketsDropped uint64 +} + +var ngEmptyStatistics = NgInterfaceStatistics{ + PacketsReceived: NgNoValue64, + PacketsDropped: NgNoValue64, +} + +// NgInterface holds all the information of a pcapng interface. +type NgInterface struct { + // Name is the name of the interface. This value might be empty if this option is missing. + Name string + // Comment can be an arbitrary comment. This value might be empty if this option is missing. + Comment string + // Description is a description of the interface. This value might be empty if this option is missing. + Description string + // Filter is the filter used during packet capture. This value might be empty if this option is missing. + Filter string + // OS is the operating system this interface was controlled by. This value might be empty if this option is missing. + OS string + // LinkType is the linktype of the interface. + LinkType layers.LinkType + // TimestampResolution is the timestamp resolution of the packets in the pcapng file belonging to this interface. + TimestampResolution NgResolution + // TimestampResolution is the timestamp offset in seconds of the packets in the pcapng file belonging to this interface. + TimestampOffset uint64 + // SnapLength is the maximum packet length captured by this interface. 0 for unlimited + SnapLength uint32 + // Statistics holds the interface statistics + Statistics NgInterfaceStatistics + + secondMask uint64 + scaleUp uint64 + scaleDown uint64 +} + +// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution. +func (i NgInterface) Resolution() gopacket.TimestampResolution { + return i.TimestampResolution.ToTimestampResolution() +} + +// NgSectionInfo contains additional information of a pcapng section +type NgSectionInfo struct { + // Hardware is the hardware this file was generated on. This value might be empty if this option is missing. + Hardware string + // OS is the operating system this file was generated on. This value might be empty if this option is missing. + OS string + // Application is the user space application this file was generated with. This value might be empty if this option is missing. + Application string + // Comment can be an arbitrary comment. This value might be empty if this option is missing. + Comment string +} + +// NgPacketOptions contains additional information of a pcapng packet +type NgPacketOptions struct { + // Comments can be multiple arbitrary comments. This value might be empty if this option is missing. + Comments []string + // Flags is a 32-bit flags word containing link-layer information + Flags *NgEpbFlags + // Hashes contains a list of hash of the packet + Hashes []NgEpbHash + // DropCount is a 64-bit unsigned integer value specifying the number of packets lost (by the interface and the operating system) + // between this packet and the preceding one for the same interface or, for the first packet for an interface, + // between this packet and the start of the capture process + DropCount *uint64 + // PacketID is a 64-bit unsigned integer that uniquely identifies the packet + PacketID *uint64 + // Queue is a 32-bit unsigned integer that identifies on which queue of the interface the specific packet was received + Queue *uint32 + // Verdicts stores a list of verdict of the packet + Verdicts []NgEpbVerdict +} + +func (opts NgPacketOptions) toNgOptions() []ngOption { + var ngOpts []ngOption + for _, comment := range opts.Comments { + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeComment, + raw: comment, + length: uint16(len(comment)), + }) + } + if opts.Flags != nil { + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbFlags, + raw: opts.Flags.ToUint32(), + length: 4, + }) + } + for _, hash := range opts.Hashes { + v := hash.toBytes() + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbHash, + raw: v, + length: uint16(len(v)), + }) + } + if opts.DropCount != nil { + v := *opts.DropCount + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbDropCount, + raw: v, + length: 8, + }) + } + if opts.PacketID != nil { + v := *opts.PacketID + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbPacketID, + raw: v, + length: 8, + }) + } + if opts.Queue != nil { + v := *opts.Queue + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbQueue, + raw: v, + length: 4, + }) + } + for _, verdict := range opts.Verdicts { + v := verdict.toBytes() + ngOpts = append(ngOpts, ngOption{ + code: ngOptionCodeEpbVerdict, + raw: v, + length: uint16(len(v)), + }) + } + + return ngOpts +} + +type ngAddressType uint16 + +const ( + ngAddressIPv4 uint16 = iota + ngAddressIPv6 + ngAddressEUI48 + ngAddressEUI64 +) + +type NgAddress interface { + Len() int +} + +type NgIPAddress struct { + Addr netip.Addr +} + +func (addr *NgIPAddress) Len() int { + return addr.Addr.BitLen() / 8 +} + +type NgEUIAddress struct { + Addr net.HardwareAddr +} + +func (addr *NgEUIAddress) Len() int { + return len(addr.Addr) +} + +type NgNameRecord struct { + Addr NgAddress + Names []string +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/read.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/read.go new file mode 100644 index 0000000000..243489a4dc --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/read.go @@ -0,0 +1,231 @@ +// Copyright 2014 Damjan Cvetko. 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 pcapgo + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "time" + + "bufio" + "compress/gzip" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +// Reader wraps an underlying io.Reader to read packet data in PCAP +// format. See http://wiki.wireshark.org/Development/LibpcapFileFormat +// for information on the file format. +// +// We currenty read v2.4 file format with nanosecond and microsecdond +// timestamp resolution in little-endian and big-endian encoding. +// +// If the PCAP data is gzip compressed it is transparently uncompressed +// by wrapping the given io.Reader with a gzip.Reader. +type Reader struct { + r io.Reader + byteOrder binary.ByteOrder + nanoSecsFactor uint32 + versionMajor uint16 + versionMinor uint16 + // timezone + // sigfigs + snaplen uint32 + linkType layers.LinkType + // reusable buffer + buf [16]byte + // buffer for ZeroCopyReadPacketData + packetBuf []byte +} + +const magicNanoseconds = 0xA1B23C4D +const magicMicrosecondsBigendian = 0xD4C3B2A1 +const magicNanosecondsBigendian = 0x4D3CB2A1 + +const magicGzip1 = 0x1f +const magicGzip2 = 0x8b + +// NewReader returns a new reader object, for reading packet data from +// the given reader. The reader must be open and header data is +// read from it at this point. +// If the file format is not supported an error is returned +// +// // Create new reader: +// f, _ := os.Open("/tmp/file.pcap") +// defer f.Close() +// r, err := NewReader(f) +// data, ci, err := r.ReadPacketData() +func NewReader(r io.Reader) (*Reader, error) { + ret := Reader{r: r} + if err := ret.readHeader(); err != nil { + return nil, err + } + return &ret, nil +} + +func (r *Reader) readHeader() error { + br := bufio.NewReader(r.r) + gzipMagic, err := br.Peek(2) + if err != nil { + return err + } + + if gzipMagic[0] == magicGzip1 && gzipMagic[1] == magicGzip2 { + if r.r, err = gzip.NewReader(br); err != nil { + return err + } + } else { + r.r = br + } + + buf := make([]byte, 24) + if n, err := io.ReadFull(r.r, buf); err != nil { + return err + } else if n < 24 { + return errors.New("Not enough data for read") + } + if magic := binary.LittleEndian.Uint32(buf[0:4]); magic == magicNanoseconds { + r.byteOrder = binary.LittleEndian + r.nanoSecsFactor = 1 + } else if magic == magicNanosecondsBigendian { + r.byteOrder = binary.BigEndian + r.nanoSecsFactor = 1 + } else if magic == magicMicroseconds { + r.byteOrder = binary.LittleEndian + r.nanoSecsFactor = 1000 + } else if magic == magicMicrosecondsBigendian { + r.byteOrder = binary.BigEndian + r.nanoSecsFactor = 1000 + } else { + return fmt.Errorf("Unknown magic %x", magic) + } + if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor { + return fmt.Errorf("Unknown major version %d", r.versionMajor) + } + if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor { + return fmt.Errorf("Unknown minor version %d", r.versionMinor) + } + // ignore timezone 8:12 and sigfigs 12:16 + r.snaplen = r.byteOrder.Uint32(buf[16:20]) + r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24])) + return nil +} + +// ReadPacketData reads next packet from file. +func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + if ci, err = r.readPacketHeader(); err != nil { + return + } + if ci.CaptureLength > int(r.snaplen) { + err = fmt.Errorf("capture length exceeds snap length: %d > %d", ci.CaptureLength, r.snaplen) + return + } + if ci.CaptureLength > ci.Length { + err = fmt.Errorf("capture length exceeds original packet length: %d > %d", ci.CaptureLength, ci.Length) + return + } + data = make([]byte, ci.CaptureLength) + _, err = io.ReadFull(r.r, data) + return data, ci, err +} + +// ZeroCopyReadPacketData reads next packet from file. The data buffer is owned by the Reader, +// and each call to ZeroCopyReadPacketData invalidates data returned by the previous one. +// +// It is not true zero copy, as data is still copied from the underlying reader. However, +// this method avoids allocating heap memory for every packet. +func (r *Reader) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + if ci, err = r.readPacketHeader(); err != nil { + return + } + if ci.CaptureLength > int(r.snaplen) { + err = fmt.Errorf("capture length exceeds snap length: %d > %d", ci.CaptureLength, r.snaplen) + return + } + if ci.CaptureLength > ci.Length { + err = fmt.Errorf("capture length exceeds original packet length: %d > %d", ci.CaptureLength, ci.Length) + return + } + + if cap(r.packetBuf) < ci.CaptureLength { + snaplen := int(r.snaplen) + if snaplen < ci.CaptureLength { + snaplen = ci.CaptureLength + } + r.packetBuf = make([]byte, snaplen) + } + data = r.packetBuf[:ci.CaptureLength] + _, err = io.ReadFull(r.r, data) + return data, ci, err +} + +func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) { + if _, err = io.ReadFull(r.r, r.buf[:]); err != nil { + return + } + ci.Timestamp = time.Unix(int64(r.byteOrder.Uint32(r.buf[0:4])), int64(r.byteOrder.Uint32(r.buf[4:8])*r.nanoSecsFactor)).UTC() + ci.CaptureLength = int(r.byteOrder.Uint32(r.buf[8:12])) + ci.Length = int(r.byteOrder.Uint32(r.buf[12:16])) + return +} + +// LinkType returns network, as a layers.LinkType. +func (r *Reader) LinkType() layers.LinkType { + return r.linkType +} + +// Snaplen returns the snapshot length of the capture file. +func (r *Reader) Snaplen() uint32 { + return r.snaplen +} + +// SetSnaplen sets the snapshot length of the capture file. +// +// This is useful when a pcap file contains packets bigger than then snaplen. +// Pcapgo will error when reading packets bigger than snaplen, then it dumps those +// packets and reads the next 16 bytes, which are part of the "faulty" packet's payload, but pcapgo +// thinks it's the next header, which is probably also faulty because it's not really a packet header. +// This can lead to a lot of faulty reads. +// +// The SetSnaplen function can be used to set a bigger snaplen to prevent those read errors. +// +// This snaplen situation can happen when a pcap writer doesn't truncate packets to the snaplen size while writing packets to file. +// E.g. In Python, dpkt.pcap.Writer sets snaplen by default to 1500 (https://dpkt.readthedocs.io/en/latest/api/api_auto.html#dpkt.pcap.Writer) +// but doesn't enforce this when writing packets (https://dpkt.readthedocs.io/en/latest/_modules/dpkt/pcap.html#Writer.writepkt). +// When reading, tools like tcpdump, tcpslice, mergecap and wireshark ignore the snaplen and use +// their own defined snaplen. +// E.g. When reading packets, tcpdump defines MAXIMUM_SNAPLEN (https://github.com/the-tcpdump-group/tcpdump/blob/6e80fcdbe9c41366df3fa244ffe4ac8cce2ab597/netdissect.h#L290) +// and uses it (https://github.com/the-tcpdump-group/tcpdump/blob/66384fa15b04b47ad08c063d4728df3b9c1c0677/print.c#L343-L358). +// +// For further reading: +// - https://github.com/the-tcpdump-group/tcpdump/issues/389 +// - https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8808 +// - https://www.wireshark.org/lists/wireshark-dev/201307/msg00061.html +// - https://github.com/wireshark/wireshark/blob/bfd51199e707c1d5c28732be34b44a9ee8a91cd8/wiretap/pcap-common.c#L723-L742 +// - https://github.com/wireshark/wireshark/blob/f07fb6cdfc0904905627707b88450054e921f092/wiretap/libpcap.c#L592-L598 +// - https://github.com/wireshark/wireshark/blob/f07fb6cdfc0904905627707b88450054e921f092/wiretap/libpcap.c#L714-L727 +// - https://github.com/the-tcpdump-group/tcpdump/commit/d033c1bc381c76d13e4aface97a4f4ec8c3beca2 +// - https://github.com/the-tcpdump-group/tcpdump/blob/88e87cb2cb74c5f939792171379acd9e0efd8b9a/netdissect.h#L263-L290 +func (r *Reader) SetSnaplen(newSnaplen uint32) { + r.snaplen = newSnaplen +} + +// Reader formater +func (r *Reader) String() string { + return fmt.Sprintf("PcapFile maj: %x min: %x snaplen: %d linktype: %s", r.versionMajor, r.versionMinor, r.snaplen, r.linkType) +} + +// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution. +func (r *Reader) Resolution() gopacket.TimestampResolution { + if r.nanoSecsFactor == 1000 { + return gopacket.TimestampResolutionMicrosecond + } + return gopacket.TimestampResolutionNanosecond +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/snoop.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/snoop.go new file mode 100644 index 0000000000..bbfc901bf3 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/snoop.go @@ -0,0 +1,170 @@ +// 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. + +package pcapgo + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "time" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +const snoopMagic uint64 = 0x736e6f6f70000000 //8 byte in big endian +const snoopVersion uint32 = 2 +const maxCaptureLen int = 4096 + +// Errors +const unknownMagic = "Unknown Snoop Magic Bytes" +const unknownVersion = "Unknown Snoop Format Version" +const unkownLinkType = "Unknown Link Type" +const originalLenExceeded = "Capture length exceeds original packet length" +const captureLenExceeded = "Capture length exceeds max capture length" + +type snoopHeader struct { + Version uint32 + linkType uint32 +} + +// SnoopReader wraps an underlying io.SnoopReader to read packet data in SNOOP +// format. See https://tools.ietf.org/html/rfc1761 +// for information on the file format. +// We currenty read v2 file format and convert microsecond to nanoseconds +// byte order in big-endian encoding. +type SnoopReader struct { + r io.Reader + header snoopHeader + //reuseable + pad int + packetBuf []byte + buf [24]byte +} + +var ( + layerTypes = map[uint32]layers.LinkType{ + 0: layers.LinkTypeEthernet, // IEEE 802.3 + 2: layers.LinkTypeTokenRing, // IEEE 802.5 Token Ring + 4: layers.LinkTypeEthernet, // Ethernet + 5: layers.LinkTypeC_HDLC, // HDLC + 8: layers.LinkTypeFDDI, // FDDI + /* + 10 - 4294967295 Unassigned + not supported: + 1 - IEEE 802.4 Token Bus + 3 - IEEE 802.6 Metro Net + 6 - Character Synchronous + 7 - IBM Channel-to-Channel + 9 - Other + */ + } +) + +// LinkType return the mapped gopacket LinkType +func (r *SnoopReader) LinkType() (*layers.LinkType, error) { + if _, ok := layerTypes[r.header.linkType]; ok { + lt := layerTypes[r.header.linkType] + return <, nil + } + return nil, fmt.Errorf("%s, Code:%d", unkownLinkType, r.header.linkType) + +} + +// NewSnoopReader returns a new SnoopReader object, for reading packet data from +// the given SnoopReader. The SnoopReader must be open and header data is +// read from it at this point. +// If the file format is not supported an error is returned +func NewSnoopReader(r io.Reader) (*SnoopReader, error) { + ret := SnoopReader{r: r} + + if err := ret.readHeader(); err != nil { + return nil, err + } + return &ret, nil +} + +func (r *SnoopReader) readHeader() error { + buf := make([]byte, 16) + + if n, err := io.ReadFull(r.r, buf); err != nil { + return err + } else if n < 16 { + return errors.New("Not enough data for read") + } + + if magic := binary.BigEndian.Uint64(buf[0:8]); magic != snoopMagic { + return fmt.Errorf("%s: %x", unknownMagic, magic) + } + + if r.header.Version = binary.BigEndian.Uint32(buf[8:12]); r.header.Version != snoopVersion { + return fmt.Errorf("%s: %d", unknownVersion, r.header.Version) + } + + if r.header.linkType = binary.BigEndian.Uint32(buf[12:16]); r.header.linkType > 10 { + return fmt.Errorf("%s, Code:%d", unkownLinkType, r.header.linkType) + } + return nil +} + +func (r *SnoopReader) readPacketHeader() (ci gopacket.CaptureInfo, err error) { + + if _, err = io.ReadFull(r.r, r.buf[:]); err != nil { + return + } + // OriginalLength uint32 4 + // IncludedLength uint32 8 + // PacketRecordLength uint32 12 + // CumulativeDrops uint32 16 + // TimestampSeconds uint32 20 + // TimestampMicroseconds uint32 24 + + ci.Timestamp = time.Unix(int64(binary.BigEndian.Uint32(r.buf[16:20])), int64(binary.BigEndian.Uint32(r.buf[20:24])*1000)).UTC() + ci.Length = int(binary.BigEndian.Uint32(r.buf[0:4])) + ci.CaptureLength = int(binary.BigEndian.Uint32(r.buf[4:8])) + r.pad = int(binary.BigEndian.Uint32(r.buf[8:12])) - (24 + ci.Length) + + if ci.CaptureLength > ci.Length { + err = errors.New(originalLenExceeded) + return + } + + if ci.CaptureLength > maxCaptureLen { + err = errors.New(captureLenExceeded) + } + + return +} + +// ReadPacketData reads next packet data. +func (r *SnoopReader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + if ci, err = r.readPacketHeader(); err != nil { + return + } + data = make([]byte, ci.CaptureLength+r.pad) + _, err = io.ReadFull(r.r, data) + return data[:ci.CaptureLength], ci, err + +} + +// ZeroCopyReadPacketData reads next packet data. The data buffer is owned by the SnoopReader, +// and each call to ZeroCopyReadPacketData invalidates data returned by the previous one. +// +// It is not true zero copy, as data is still copied from the underlying SnoopReader. However, +// this method avoids allocating heap memory for every packet. +func (r *SnoopReader) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { + if ci, err = r.readPacketHeader(); err != nil { + return + } + + if cap(r.packetBuf) < ci.CaptureLength+r.pad { + r.packetBuf = make([]byte, ci.CaptureLength+r.pad) + } + _, err = io.ReadFull(r.r, r.packetBuf[:ci.CaptureLength+r.pad]) + return r.packetBuf[:ci.CaptureLength], ci, err +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/write.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/write.go new file mode 100644 index 0000000000..40b6e7d6fe --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/pcapgo/write.go @@ -0,0 +1,129 @@ +// 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 pcapgo + +import ( + "encoding/binary" + "fmt" + "io" + "time" + + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" +) + +// Writer wraps an underlying io.Writer to write packet data in PCAP +// format. See http://wiki.wireshark.org/Development/LibpcapFileFormat +// for information on the file format. +// +// For those that care, we currently write v2.4 files with nanosecond +// or microsecond timestamp resolution and little-endian encoding. +type Writer struct { + w io.Writer + tsScaler int + // Moving this into the struct seems to save an allocation for each call to writePacketHeader + buf [16]byte +} + +const magicMicroseconds = 0xA1B2C3D4 +const versionMajor = 2 +const versionMinor = 4 + +// NewWriterNanos returns a new writer object, for writing packet data out +// to the given writer. If this is a new empty writer (as opposed to +// an append), you must call WriteFileHeader before WritePacket. Packet +// timestamps are written with nanosecond precision. +// +// // Write a new file: +// f, _ := os.Create("/tmp/file.pcap") +// w := pcapgo.NewWriterNanos(f) +// w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this. +// w.WritePacket(gopacket.CaptureInfo{...}, data1) +// f.Close() +// // Append to existing file (must have same snaplen and linktype) +// f2, _ := os.OpenFile("/tmp/fileNano.pcap", os.O_APPEND, 0700) +// w2 := pcapgo.NewWriter(f2) +// // no need for file header, it's already written. +// w2.WritePacket(gopacket.CaptureInfo{...}, data2) +// f2.Close() +func NewWriterNanos(w io.Writer) *Writer { + return &Writer{w: w, tsScaler: nanosPerNano} +} + +// NewWriter returns a new writer object, for writing packet data out +// to the given writer. If this is a new empty writer (as opposed to +// an append), you must call WriteFileHeader before WritePacket. +// Packet timestamps are written witn microsecond precision. +// +// // Write a new file: +// f, _ := os.Create("/tmp/file.pcap") +// w := pcapgo.NewWriter(f) +// w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this. +// w.WritePacket(gopacket.CaptureInfo{...}, data1) +// f.Close() +// // Append to existing file (must have same snaplen and linktype) +// f2, _ := os.OpenFile("/tmp/file.pcap", os.O_APPEND, 0700) +// w2 := pcapgo.NewWriter(f2) +// // no need for file header, it's already written. +// w2.WritePacket(gopacket.CaptureInfo{...}, data2) +// f2.Close() +func NewWriter(w io.Writer) *Writer { + return &Writer{w: w, tsScaler: nanosPerMicro} +} + +// WriteFileHeader writes a file header out to the writer. +// This must be called exactly once per output. +func (w *Writer) WriteFileHeader(snaplen uint32, linktype layers.LinkType) error { + var buf [24]byte + if w.tsScaler == nanosPerMicro { + binary.LittleEndian.PutUint32(buf[0:4], magicMicroseconds) + } else { + binary.LittleEndian.PutUint32(buf[0:4], magicNanoseconds) + } + binary.LittleEndian.PutUint16(buf[4:6], versionMajor) + binary.LittleEndian.PutUint16(buf[6:8], versionMinor) + // bytes 8:12 stay 0 (timezone = UTC) + // bytes 12:16 stay 0 (sigfigs is always set to zero, according to + // http://wiki.wireshark.org/Development/LibpcapFileFormat + binary.LittleEndian.PutUint32(buf[16:20], snaplen) + binary.LittleEndian.PutUint32(buf[20:24], uint32(linktype)) + _, err := w.w.Write(buf[:]) + return err +} + +const nanosPerMicro = 1000 +const nanosPerNano = 1 + +func (w *Writer) writePacketHeader(ci gopacket.CaptureInfo) error { + t := ci.Timestamp + if t.IsZero() { + t = time.Now() + } + secs := t.Unix() + usecs := t.Nanosecond() / w.tsScaler + binary.LittleEndian.PutUint32(w.buf[0:4], uint32(secs)) + binary.LittleEndian.PutUint32(w.buf[4:8], uint32(usecs)) + binary.LittleEndian.PutUint32(w.buf[8:12], uint32(ci.CaptureLength)) + binary.LittleEndian.PutUint32(w.buf[12:16], uint32(ci.Length)) + _, err := w.w.Write(w.buf[:]) + return err +} + +// WritePacket writes the given packet data out to the file. +func (w *Writer) WritePacket(ci gopacket.CaptureInfo, data []byte) error { + if ci.CaptureLength != len(data) { + return fmt.Errorf("capture length %d does not match data length %d", ci.CaptureLength, len(data)) + } + if ci.CaptureLength > ci.Length { + return fmt.Errorf("invalid capture info %+v: capture length > length", ci) + } + if err := w.writePacketHeader(ci); err != nil { + return fmt.Errorf("error writing packet header: %v", err) + } + _, err := w.w.Write(data) + return err +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/runtests.sh b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/runtests.sh new file mode 100644 index 0000000000..61e95a4def --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/runtests.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +DIRS="afpacket layers pcap pcapgo tcpassembly tcpassembly/tcpreader reassembly routing ip4defrag bytediff macs routing defrag/lcmdefrag" +set -e +export CGO_ENABLED=1 +for subdir in $DIRS; do + pushd $subdir + sudo -E go test -v -count=1 . + popd +done diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/time.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/time.go new file mode 100644 index 0000000000..6d116cdfbc --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/time.go @@ -0,0 +1,72 @@ +// Copyright 2018 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. + +package gopacket + +import ( + "fmt" + "math" + "time" +) + +// TimestampResolution represents the resolution of timestamps in Base^Exponent. +type TimestampResolution struct { + Base, Exponent int +} + +func (t TimestampResolution) String() string { + return fmt.Sprintf("%d^%d", t.Base, t.Exponent) +} + +// ToDuration returns the smallest representable time difference as a time.Duration +func (t TimestampResolution) ToDuration() time.Duration { + if t.Base == 0 { + return 0 + } + if t.Exponent == 0 { + return time.Second + } + switch t.Base { + case 10: + return time.Duration(math.Pow10(t.Exponent + 9)) + case 2: + if t.Exponent < 0 { + return time.Second >> uint(-t.Exponent) + } + return time.Second << uint(t.Exponent) + default: + // this might loose precision + return time.Duration(float64(time.Second) * math.Pow(float64(t.Base), float64(t.Exponent))) + } +} + +// TimestampResolutionInvalid represents an invalid timestamp resolution +var TimestampResolutionInvalid = TimestampResolution{} + +// TimestampResolutionMillisecond is a resolution of 10^-3s +var TimestampResolutionMillisecond = TimestampResolution{10, -3} + +// TimestampResolutionMicrosecond is a resolution of 10^-6s +var TimestampResolutionMicrosecond = TimestampResolution{10, -6} + +// TimestampResolutionNanosecond is a resolution of 10^-9s +var TimestampResolutionNanosecond = TimestampResolution{10, -9} + +// TimestampResolutionNTP is the resolution of NTP timestamps which is 2^-32 ≈ 233 picoseconds +var TimestampResolutionNTP = TimestampResolution{2, -32} + +// TimestampResolutionCaptureInfo is the resolution used in CaptureInfo, which his currently nanosecond +var TimestampResolutionCaptureInfo = TimestampResolutionNanosecond + +// PacketSourceResolution is an interface for packet data sources that +// support reporting the timestamp resolution of the aqcuired timestamps. +// Returned timestamps will always have NanosecondTimestampResolution due +// to the use of time.Time, but scaling might have occured if acquired +// timestamps have a different resolution. +type PacketSourceResolution interface { + // Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution. + Resolution() TimestampResolution +} diff --git a/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/writer.go b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/writer.go new file mode 100644 index 0000000000..9a463f047a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/github.com/gopacket/gopacket/writer.go @@ -0,0 +1,233 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package gopacket + +import ( + "fmt" +) + +// SerializableLayer allows its implementations to be written out as a set of bytes, +// so those bytes may be sent on the wire or otherwise used by the caller. +// SerializableLayer is implemented by certain Layer types, and can be encoded to +// bytes using the LayerWriter object. +type SerializableLayer interface { + // SerializeTo writes this layer to a slice, growing that slice if necessary + // to make it fit the layer's data. + // Args: + // b: SerializeBuffer to write this layer on to. When called, b.Bytes() + // is the payload this layer should wrap, if any. Note that this + // layer can either prepend itself (common), append itself + // (uncommon), or both (sometimes padding or footers are required at + // the end of packet data). It's also possible (though probably very + // rarely needed) to overwrite any bytes in the current payload. + // After this call, b.Bytes() should return the byte encoding of + // this layer wrapping the original b.Bytes() payload. + // opts: options to use while writing out data. + // Returns: + // error if a problem was encountered during encoding. If an error is + // returned, the bytes in data should be considered invalidated, and + // not used. + // + // SerializeTo calls SHOULD entirely ignore LayerContents and + // LayerPayload. It just serializes based on struct fields, neither + // modifying nor using contents/payload. + SerializeTo(b SerializeBuffer, opts SerializeOptions) error + // LayerType returns the type of the layer that is being serialized to the buffer + LayerType() LayerType +} + +// SerializeOptions provides options for behaviors that SerializableLayers may want to +// implement. +type SerializeOptions struct { + // FixLengths determines whether, during serialization, layers should fix + // the values for any length field that depends on the payload. + FixLengths bool + // ComputeChecksums determines whether, during serialization, layers + // should recompute checksums based on their payloads. + ComputeChecksums bool +} + +// SerializeBuffer is a helper used by gopacket for writing out packet layers. +// SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes +// return byte slices before the current Bytes(), AppendBytes returns byte +// slices after. +// +// Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if +// you want to make sure they're all zeros, set them as such. +// +// SerializeBuffer is specifically designed to handle packet writing, where unlike +// with normal writes it's easier to start writing at the inner-most layer and +// work out, meaning that we often need to prepend bytes. This runs counter to +// typical writes to byte slices using append(), where we only write at the end +// of the buffer. +// +// It can be reused via Clear. Note, however, that a Clear call will invalidate the +// byte slices returned by any previous Bytes() call (the same buffer is +// reused). +// +// 1. Reusing a write buffer is generally much faster than creating a new one, +// and with the default implementation it avoids additional memory allocations. +// 2. If a byte slice from a previous Bytes() call will continue to be used, +// it's better to create a new SerializeBuffer. +// +// The Clear method is specifically designed to minimize memory allocations for +// similar later workloads on the SerializeBuffer. IE: if you make a set of +// Prepend/Append calls, then clear, then make the same calls with the same +// sizes, the second round (and all future similar rounds) shouldn't allocate +// any new memory. +type SerializeBuffer interface { + // Bytes returns the contiguous set of bytes collected so far by Prepend/Append + // calls. The slice returned by Bytes will be modified by future Clear calls, + // so if you're planning on clearing this SerializeBuffer, you may want to copy + // Bytes somewhere safe first. + Bytes() []byte + // PrependBytes returns a set of bytes which prepends the current bytes in this + // buffer. These bytes start in an indeterminate state, so they should be + // overwritten by the caller. The caller must only call PrependBytes if they + // know they're going to immediately overwrite all bytes returned. + PrependBytes(num int) ([]byte, error) + // AppendBytes returns a set of bytes which appends the current bytes in this + // buffer. These bytes start in an indeterminate state, so they should be + // overwritten by the caller. The caller must only call AppendBytes if they + // know they're going to immediately overwrite all bytes returned. + AppendBytes(num int) ([]byte, error) + // Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear, + // the byte slice returned by any previous call to Bytes() for this buffer + // should be considered invalidated. + Clear() error + // Layers returns all the Layers that have been successfully serialized into this buffer + // already. + Layers() []LayerType + // PushLayer adds the current Layer to the list of Layers that have been serialized + // into this buffer. + PushLayer(LayerType) +} + +type serializeBuffer struct { + data []byte + start int + prepended, appended int + layers []LayerType +} + +// NewSerializeBuffer creates a new instance of the default implementation of +// the SerializeBuffer interface. +func NewSerializeBuffer() SerializeBuffer { + return &serializeBuffer{} +} + +// NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an +// expected number of bytes prepended/appended. This tends to decrease the +// number of memory allocations made by the buffer during writes. +func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer { + return &serializeBuffer{ + data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength), + start: expectedPrependLength, + prepended: expectedPrependLength, + appended: expectedAppendLength, + } +} + +func (w *serializeBuffer) Bytes() []byte { + return w.data[w.start:] +} + +func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) { + if num < 0 { + panic("num < 0") + } + if w.start < num { + toPrepend := w.prepended + if toPrepend < num { + toPrepend = num + } + w.prepended += toPrepend + length := cap(w.data) + toPrepend + newData := make([]byte, length) + newStart := w.start + toPrepend + copy(newData[newStart:], w.data[w.start:]) + w.start = newStart + w.data = newData[:toPrepend+len(w.data)] + } + w.start -= num + return w.data[w.start : w.start+num], nil +} + +func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) { + if num < 0 { + panic("num < 0") + } + initialLength := len(w.data) + if cap(w.data)-initialLength < num { + toAppend := w.appended + if toAppend < num { + toAppend = num + } + w.appended += toAppend + newData := make([]byte, cap(w.data)+toAppend) + copy(newData[w.start:], w.data[w.start:]) + w.data = newData[:initialLength] + } + // Grow the buffer. We know it'll be under capacity given above. + w.data = w.data[:initialLength+num] + return w.data[initialLength:], nil +} + +func (w *serializeBuffer) Clear() error { + w.start = w.prepended + w.data = w.data[:w.start] + w.layers = w.layers[:0] + return nil +} + +func (w *serializeBuffer) Layers() []LayerType { + return w.layers +} + +func (w *serializeBuffer) PushLayer(l LayerType) { + w.layers = append(w.layers, l) +} + +// SerializeLayers clears the given write buffer, then writes all layers into it so +// they correctly wrap each other. Note that by clearing the buffer, it +// invalidates all slices previously returned by w.Bytes() +// +// Example: +// +// buf := gopacket.NewSerializeBuffer() +// opts := gopacket.SerializeOptions{} +// gopacket.SerializeLayers(buf, opts, a, b, c) +// firstPayload := buf.Bytes() // contains byte representation of a(b(c)) +// gopacket.SerializeLayers(buf, opts, d, e, f) +// secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf. +func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error { + w.Clear() + for i := len(layers) - 1; i >= 0; i-- { + layer := layers[i] + err := layer.SerializeTo(w, opts) + if err != nil { + return err + } + w.PushLayer(layer.LayerType()) + } + return nil +} + +// SerializePacket is a convenience function that calls SerializeLayers +// on packet's Layers(). +// It returns an error if one of the packet layers is not a SerializableLayer. +func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error { + sls := []SerializableLayer{} + for _, layer := range packet.Layers() { + sl, ok := layer.(SerializableLayer) + if !ok { + return fmt.Errorf("layer %s is not serializable", layer.LayerType().String()) + } + sls = append(sls, sl) + } + return SerializeLayers(buf, opts, sls...) +} diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/asm.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/asm.go new file mode 100644 index 0000000000..15e21b1812 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/asm.go @@ -0,0 +1,41 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import "fmt" + +// Assemble converts insts into raw instructions suitable for loading +// into a BPF virtual machine. +// +// Currently, no optimization is attempted, the assembled program flow +// is exactly as provided. +func Assemble(insts []Instruction) ([]RawInstruction, error) { + ret := make([]RawInstruction, len(insts)) + var err error + for i, inst := range insts { + ret[i], err = inst.Assemble() + if err != nil { + return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err) + } + } + return ret, nil +} + +// Disassemble attempts to parse raw back into +// Instructions. Unrecognized RawInstructions are assumed to be an +// extension not implemented by this package, and are passed through +// unchanged to the output. The allDecoded value reports whether insts +// contains no RawInstructions. +func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) { + insts = make([]Instruction, len(raw)) + allDecoded = true + for i, r := range raw { + insts[i] = r.Disassemble() + if _, ok := insts[i].(RawInstruction); ok { + allDecoded = false + } + } + return insts, allDecoded +} diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/constants.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/constants.go new file mode 100644 index 0000000000..12f3ee835a --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/constants.go @@ -0,0 +1,222 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +// A Register is a register of the BPF virtual machine. +type Register uint16 + +const ( + // RegA is the accumulator register. RegA is always the + // destination register of ALU operations. + RegA Register = iota + // RegX is the indirection register, used by LoadIndirect + // operations. + RegX +) + +// An ALUOp is an arithmetic or logic operation. +type ALUOp uint16 + +// ALU binary operation types. +const ( + ALUOpAdd ALUOp = iota << 4 + ALUOpSub + ALUOpMul + ALUOpDiv + ALUOpOr + ALUOpAnd + ALUOpShiftLeft + ALUOpShiftRight + aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type. + ALUOpMod + ALUOpXor +) + +// A JumpTest is a comparison operator used in conditional jumps. +type JumpTest uint16 + +// Supported operators for conditional jumps. +// K can be RegX for JumpIfX +const ( + // K == A + JumpEqual JumpTest = iota + // K != A + JumpNotEqual + // K > A + JumpGreaterThan + // K < A + JumpLessThan + // K >= A + JumpGreaterOrEqual + // K <= A + JumpLessOrEqual + // K & A != 0 + JumpBitsSet + // K & A == 0 + JumpBitsNotSet +) + +// An Extension is a function call provided by the kernel that +// performs advanced operations that are expensive or impossible +// within the BPF virtual machine. +// +// Extensions are only implemented by the Linux kernel. +// +// TODO: should we prune this list? Some of these extensions seem +// either broken or near-impossible to use correctly, whereas other +// (len, random, ifindex) are quite useful. +type Extension int + +// Extension functions available in the Linux kernel. +const ( + // extOffset is the negative maximum number of instructions used + // to load instructions by overloading the K argument. + extOffset = -0x1000 + // ExtLen returns the length of the packet. + ExtLen Extension = 1 + // ExtProto returns the packet's L3 protocol type. + ExtProto Extension = 0 + // ExtType returns the packet's type (skb->pkt_type in the kernel) + // + // TODO: better documentation. How nice an API do we want to + // provide for these esoteric extensions? + ExtType Extension = 4 + // ExtPayloadOffset returns the offset of the packet payload, or + // the first protocol header that the kernel does not know how to + // parse. + ExtPayloadOffset Extension = 52 + // ExtInterfaceIndex returns the index of the interface on which + // the packet was received. + ExtInterfaceIndex Extension = 8 + // ExtNetlinkAttr returns the netlink attribute of type X at + // offset A. + ExtNetlinkAttr Extension = 12 + // ExtNetlinkAttrNested returns the nested netlink attribute of + // type X at offset A. + ExtNetlinkAttrNested Extension = 16 + // ExtMark returns the packet's mark value. + ExtMark Extension = 20 + // ExtQueue returns the packet's assigned hardware queue. + ExtQueue Extension = 24 + // ExtLinkLayerType returns the packet's hardware address type + // (e.g. Ethernet, Infiniband). + ExtLinkLayerType Extension = 28 + // ExtRXHash returns the packets receive hash. + // + // TODO: figure out what this rxhash actually is. + ExtRXHash Extension = 32 + // ExtCPUID returns the ID of the CPU processing the current + // packet. + ExtCPUID Extension = 36 + // ExtVLANTag returns the packet's VLAN tag. + ExtVLANTag Extension = 44 + // ExtVLANTagPresent returns non-zero if the packet has a VLAN + // tag. + // + // TODO: I think this might be a lie: it reads bit 0x1000 of the + // VLAN header, which changed meaning in recent revisions of the + // spec - this extension may now return meaningless information. + ExtVLANTagPresent Extension = 48 + // ExtVLANProto returns 0x8100 if the frame has a VLAN header, + // 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some + // other value if no VLAN information is present. + ExtVLANProto Extension = 60 + // ExtRand returns a uniformly random uint32. + ExtRand Extension = 56 +) + +// The following gives names to various bit patterns used in opcode construction. + +const ( + opMaskCls uint16 = 0x7 + // opClsLoad masks + opMaskLoadDest = 0x01 + opMaskLoadWidth = 0x18 + opMaskLoadMode = 0xe0 + // opClsALU & opClsJump + opMaskOperand = 0x08 + opMaskOperator = 0xf0 +) + +const ( + // +---------------+-----------------+---+---+---+ + // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 | + // +---------------+-----------------+---+---+---+ + opClsLoadA uint16 = iota + // +---------------+-----------------+---+---+---+ + // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 | + // +---------------+-----------------+---+---+---+ + opClsLoadX + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | + // +---+---+---+---+---+---+---+---+ + opClsStoreA + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // +---+---+---+---+---+---+---+---+ + opClsStoreX + // +---------------+-----------------+---+---+---+ + // | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 | + // +---------------+-----------------+---+---+---+ + opClsALU + // +-----------------------------+---+---+---+---+ + // | TestOperator (4b) | 0 | 1 | 0 | 1 | + // +-----------------------------+---+---+---+---+ + opClsJump + // +---+-------------------------+---+---+---+---+ + // | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 | + // +---+-------------------------+---+---+---+---+ + opClsReturn + // +---+-------------------------+---+---+---+---+ + // | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 | + // +---+-------------------------+---+---+---+---+ + opClsMisc +) + +const ( + opAddrModeImmediate uint16 = iota << 5 + opAddrModeAbsolute + opAddrModeIndirect + opAddrModeScratch + opAddrModePacketLen // actually an extension, not an addressing mode. + opAddrModeMemShift +) + +const ( + opLoadWidth4 uint16 = iota << 3 + opLoadWidth2 + opLoadWidth1 +) + +// Operand for ALU and Jump instructions +type opOperand uint16 + +// Supported operand sources. +const ( + opOperandConstant opOperand = iota << 3 + opOperandX +) + +// An jumpOp is a conditional jump condition. +type jumpOp uint16 + +// Supported jump conditions. +const ( + opJumpAlways jumpOp = iota << 4 + opJumpEqual + opJumpGT + opJumpGE + opJumpSet +) + +const ( + opRetSrcConstant uint16 = iota << 4 + opRetSrcA +) + +const ( + opMiscTAX = 0x00 + opMiscTXA = 0x80 +) diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/doc.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/doc.go new file mode 100644 index 0000000000..04ec1c8ab5 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/doc.go @@ -0,0 +1,80 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package bpf implements marshaling and unmarshaling of programs for the +Berkeley Packet Filter virtual machine, and provides a Go implementation +of the virtual machine. + +BPF's main use is to specify a packet filter for network taps, so that +the kernel doesn't have to expensively copy every packet it sees to +userspace. However, it's been repurposed to other areas where running +user code in-kernel is needed. For example, Linux's seccomp uses BPF +to apply security policies to system calls. For simplicity, this +documentation refers only to packets, but other uses of BPF have their +own data payloads. + +BPF programs run in a restricted virtual machine. It has almost no +access to kernel functions, and while conditional branches are +allowed, they can only jump forwards, to guarantee that there are no +infinite loops. + +# The virtual machine + +The BPF VM is an accumulator machine. Its main register, called +register A, is an implicit source and destination in all arithmetic +and logic operations. The machine also has 16 scratch registers for +temporary storage, and an indirection register (register X) for +indirect memory access. All registers are 32 bits wide. + +Each run of a BPF program is given one packet, which is placed in the +VM's read-only "main memory". LoadAbsolute and LoadIndirect +instructions can fetch up to 32 bits at a time into register A for +examination. + +The goal of a BPF program is to produce and return a verdict (uint32), +which tells the kernel what to do with the packet. In the context of +packet filtering, the returned value is the number of bytes of the +packet to forward to userspace, or 0 to ignore the packet. Other +contexts like seccomp define their own return values. + +In order to simplify programs, attempts to read past the end of the +packet terminate the program execution with a verdict of 0 (ignore +packet). This means that the vast majority of BPF programs don't need +to do any explicit bounds checking. + +In addition to the bytes of the packet, some BPF programs have access +to extensions, which are essentially calls to kernel utility +functions. Currently, the only extensions supported by this package +are the Linux packet filter extensions. + +# Examples + +This packet filter selects all ARP packets. + + bpf.Assemble([]bpf.Instruction{ + // Load "EtherType" field from the ethernet header. + bpf.LoadAbsolute{Off: 12, Size: 2}, + // Skip over the next instruction if EtherType is not ARP. + bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1}, + // Verdict is "send up to 4k of the packet to userspace." + bpf.RetConstant{Val: 4096}, + // Verdict is "ignore packet." + bpf.RetConstant{Val: 0}, + }) + +This packet filter captures a random 1% sample of traffic. + + bpf.Assemble([]bpf.Instruction{ + // Get a 32-bit random number from the Linux kernel. + bpf.LoadExtension{Num: bpf.ExtRand}, + // 1% dice roll? + bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1}, + // Capture. + bpf.RetConstant{Val: 4096}, + // Ignore. + bpf.RetConstant{Val: 0}, + }) +*/ +package bpf // import "golang.org/x/net/bpf" diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/instructions.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/instructions.go new file mode 100644 index 0000000000..3cffcaa014 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/instructions.go @@ -0,0 +1,726 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import "fmt" + +// An Instruction is one instruction executed by the BPF virtual +// machine. +type Instruction interface { + // Assemble assembles the Instruction into a RawInstruction. + Assemble() (RawInstruction, error) +} + +// A RawInstruction is a raw BPF virtual machine instruction. +type RawInstruction struct { + // Operation to execute. + Op uint16 + // For conditional jump instructions, the number of instructions + // to skip if the condition is true/false. + Jt uint8 + Jf uint8 + // Constant parameter. The meaning depends on the Op. + K uint32 +} + +// Assemble implements the Instruction Assemble method. +func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil } + +// Disassemble parses ri into an Instruction and returns it. If ri is +// not recognized by this package, ri itself is returned. +func (ri RawInstruction) Disassemble() Instruction { + switch ri.Op & opMaskCls { + case opClsLoadA, opClsLoadX: + reg := Register(ri.Op & opMaskLoadDest) + sz := 0 + switch ri.Op & opMaskLoadWidth { + case opLoadWidth4: + sz = 4 + case opLoadWidth2: + sz = 2 + case opLoadWidth1: + sz = 1 + default: + return ri + } + switch ri.Op & opMaskLoadMode { + case opAddrModeImmediate: + if sz != 4 { + return ri + } + return LoadConstant{Dst: reg, Val: ri.K} + case opAddrModeScratch: + if sz != 4 || ri.K > 15 { + return ri + } + return LoadScratch{Dst: reg, N: int(ri.K)} + case opAddrModeAbsolute: + if ri.K > extOffset+0xffffffff { + return LoadExtension{Num: Extension(-extOffset + ri.K)} + } + return LoadAbsolute{Size: sz, Off: ri.K} + case opAddrModeIndirect: + return LoadIndirect{Size: sz, Off: ri.K} + case opAddrModePacketLen: + if sz != 4 { + return ri + } + return LoadExtension{Num: ExtLen} + case opAddrModeMemShift: + return LoadMemShift{Off: ri.K} + default: + return ri + } + + case opClsStoreA: + if ri.Op != opClsStoreA || ri.K > 15 { + return ri + } + return StoreScratch{Src: RegA, N: int(ri.K)} + + case opClsStoreX: + if ri.Op != opClsStoreX || ri.K > 15 { + return ri + } + return StoreScratch{Src: RegX, N: int(ri.K)} + + case opClsALU: + switch op := ALUOp(ri.Op & opMaskOperator); op { + case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor: + switch operand := opOperand(ri.Op & opMaskOperand); operand { + case opOperandX: + return ALUOpX{Op: op} + case opOperandConstant: + return ALUOpConstant{Op: op, Val: ri.K} + default: + return ri + } + case aluOpNeg: + return NegateA{} + default: + return ri + } + + case opClsJump: + switch op := jumpOp(ri.Op & opMaskOperator); op { + case opJumpAlways: + return Jump{Skip: ri.K} + case opJumpEqual, opJumpGT, opJumpGE, opJumpSet: + cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf) + switch operand := opOperand(ri.Op & opMaskOperand); operand { + case opOperandX: + return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse} + case opOperandConstant: + return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse} + default: + return ri + } + default: + return ri + } + + case opClsReturn: + switch ri.Op { + case opClsReturn | opRetSrcA: + return RetA{} + case opClsReturn | opRetSrcConstant: + return RetConstant{Val: ri.K} + default: + return ri + } + + case opClsMisc: + switch ri.Op { + case opClsMisc | opMiscTAX: + return TAX{} + case opClsMisc | opMiscTXA: + return TXA{} + default: + return ri + } + + default: + panic("unreachable") // switch is exhaustive on the bit pattern + } +} + +func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) { + var test JumpTest + + // Decode "fake" jump conditions that don't appear in machine code + // Ensures the Assemble -> Disassemble stage recreates the same instructions + // See https://github.com/golang/go/issues/18470 + if skipTrue == 0 { + switch op { + case opJumpEqual: + test = JumpNotEqual + case opJumpGT: + test = JumpLessOrEqual + case opJumpGE: + test = JumpLessThan + case opJumpSet: + test = JumpBitsNotSet + } + + return test, skipFalse, 0 + } + + switch op { + case opJumpEqual: + test = JumpEqual + case opJumpGT: + test = JumpGreaterThan + case opJumpGE: + test = JumpGreaterOrEqual + case opJumpSet: + test = JumpBitsSet + } + + return test, skipTrue, skipFalse +} + +// LoadConstant loads Val into register Dst. +type LoadConstant struct { + Dst Register + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadConstant) Assemble() (RawInstruction, error) { + return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val) +} + +// String returns the instruction in assembler notation. +func (a LoadConstant) String() string { + switch a.Dst { + case RegA: + return fmt.Sprintf("ld #%d", a.Val) + case RegX: + return fmt.Sprintf("ldx #%d", a.Val) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadScratch loads scratch[N] into register Dst. +type LoadScratch struct { + Dst Register + N int // 0-15 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadScratch) Assemble() (RawInstruction, error) { + if a.N < 0 || a.N > 15 { + return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N) + } + return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N)) +} + +// String returns the instruction in assembler notation. +func (a LoadScratch) String() string { + switch a.Dst { + case RegA: + return fmt.Sprintf("ld M[%d]", a.N) + case RegX: + return fmt.Sprintf("ldx M[%d]", a.N) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadAbsolute loads packet[Off:Off+Size] as an integer value into +// register A. +type LoadAbsolute struct { + Off uint32 + Size int // 1, 2 or 4 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadAbsolute) Assemble() (RawInstruction, error) { + return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadAbsolute) String() string { + switch a.Size { + case 1: // byte + return fmt.Sprintf("ldb [%d]", a.Off) + case 2: // half word + return fmt.Sprintf("ldh [%d]", a.Off) + case 4: // word + if a.Off > extOffset+0xffffffff { + return LoadExtension{Num: Extension(a.Off + 0x1000)}.String() + } + return fmt.Sprintf("ld [%d]", a.Off) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value +// into register A. +type LoadIndirect struct { + Off uint32 + Size int // 1, 2 or 4 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadIndirect) Assemble() (RawInstruction, error) { + return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadIndirect) String() string { + switch a.Size { + case 1: // byte + return fmt.Sprintf("ldb [x + %d]", a.Off) + case 2: // half word + return fmt.Sprintf("ldh [x + %d]", a.Off) + case 4: // word + return fmt.Sprintf("ld [x + %d]", a.Off) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadMemShift multiplies the first 4 bits of the byte at packet[Off] +// by 4 and stores the result in register X. +// +// This instruction is mainly useful to load into X the length of an +// IPv4 packet header in a single instruction, rather than have to do +// the arithmetic on the header's first byte by hand. +type LoadMemShift struct { + Off uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadMemShift) Assemble() (RawInstruction, error) { + return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadMemShift) String() string { + return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off) +} + +// LoadExtension invokes a linux-specific extension and stores the +// result in register A. +type LoadExtension struct { + Num Extension +} + +// Assemble implements the Instruction Assemble method. +func (a LoadExtension) Assemble() (RawInstruction, error) { + if a.Num == ExtLen { + return assembleLoad(RegA, 4, opAddrModePacketLen, 0) + } + return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num)) +} + +// String returns the instruction in assembler notation. +func (a LoadExtension) String() string { + switch a.Num { + case ExtLen: + return "ld #len" + case ExtProto: + return "ld #proto" + case ExtType: + return "ld #type" + case ExtPayloadOffset: + return "ld #poff" + case ExtInterfaceIndex: + return "ld #ifidx" + case ExtNetlinkAttr: + return "ld #nla" + case ExtNetlinkAttrNested: + return "ld #nlan" + case ExtMark: + return "ld #mark" + case ExtQueue: + return "ld #queue" + case ExtLinkLayerType: + return "ld #hatype" + case ExtRXHash: + return "ld #rxhash" + case ExtCPUID: + return "ld #cpu" + case ExtVLANTag: + return "ld #vlan_tci" + case ExtVLANTagPresent: + return "ld #vlan_avail" + case ExtVLANProto: + return "ld #vlan_tpid" + case ExtRand: + return "ld #rand" + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// StoreScratch stores register Src into scratch[N]. +type StoreScratch struct { + Src Register + N int // 0-15 +} + +// Assemble implements the Instruction Assemble method. +func (a StoreScratch) Assemble() (RawInstruction, error) { + if a.N < 0 || a.N > 15 { + return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N) + } + var op uint16 + switch a.Src { + case RegA: + op = opClsStoreA + case RegX: + op = opClsStoreX + default: + return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src) + } + + return RawInstruction{ + Op: op, + K: uint32(a.N), + }, nil +} + +// String returns the instruction in assembler notation. +func (a StoreScratch) String() string { + switch a.Src { + case RegA: + return fmt.Sprintf("st M[%d]", a.N) + case RegX: + return fmt.Sprintf("stx M[%d]", a.N) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// ALUOpConstant executes A = A Val. +type ALUOpConstant struct { + Op ALUOp + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a ALUOpConstant) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op), + K: a.Val, + }, nil +} + +// String returns the instruction in assembler notation. +func (a ALUOpConstant) String() string { + switch a.Op { + case ALUOpAdd: + return fmt.Sprintf("add #%d", a.Val) + case ALUOpSub: + return fmt.Sprintf("sub #%d", a.Val) + case ALUOpMul: + return fmt.Sprintf("mul #%d", a.Val) + case ALUOpDiv: + return fmt.Sprintf("div #%d", a.Val) + case ALUOpMod: + return fmt.Sprintf("mod #%d", a.Val) + case ALUOpAnd: + return fmt.Sprintf("and #%d", a.Val) + case ALUOpOr: + return fmt.Sprintf("or #%d", a.Val) + case ALUOpXor: + return fmt.Sprintf("xor #%d", a.Val) + case ALUOpShiftLeft: + return fmt.Sprintf("lsh #%d", a.Val) + case ALUOpShiftRight: + return fmt.Sprintf("rsh #%d", a.Val) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// ALUOpX executes A = A X +type ALUOpX struct { + Op ALUOp +} + +// Assemble implements the Instruction Assemble method. +func (a ALUOpX) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(opOperandX) | uint16(a.Op), + }, nil +} + +// String returns the instruction in assembler notation. +func (a ALUOpX) String() string { + switch a.Op { + case ALUOpAdd: + return "add x" + case ALUOpSub: + return "sub x" + case ALUOpMul: + return "mul x" + case ALUOpDiv: + return "div x" + case ALUOpMod: + return "mod x" + case ALUOpAnd: + return "and x" + case ALUOpOr: + return "or x" + case ALUOpXor: + return "xor x" + case ALUOpShiftLeft: + return "lsh x" + case ALUOpShiftRight: + return "rsh x" + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// NegateA executes A = -A. +type NegateA struct{} + +// Assemble implements the Instruction Assemble method. +func (a NegateA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(aluOpNeg), + }, nil +} + +// String returns the instruction in assembler notation. +func (a NegateA) String() string { + return fmt.Sprintf("neg") +} + +// Jump skips the following Skip instructions in the program. +type Jump struct { + Skip uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a Jump) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsJump | uint16(opJumpAlways), + K: a.Skip, + }, nil +} + +// String returns the instruction in assembler notation. +func (a Jump) String() string { + return fmt.Sprintf("ja %d", a.Skip) +} + +// JumpIf skips the following Skip instructions in the program if A +// Val is true. +type JumpIf struct { + Cond JumpTest + Val uint32 + SkipTrue uint8 + SkipFalse uint8 +} + +// Assemble implements the Instruction Assemble method. +func (a JumpIf) Assemble() (RawInstruction, error) { + return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse) +} + +// String returns the instruction in assembler notation. +func (a JumpIf) String() string { + return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse) +} + +// JumpIfX skips the following Skip instructions in the program if A +// X is true. +type JumpIfX struct { + Cond JumpTest + SkipTrue uint8 + SkipFalse uint8 +} + +// Assemble implements the Instruction Assemble method. +func (a JumpIfX) Assemble() (RawInstruction, error) { + return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse) +} + +// String returns the instruction in assembler notation. +func (a JumpIfX) String() string { + return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse) +} + +// jumpToRaw assembles a jump instruction into a RawInstruction +func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) { + var ( + cond jumpOp + flip bool + ) + switch test { + case JumpEqual: + cond = opJumpEqual + case JumpNotEqual: + cond, flip = opJumpEqual, true + case JumpGreaterThan: + cond = opJumpGT + case JumpLessThan: + cond, flip = opJumpGE, true + case JumpGreaterOrEqual: + cond = opJumpGE + case JumpLessOrEqual: + cond, flip = opJumpGT, true + case JumpBitsSet: + cond = opJumpSet + case JumpBitsNotSet: + cond, flip = opJumpSet, true + default: + return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test) + } + jt, jf := skipTrue, skipFalse + if flip { + jt, jf = jf, jt + } + return RawInstruction{ + Op: opClsJump | uint16(cond) | uint16(operand), + Jt: jt, + Jf: jf, + K: k, + }, nil +} + +// jumpToString converts a jump instruction to assembler notation +func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string { + switch cond { + // K == A + case JumpEqual: + return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq") + // K != A + case JumpNotEqual: + return fmt.Sprintf("jneq %s,%d", operand, skipTrue) + // K > A + case JumpGreaterThan: + return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle") + // K < A + case JumpLessThan: + return fmt.Sprintf("jlt %s,%d", operand, skipTrue) + // K >= A + case JumpGreaterOrEqual: + return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt") + // K <= A + case JumpLessOrEqual: + return fmt.Sprintf("jle %s,%d", operand, skipTrue) + // K & A != 0 + case JumpBitsSet: + if skipFalse > 0 { + return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse) + } + return fmt.Sprintf("jset %s,%d", operand, skipTrue) + // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips + case JumpBitsNotSet: + return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue) + default: + return fmt.Sprintf("unknown JumpTest %#v", cond) + } +} + +func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string { + if skipTrue > 0 { + if skipFalse > 0 { + return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse) + } + return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue) + } + return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse) +} + +// RetA exits the BPF program, returning the value of register A. +type RetA struct{} + +// Assemble implements the Instruction Assemble method. +func (a RetA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsReturn | opRetSrcA, + }, nil +} + +// String returns the instruction in assembler notation. +func (a RetA) String() string { + return fmt.Sprintf("ret a") +} + +// RetConstant exits the BPF program, returning a constant value. +type RetConstant struct { + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a RetConstant) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsReturn | opRetSrcConstant, + K: a.Val, + }, nil +} + +// String returns the instruction in assembler notation. +func (a RetConstant) String() string { + return fmt.Sprintf("ret #%d", a.Val) +} + +// TXA copies the value of register X to register A. +type TXA struct{} + +// Assemble implements the Instruction Assemble method. +func (a TXA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsMisc | opMiscTXA, + }, nil +} + +// String returns the instruction in assembler notation. +func (a TXA) String() string { + return fmt.Sprintf("txa") +} + +// TAX copies the value of register A to register X. +type TAX struct{} + +// Assemble implements the Instruction Assemble method. +func (a TAX) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsMisc | opMiscTAX, + }, nil +} + +// String returns the instruction in assembler notation. +func (a TAX) String() string { + return fmt.Sprintf("tax") +} + +func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) { + var ( + cls uint16 + sz uint16 + ) + switch dst { + case RegA: + cls = opClsLoadA + case RegX: + cls = opClsLoadX + default: + return RawInstruction{}, fmt.Errorf("invalid target register %v", dst) + } + switch loadSize { + case 1: + sz = opLoadWidth1 + case 2: + sz = opLoadWidth2 + case 4: + sz = opLoadWidth4 + default: + return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz) + } + return RawInstruction{ + Op: cls | sz | mode, + K: k, + }, nil +} diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/setter.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/setter.go new file mode 100644 index 0000000000..43e35f0ac2 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/setter.go @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +// A Setter is a type which can attach a compiled BPF filter to itself. +type Setter interface { + SetBPF(filter []RawInstruction) error +} diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm.go new file mode 100644 index 0000000000..73f57f1f72 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm.go @@ -0,0 +1,150 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import ( + "errors" + "fmt" +) + +// A VM is an emulated BPF virtual machine. +type VM struct { + filter []Instruction +} + +// NewVM returns a new VM using the input BPF program. +func NewVM(filter []Instruction) (*VM, error) { + if len(filter) == 0 { + return nil, errors.New("one or more Instructions must be specified") + } + + for i, ins := range filter { + check := len(filter) - (i + 1) + switch ins := ins.(type) { + // Check for out-of-bounds jumps in instructions + case Jump: + if check <= int(ins.Skip) { + return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip) + } + case JumpIf: + if check <= int(ins.SkipTrue) { + return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue) + } + if check <= int(ins.SkipFalse) { + return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse) + } + case JumpIfX: + if check <= int(ins.SkipTrue) { + return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue) + } + if check <= int(ins.SkipFalse) { + return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse) + } + // Check for division or modulus by zero + case ALUOpConstant: + if ins.Val != 0 { + break + } + + switch ins.Op { + case ALUOpDiv, ALUOpMod: + return nil, errors.New("cannot divide by zero using ALUOpConstant") + } + // Check for unknown extensions + case LoadExtension: + switch ins.Num { + case ExtLen: + default: + return nil, fmt.Errorf("extension %d not implemented", ins.Num) + } + } + } + + // Make sure last instruction is a return instruction + switch filter[len(filter)-1].(type) { + case RetA, RetConstant: + default: + return nil, errors.New("BPF program must end with RetA or RetConstant") + } + + // Though our VM works using disassembled instructions, we + // attempt to assemble the input filter anyway to ensure it is compatible + // with an operating system VM. + _, err := Assemble(filter) + + return &VM{ + filter: filter, + }, err +} + +// Run runs the VM's BPF program against the input bytes. +// Run returns the number of bytes accepted by the BPF program, and any errors +// which occurred while processing the program. +func (v *VM) Run(in []byte) (int, error) { + var ( + // Registers of the virtual machine + regA uint32 + regX uint32 + regScratch [16]uint32 + + // OK is true if the program should continue processing the next + // instruction, or false if not, causing the loop to break + ok = true + ) + + // TODO(mdlayher): implement: + // - NegateA: + // - would require a change from uint32 registers to int32 + // registers + + // TODO(mdlayher): add interop tests that check signedness of ALU + // operations against kernel implementation, and make sure Go + // implementation matches behavior + + for i := 0; i < len(v.filter) && ok; i++ { + ins := v.filter[i] + + switch ins := ins.(type) { + case ALUOpConstant: + regA = aluOpConstant(ins, regA) + case ALUOpX: + regA, ok = aluOpX(ins, regA, regX) + case Jump: + i += int(ins.Skip) + case JumpIf: + jump := jumpIf(ins, regA) + i += jump + case JumpIfX: + jump := jumpIfX(ins, regA, regX) + i += jump + case LoadAbsolute: + regA, ok = loadAbsolute(ins, in) + case LoadConstant: + regA, regX = loadConstant(ins, regA, regX) + case LoadExtension: + regA = loadExtension(ins, in) + case LoadIndirect: + regA, ok = loadIndirect(ins, in, regX) + case LoadMemShift: + regX, ok = loadMemShift(ins, in) + case LoadScratch: + regA, regX = loadScratch(ins, regScratch, regA, regX) + case RetA: + return int(regA), nil + case RetConstant: + return int(ins.Val), nil + case StoreScratch: + regScratch = storeScratch(ins, regScratch, regA, regX) + case TAX: + regX = regA + case TXA: + regA = regX + default: + return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins) + } + } + + return 0, nil +} diff --git a/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm_instructions.go b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm_instructions.go new file mode 100644 index 0000000000..0aa307c061 --- /dev/null +++ b/src/code.cloudfoundry.org/vendor/golang.org/x/net/bpf/vm_instructions.go @@ -0,0 +1,182 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import ( + "encoding/binary" + "fmt" +) + +func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 { + return aluOpCommon(ins.Op, regA, ins.Val) +} + +func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) { + // Guard against division or modulus by zero by terminating + // the program, as the OS BPF VM does + if regX == 0 { + switch ins.Op { + case ALUOpDiv, ALUOpMod: + return 0, false + } + } + + return aluOpCommon(ins.Op, regA, regX), true +} + +func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 { + switch op { + case ALUOpAdd: + return regA + value + case ALUOpSub: + return regA - value + case ALUOpMul: + return regA * value + case ALUOpDiv: + // Division by zero not permitted by NewVM and aluOpX checks + return regA / value + case ALUOpOr: + return regA | value + case ALUOpAnd: + return regA & value + case ALUOpShiftLeft: + return regA << value + case ALUOpShiftRight: + return regA >> value + case ALUOpMod: + // Modulus by zero not permitted by NewVM and aluOpX checks + return regA % value + case ALUOpXor: + return regA ^ value + default: + return regA + } +} + +func jumpIf(ins JumpIf, regA uint32) int { + return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val) +} + +func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int { + return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX) +} + +func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int { + var ok bool + + switch cond { + case JumpEqual: + ok = regA == value + case JumpNotEqual: + ok = regA != value + case JumpGreaterThan: + ok = regA > value + case JumpLessThan: + ok = regA < value + case JumpGreaterOrEqual: + ok = regA >= value + case JumpLessOrEqual: + ok = regA <= value + case JumpBitsSet: + ok = (regA & value) != 0 + case JumpBitsNotSet: + ok = (regA & value) == 0 + } + + if ok { + return int(skipTrue) + } + + return int(skipFalse) +} + +func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) { + offset := int(ins.Off) + size := ins.Size + + return loadCommon(in, offset, size) +} + +func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) { + switch ins.Dst { + case RegA: + regA = ins.Val + case RegX: + regX = ins.Val + } + + return regA, regX +} + +func loadExtension(ins LoadExtension, in []byte) uint32 { + switch ins.Num { + case ExtLen: + return uint32(len(in)) + default: + panic(fmt.Sprintf("unimplemented extension: %d", ins.Num)) + } +} + +func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) { + offset := int(ins.Off) + int(regX) + size := ins.Size + + return loadCommon(in, offset, size) +} + +func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) { + offset := int(ins.Off) + + // Size of LoadMemShift is always 1 byte + if !inBounds(len(in), offset, 1) { + return 0, false + } + + // Mask off high 4 bits and multiply low 4 bits by 4 + return uint32(in[offset]&0x0f) * 4, true +} + +func inBounds(inLen int, offset int, size int) bool { + return offset+size <= inLen +} + +func loadCommon(in []byte, offset int, size int) (uint32, bool) { + if !inBounds(len(in), offset, size) { + return 0, false + } + + switch size { + case 1: + return uint32(in[offset]), true + case 2: + return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true + case 4: + return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true + default: + panic(fmt.Sprintf("invalid load size: %d", size)) + } +} + +func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) { + switch ins.Dst { + case RegA: + regA = regScratch[ins.N] + case RegX: + regX = regScratch[ins.N] + } + + return regA, regX +} + +func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 { + switch ins.Src { + case RegA: + regScratch[ins.N] = regA + case RegX: + regScratch[ins.N] = regX + } + + return regScratch +} diff --git a/src/code.cloudfoundry.org/vendor/modules.txt b/src/code.cloudfoundry.org/vendor/modules.txt index 1392e826bb..c96577d95a 100644 --- a/src/code.cloudfoundry.org/vendor/modules.txt +++ b/src/code.cloudfoundry.org/vendor/modules.txt @@ -502,6 +502,13 @@ github.com/google/pprof/profile # github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 ## explicit; go 1.13 github.com/google/shlex +# github.com/gopacket/gopacket v1.5.0 +## explicit; go 1.24.0 +github.com/gopacket/gopacket +github.com/gopacket/gopacket/endian +github.com/gopacket/gopacket/layers +github.com/gopacket/gopacket/pcap +github.com/gopacket/gopacket/pcapgo # github.com/gorilla/mux v1.8.1 ## explicit; go 1.20 github.com/gorilla/mux @@ -802,6 +809,7 @@ golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/mod/semver # golang.org/x/net v0.48.0 ## explicit; go 1.24.0 +golang.org/x/net/bpf golang.org/x/net/context golang.org/x/net/html golang.org/x/net/html/atom diff --git a/src/libpcap-1.10.5/CHANGES b/src/libpcap-1.10.5/CHANGES new file mode 100644 index 0000000000..bf8701c829 --- /dev/null +++ b/src/libpcap-1.10.5/CHANGES @@ -0,0 +1,1595 @@ +Friday, August 30, 2024 / The Tcpdump Group + Summary for 1.10.5 libpcap release + Source code: + Spell WirelessHART details properly. + Mark pcap_vasprintf() as printf-like. + Finalize moving of bpf_filter.c. (GH #1166) + Remove an unneeded argument from gen_mcode6(). + Don't do some Berkeley YACC workarounds with YACC releases not + requiring them. + Use correct data types rather than int in some cases. + Squelch compiler warning in grammar.c. + Fix findalldevtest compilation if IPv6 isn't enabled. + Rename helper routines for pcap modules to have names beginning with + pcapint_, to avoid namespace collisions for code linking statically + with libpcap. + Avoid casting hack for the Windows cleanup-on-exit routine. + Use %zu format for one case of printing a size_t. + Fix some Coverity errors. + Fix availabilities of some functions to match reality. + pcap: make the seconds and microseconds/nanoseconds fields unsigned. + Remove the unused pcap-rpcap-int.h header file. + Thread safety: + Make some static variables thread-local; fixes issue #1174. + Packet filtering: + Improve reporting of some invalid filter expressions. + Return an error from pcap_compile() if the scanner fails to initialize. + Optimizer fix from Archit Shah to recompute dominators after + moving code (#976); fixes #945 (although the resulting filter + isn't empty). + Optimizer fix from Archit Shah to mark value as unknown when store + of that value is deleted (#972); fixes #143, #434, #436, #437, + and #1076. + Linux: + Properly return warnings. + Don't use DLT_LINUX_SLL2 for anything other than the "any" device. + Avoid 32-bit unsigned integer overflow in USB captures. Fixes + issues #1134 and #1205. + Fix a file descriptor leak. + Properly report warnings about unknown ARPHRD_ types. + Fix DLT_CAN_SOCKETCAN handling of CAN FD. + Add CAN XL support to DLT_CAN_SOCKETCAN. + Clean up the code that sets the "real" ("original") length for + isochronous USB transfers. + Avoid unnecessary blocking on recvmsg() in the Bluetooth monitor and + Bluetoth modules. + Solaris: + Handle BPF returning ESRCH for unknown devices. + List the "any" device if it's supported. + Report {non-existent zone}/{interface} errors appropriately. + Allow attaching to links owned by a non-global zone. (Based on + pull request #1202.) + Fix AF_LINK handling on illumos. + macOS: + Redid the availability macros to be closer to what Apple's doing + in recent SDKs, including tagging pcap-namedb.h routines. + Fix the install name of the installed shared library to have a + full path when building with CMake. + Fix universal builds. + Haiku: + Convert the module to C. Fixes issue #1114. + Address a few compiler warnings. Fixes issue #1114. + Fix various build problems. Fixes issue #1114. + Report non-existent devices correctly. + Fix handling of packet statistics. + Fix packet timestamping. + Fix packet filtering with low snaplen. + Improve connection status reporting. + Add support for promiscuous mode. + Detect DLTs and loopback capture support at run time. + Report IEEE 802.11 as PCAP_IF_WIRELESS. + Windows: + Fix internal handling of "not supported" error codes from NPF. + Work around a bug in Npcap 1.00 in case of driver version mismatch. + Don't call WSACleanup() when handling a failed WSAStartup(). + BSD, macOS, AIX, Solaris 11, Linux: + Add a new error PCAP_ERROR_CAPTURE_NOTSUP, for use if a capture + mechanism is not present, in the hopes that, for example, + attempts to capture on Windows Services for Linux 1, in which + the NT kernel attempts to simulate Linux system calls but does + not support packet sockets, can get an error that better + indicates the underlying problem. + AirPcap: + Format an error message if we run out of memory. + nflog: + Fix count of dropped packets. + Make sure we don't overflow when rounding up the TLV length. + rpcap: + Handle routines removed in at least some OpenSSL libraries. + CVE-2023-7256: Clean up sock_initaddress() and its callers to avoid + double frees in some cases. + Don't define SOCKET ourselves; instead, define PCAP_SOCKET as int + on UN*Xes and as SOCKET on Windows. + CVE-2024-8006: Fix pcap_findalldevs_ex() not to crash if passed a + file:// URL with a path to a directory that cannot be opened. + Savefiles: + Handle DLT_/LINKTYPE_ mapping better, to handle some + OpenBSD-specific link types better. + Treat if_tsoffset as signed in pcapng files, as the spec says. + Don't try to fix the "real" length for isochronous USB + transfers if the number of USB descriptors is too large. + Reject pcap files where one of the reserved fields in the + "link-layer type plus other stuff" is non-zero. + Building and testing: + Add a configure option to help debugging (--enable-instrument-functions). + Improved tests and error reporting for uses of pkg-config, and + improve help message. + Fix Haiku build. + With CMake, install headers in CMAKE_INSTALL_INCLUDEDIR rather + than just include. + Build libpcap.a before building test programs. + Print address family numerically, as well as symbolically, + in findalldevstest. + Fail with suggestions, rather than failing over to no capture + support, if no capture mechanism was found. Fixes issue #1016. + Don't indent comments in Make, as that may cause them not to be + recognized as comments. + Don't check for libssl if we aren't going to use it. + Better handle enabling and disabling of sanitizers. Fixes issue + #1171. + CMakeLists.txt: Print "Symlinking: /some/path to ..." conditionally. + Evaluate CMAKE_INSTALL_PREFIX at install time. + cmake: Update the minimum required version to 2.8.12 (except Windows). + cmake: suppress CMP0042 OLD deprecated warning. + Makefile.in: Add the releasecheck target. + Cirrus CI: Add the "make releasecheck" command in the Linux task. + Makefile.in: Add the whitespacecheck target. + Cirrus CI: Run the "make whitespacecheck" command in the Linux task. + Autoconf: Update config.{guess,sub}, timestamps 2024-01-01. + Autoconf: Update the install-sh script to the 2020-11-14.01 version. + Compile with '-Wnull-pointer-subtraction', + '-Wunused-but-set-parameter', and '-Wunused-but-set-variable' in + devel mode if supported. + Don't ignore spaces between CMAKE_C_FLAGS and DPDK_C_FLAGS with + CMake. + Use noreturn and __format__ with XL C 7.0 and later. + Check for the same -W flags in autotools and CMake. + Autoconf: Add autogen.sh, remove configure and config.h.in and put + these generated files in the release tarball. + Autoconf: Get the size of a time_t. + Fix propagation of cc_werr_cflags() output. + Makefile.in(s): Fix the depend target. + mkdep: Exit with a non-zero status if a command fails. + Fix HCI_CHANNEL_MONITOR detection with musl libc. + Extend "make shellcheck" onto mkdep too. + Add initial support for building with TinyCC. + Address all known compiler warnings specific to illumos, Linux, NetBSD, + Solaris and Sun C; in CI expect warnings specific to TinyCC only. + Documentation: + Update and fix pcap-filter man page. + Add a README.haiku.md file. + Document pcap-config better. + Man page formatting and prose fixes. + Rename doc/README.Win32.md to doc/README.windows.md. + Update pcap-savefile man page to match the Internet-Draft for + pcap. + Fix CMake issues for target used by other projects. + Explain "any" device better in pcap_open_live(3PCAP). + Update INSTALL.md. + Note in man pages that errbuf arguments must point to an error + buffer. + Note that if pcap_findalldevs() fails it sets *alldevsp to NULL; + there's no devices list to free. + Explain "other addresses" in pcap_findalldevs(3PCAP). + Document pcap_lookupnet(3PCAP) a bit better. + +Friday, April 7, 2023 / The Tcpdump Group + Summary for 1.10.4 libpcap release + Source code: + Fix spaces before tabs in indentation. + rpcap: + Fix name of launchd service. + Documentation: + Document use of rpcapd with systemd, launchd, inetd, and xinetd. + Building and testing: + Require at least pkg-config 0.17.0, as we use --static. + Get rid of the remains of gnuc.h. + Require at least autoconf 2.69. + Update config.{guess,sub}, timestamps 2023-01-01,2023-01-21. + +Thursday, January 12, 2023 / The Tcpdump Group + Summary for 1.10.3 libpcap release + Source code: + Sort the PUBHDR variable in Makefile.in in "ls" order. + Fix typo in comment in pflog.h. + Remove two no-longer-present files from .gitignore. + Update code and comments for handling failure to set promiscuous + mode based on new information. + Building and testing: + install: Fixed not to install the non-public pcap-util.h header. + pcap-config: add a --version flag. + Makefile.in: Add some missing files in the distclean target. + +Saturday, December 31, 2022 / The Tcpdump Group + Summary for 1.10.2 libpcap release + Source code: + Use __builtin_unreachable() in PCAP_UNREACHABLE. + Use AS_HELP_STRING macro instead of AC_HELP_STRING in the + configure scripts, to avoid deprecation warnings. + Change availability tags in pcap.h to make it easier to + arrange for it to be used in Darwin releases. + Use AS_HELP_STRING for --enable-remote. + Fix some formatting string issues found by cppcheck. + Various small code and comment cleanups. + Use PCAP_ERROR (defined as -1) rather than explicit -1 for + functions the documentation says return PCAP_ERROR. + Remove unused code from the filter compiler. + Use _declspec(deprecated(msg)) rather than __pragma(deprecated) + for Windows deprecation warnings, so the message that was + specified shows up. + diag-control.h: define PCAP_DO_PRAGMA() iff we're going to use it. + Use "%d" to print some signed ints. + Use the Wayback Machine for a removed document in a comment. + Add some const qualifiers. + RDMA: Use PRIu64 to print a uint64_t. + "Dead" pcap_ts from pcap_open_dead() and ..._with_tstamp_precision(): + Don't crash if pcap_breakloop() is called. + Savefiles: + Fix pcap_dispatch() to return number of packets processed, rather + than 0, even at EOF. + If we get an error writing the packet header, don't write the + packet data. + Put PFLOG UID and PID values in the header into host byte order + when reading a LINKTYPE_PFLOG file. + Put CAN ID field in CAN pseudo-headers for LINUX_SLL2, as we do + for LINUX_SLL. + Fix incorrectly-computed "real" length for isochronous USB + transfers when reading savefiles. + Don't crash if pcap_can_set_rfmon() is called. + Fix pcap_offline_read() loop. + Capture: + Never process more than INT_MAX packets in a pcap_dispatch() call, + to avoid integer overflow (issue #1087). + Improve error messages for "no such device" and "permission + denied" errors. + SITA: Fix a typo in a variable name. + Packet filtering: + Get PFLOG header length from the length value in the header. + Support all the direction, reason, and action types supported by + all systems that support PFLOG. + Don't require PFLOG support on the target machine in order to + support PFLOG filtering (also fixes issue #1076). + Expand abbreviations into "proto X" properly. + gencode.c: Update a comment about the VLAN TPID test. + Add the minimum and maximum matching DLTs to an error message. + Linux: + Fix memory leak in capture device open (pull request #1038). + Fix detection of CAN/CAN FD packets in direction check (issue + #1051). + Fix double-free crashes on errors such as running on a kernel with + CONFIG_PACKET_MMAP not configured (issue #1054). + Use DLT_CAN_SOCKETCAN for CANbus interfaces (issue #1052; includes + changes from pull request #1035). + Make sure the CANFD_FDF can be relied on to indicate whether a + CANbus packet is a CAN frame or a CAN FD frame + Improve error message for "out of memory" errors for kernel + filters (see issue #1089). + Fix pcap_findalldevs() to find usbmon devices. + Fix handling of VLAN tagged packets if the link-layer type is + changed from DLT_LINUX_SLL to DLT_LINUX_SLL2 (see issue #1105). + Always turn on PACKET_AUXDATA (see issue #1105). + We require 2.6.27 or later, so PACKET_RESERVE is available. + Make sure there's reserved space for a DLT_LINUX_SLL2 header + when capturing. + Correctly compute the "real" length for isochronous USB transfers. + Don't have an eventfd descriptor open in non-blocking mode, so as + not to waste descriptors. + netfilter: Squelch a narrowing warning (To be look at before 2038). + BPF capture (*BSD, macOS, AIX, Solaris 11): + Fix case where a device open might fail, rather than falling back + to a smaller buffer size, when the initial buffer size is too + big. + Use an unsigned device number to iterate over BPF devices, to + squelch a compiler warning. + NetBSD: + Fix handling of LINKTYPE_HDLC/DLT_HDLC. + rpcap: + Fix unaligned accesses in rpcapd (pull request #1037). + Fix code to process port number. + Clean up findalldevs code in rpcapd. + Clean up bufferizing code. + Fix a file descriptor/handle leak in pcap_findalldevs_ex() + (Coverity CID 1507240). + Improve error messages for host and port resolution errors. + Fix connect code not to fail if both IPv4 and IPv6 addresses are + tried. + Improve connect failure error message. + Provide an error message for a bad authentication reply size. + For link-layer types with host-endian fields in the header, fix + those fields if capturing from a server with a different byte + order. + Suppress temporarily the warnings with "enable remote packet capture". + Windows: + Add support for NdisMediumIP (pull request #1027). + Don't require applications using pcap to be built with VS 2015 or + later. + Use the correct string for the DLL VersionInfo. + Remove unnecessary DllMain() function. + Correctly handle ERROR_INVALID_FUNCTION from + PacketGetTimestampModes() (indicate that WinPcap or an older + version of Npcap is probably installed). + Fix use-after-free in some cases when a pcap_t is closed. + Make sure an error is returned by pcap_create_interface() if + PacketOpenAdapter() fails. + Return an error if the driver reports 0 timestamp modes supported. + Close the ADAPTER handle for some errors in + pcap_create_interface(). + Get rid of old unmaintained VS project files. + Fix deprecation warning for pcap_handle(). + Npcap is now at npcap.com, not npcap.org. + Make sure "no such device" and "no permission to open device" + errors show up in pcap_activate(), not pcap_create() (fixes, + among other things, tcpdump -i ). + npcap: squelch deprecation warnings for kernel dump mode. + Haiku: + Implement pcap_lib_version(), as now required. + Handle negative or too-large snaplen values. + Fix various build issues and warnings. + Building and testing: + Update configure-time universal build checks for macOS. + Update config.guess and config.sub. + If we look for an SSL library with pkg-config in configure script, + try pkg-config first. + If we have pkg-config and Homebrew, try to set pkg-config up to + find Homebrew packages. + Handle some Autoconf/make errors better. + Use "git archive" for the "make releasetar" process. + Remove the release candidate rcX targets. + Fix compiling on Solaris 9/SPARC and 11/AMD64. + Address assorted compiler warnings. + Fix cross-building on Linux for Windows with mingw32 for Win64 + (pull request #1031). + Properly set installation directory on Windows when not compiling + with MSVC. + Fix configure script checks for compiler flags. + Give more details if check for usable (F)Lex fails. + Fix compiling with GCC 4.6.4. + Don't use add_compile_options() with CMake, as we currently don't + require 2.8.12, where it first appeared. + Don't provide -L/usr/lib for pkg-config --libs in pkg-config. + Fix error message for inadequate Bison/Berkeley YACC. + configure: correctly do some DPDK checks. + Only use pkg-config when checking for DPDK. + Allow the path in which DPDK is installed to be specified. + Use pkg-config first when checking for libibverbs. + CMake: fix check for libibverbs with Sun's C compiler. + Have CMake warn if no capture mechanism can be found. + Don't do stuff requiring 3.19 or later on earlier CMakes. + Squelch some CMake warnings. + Fix diag-control.h to handle compiling with clang-cl (issues + #1101 and #1115). + Cleanup various leftover cruft in the configure script. + Fix building without protochain support. (GH #852) + Check for a usable YACC (or Bison) and {F}lex in CMake, as we do + in autotools. + Only check for a C++ compiler on Haiku, as that's the only + platform with C++ code, and make sure they generate code for + the same instruction set bit-width (both 32-bit or both 64-bit) + (issue #1112). + On Solaris, check the target bit-width and set PKG_CONFIG_PATH + appropriately, to handle the mess that is the D-Bus library + package (issue #1112). + Fix generation of pcap-config and libpcap.pc files (issue #1062). + pcap-config: don't assume the system library directory is /usr/lib. + pcap-config: add a --static-pcap-only flag. + Cirrus CI: Use the same configuration as for the main branch. + Add four libpcap test files. + Update Npcap SDK to 1.13. + Makefile.in: Use TEST_DIST, like for tcpdump. + Remove awk code from mkdep. + Cirrus CI: Add the libssl-dev package in the Linux task. + Cirrus CI: Add the openssl@3 brew package in the macOS task. + Get "make shellcheck" to pass again. + CMake: Build valgrindtest only if Autoconf would. + CMake: use ${CMAKE_INSTALL_SBINDIR} rather than just sbin. + CMake: use NUL: as the null device on Windows. + autoconf: fix typo in test of macOS version. + Makefile.in: Add two missing files in EXTRA_DIST. + autotools, cmake: provide an rpath option if necessary. + configure: get rid of the attempt to auto-run PKG_PROG_PKG_CONFIG. + configure: use PKG_CHECK_MODULES to run pkg-config. + Documentation: + Add README.solaris.md. + Add SCTP to pcap-filter(7). + Note that = and == are the same operator in filters (issue #1044). + Update INSTALL.md, README.md, and README.solaris.md. + Update and clean up CONTRIBUTING.md. + Trim documentation of support for now-dead UN*Xe and older + versions of other UN*Xes. + Move the "how to allocate a LINKTYPE_/DLT_ value" documentation to + the web site. + Clean up man pages. + Move README.capture-module to the web site. + Improve some protocol details in pcap-filter(7). + Refine "relop" notes in pcap-filter(7). + In pcap-filter(7) "domain" is an id. + Discuss backward compatibility in pcap-filter(7). + Other improvements to pcap-filter(7). + Document pcap_breakloop(3PCAP) interaction with threads better. + Document PCAP_ERROR_NOT_ACTIVATED for more routines. + +Wednesday, June 9, 2021: + Summary for 1.10.1 libpcap release: + Packet filtering: + Fix "type XXX subtype YYY" giving a parse error + Source code: + Add PCAP_AVAILABLE_1_11. + Building and testing: + Rename struct bpf_aux_data to avoid NetBSD compile errors + Squelch some compiler warnings + Squelch some Bison warnings + Fix cross-builds with older kernels lacking BPF_MOD and BPF_XOR + Fix Bison detection for minor version 0. + Fix parallel build with FreeBSD make. + Get DLT_MATCHING_MAX right in gencode.c on NetBSD. + Define timeradd() and timersub() if necessary. + Fix Cygwin/MSYS target directories. + Fix symlinking with DESTDIR. + Fix generation of libpcap.pc with CMake when not building a shared + library. + Check for Arm64 as well as x86-64 when looking for packet.lib on + Windows. + Documentation: + Refine Markdown in README.md. + Improve the description of portrange in filters. + README.linux.md isn't Markdown, rename it just README.linux. + pcapng: + Support reading version 1.2, which some writers produce, and which + is the same as 1.0 (some new block types were added, but + that's not sufficient reason to bump the minor version number, + as code that understands those new block types can handle them + in a 1.0 file) + Linux: + Drop support for text-mode USB captures, as we require a 2.6.27 + or later kernel (credit to Chaoyuan Peng for noting the + sscanf vulnerabilities in the text-mode code that got me to + realize that we didn't need this code any more) + Bluetooth: fix non-blocking mode. + Don't assume that all compilers used to build for Linux support + the __atomic builtins + Windows: + Add more information in "interface disappeared" error messages, in + the hopes of trying to figure out the cause. + Treat ERROR_DEVICE_REMOVED as "device was removed". + Indicate in the error message which "device was removed" error + occurred. + Report the Windows error status if PacketSendPacket() fails. + Use %lu for ULONGs in error message formats. + Don't treat the inability to find airpcap.dll as an error. + Ignore spurious error reports by Microsoft Surface mobile + telephony modem driver + rpcap: + Clean up error checking and error messages for server address + lookup. + +Tuesday, December 29, 2020 + Summary for 1.10.0 libpcap release + Add support for capturing on DPDK devices + Label most APIs by the first release in which they're available + Fix some memory leaks, including in pcap_compile() + Add pcap_datalink_val_to_description_or_dlt() + Handle the pcap private data in a fashion that makes fewer + assumptions about memory layouts (might fix GitHub issue #940 + on ARM) + Fix some thread safety issues + pcap_findalldevs(): don't sort interfaces by unit number + Always return a list of supported time-stamp types, even if only + host time stamps are supported + Increase the maximum snaplen for LINKTYPE_USBPCAP/DLT_USBPCAP + Report the DLT description in error messages + Add pcap_init() for first-time initialization and global option + setting; it's not required, but may be used + Remove (unused) SITA support + Capture file reading: + Correctly handle pcapng captures with more than one IDB with a + snapshot length greater than the supported maximum + Capture file writing: + Create the file in pcap_dump_open_append() if it doesn't exist + Packet filtering: + Fix "unknown ether proto 'aarp'" + Add a new filter "ifindex" for DLT_LINUX_SLL2 files on all + platforms and live Linux captures + Add a hack to the optimizer to try to catch certain optimizer + loops (should prevent GitHub issue #112) + Show special Linux BPF offsets symbolically in bpf_image() and + bpf_dump() + Added support for ICMPv6 types 1-4 as tokens with names + Remove undocumented and rather old "ether proto" protocols + Catch invalid IPv4 addresses in filters + Don't assume ARM supports unaligned accesses + Security and other issues found by analysis: + Fix various security issues reported by Charles Smith at Tangible + Security + Fix various security issues reported by Include Security + Fix some issues found by cppcheck. + Add some overflow checks in the optimizer + rpcap: + Support rpcap-over-TLS + Redo protocol version negotiation to avoid problems with old + servers (it still works with servers using the old negotiation, + as well as servers not supporting negotiation) + Error handling cleanups + Add some new authentication libpcap error codes for specific + errors + Fix some inetd issues in rpcapd + Fix rpcapd core dumps with invalid configuration file + On UN*X, don't have rpcapd tell the client why authentication + failed, so a brute-force attacker can't distinguish between + "unknown user name" and "known user name, wrong password" + Allow rpcapd to rebind more rapidly (GitHub issue #765) + Documentation: + Improve man pages, including adding backward compatibility notes + Building and testing: + Require, and assume, some level of C99 support in the C compiler + Require Visual Studio 2015 or later if using Visual Studio + Fix configure script issues, including with libnl on Linux + Fix CMake issues + Squelch complaints from Bison about "%define api.pure" being + deprecated + Fix compilation of pcap-tc.c + Linux: + Require PF_PACKET support, and kernel 2.6.27 or later + Handle systems without AF_INET or AF_UNIX socket support + Get rid of Wireless Extensions for turning monitor mode on + Proper memory sync for PACKET_MMAP (may prevent GitHub issue + #898) + Drop support for libnl 1 and 2. + Return error on interface going away, but not if it just went + down but is still present + Set socket protocol only after packet ring configured, + reducing bogus packet drop reports + Get ifdrop stats from sysfs. + When adjusting BPF programs, do not subtract the + SLL[2]_HDR_LEN if the location is negative (special metadata + offset), to preserve references to metadata; see + https://github.com/the-tcpdump-group/tcpdump/issues/480#issuecomment-486827278 + Report a warning for unknown ARPHRD types + Have pcap_breakloop() forcibly break out of a sleeping + capture loop + Add support for DSA data link types + For raw USB bus capture, use the snapshot length to set the + buffer size, and set the len field to reflect the length + in the URB (GitHub issue #808) + With a timeout of zero, wait indefinitely + Clean up support for some non-GNU libc C libraries + Add DLT_LINUX_SLL2 for cooked-mode captures + Probe CONFIGURATION descriptor of connected USB devices + Treat EPERM on ethtool ioctls as meaning "not supported", as + permissions checks are done before checking whether the + ioctl is supported at all + macOS: + Cope with getting EPWROFF from SIOCGIFMEDIA + Treat EPERM on SIOCGIFMEDIA as meaning "not supported", as + permissions checks are done before checking whether the + ioctl is supported at all + Treat ENXIO when reading packets as meaning "the interface + was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + FreeBSD: + Treat ENXIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + NetBSD: + Treat ENXIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + OpenBSD: + Treat EIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + DragonFly BSD: + Treat ENXIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + Solaris: + Treat ENXIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + AIX: + Fix loading of BPF kernel extension + Treat ENXIO as meaning "the interface was removed" + Report "the interface disappeared", not "the interface went + down", if the interface was removed during a capture + Windows: + Make the snapshot length work even if pcap_setfilter() + isn't called + Fix compilation on Cygwin/MSYS + Add pcap_handle(), and deprecate pcap_fileno() + Report PCAP_ERROR_NO_SUCH_DEVICE for a nonexistent device + Return an appropriate error message for device removed or + device unusable due to a suspend/resume + Report a warning for unknown NdisMedium types + Have pcap_breakloop() forcibly break out of a sleeping + capture loop + Clean up building DLL + Handle CRT mismatch for pcap_dump_fopen() + Map NdisMediumWirelessWan to DLT_RAW + Add AirPcap support in a module, rather than using + WinPcap/Npcap's support for it + Report the system error for PacketSetHwFilter() failures + Add support for getting and setting packet time stamp types + with Npcap + Have pcap_init() allow selecting whether the API should use + local code page strings or UTF-8 strings (including error + messages) + Haiku: + Add capture support + +Sunday, July 22, 2018 + Summary for 1.9.1 libpcap release + Mention pcap_get_required_select_timeout() in the main pcap man page + Fix pcap-usb-linux.c build on systems with musl + Fix assorted man page and other documentation issues + Plug assorted memory leaks + Documentation changes to use https: + Changes to how time stamp calculations are done + Lots of tweaks to make newer compilers happier and warning-free and + to fix instances of C undefined behavior + Warn if AC_PROG_CC_C99 can't enable C99 support + Rename pcap_set_protocol() to pcap_set_protocol_linux(). + Align pcap_t private data on an 8-byte boundary. + Fix various error messages + Use 64-bit clean API in dag_findalldevs() + Fix cleaning up after some errors + Work around some ethtool ioctl bugs in newer Linux kernels (GitHub + issue #689) + Add backwards compatibility sections to some man pages (GitHub issue + #745) + Fix autotool configuration on AIX and macOS + Don't export bpf_filter_with_aux_data() or struct bpf_aux_data; + they're internal-only and subject to change + Fix pcapng block size checking + On macOS, don't build rpcapd or test programs any fatter than they + need to be + Fix reading of capture statistics for Linux USB + Fix packet size values for Linux USB packets (GitHub issue #808) + Check only VID in VLAN test in filters (GitHub issue #461) + Fix pcap_list_datalinks on 802.11 devices on macOS + Fix overflows with very large snapshot length in pcap file + Improve parsing of rpcapd configuration file (GitHub issue #767) + Handle systems without strlcpy() or strlcat() better + Fix crashes and other errors with invalid filter expressions + Fix use of uninitialized file descriptor in remote capture + Fix some CMake issues + Fix some divide-by-zero issues with the filter compiler + Work around a GNU libc bug in pcap_nametonetaddr() + Add support for DLT_LINUX_SLL2 + Fix handling of the packet-count argument for Myricom SNF devices + Fix --disable-rdma in configure script (GitHub issue #782) + Fix compilation of TurboCap support (GitHub issue #764) + Constify first argument to pcap_findalldevs_ex() + Fix a number of issues when running rpcapd as an inetd-style daemon + Fix CMake issues with D-Bus libraries + In rpcapd, clean up termination of a capture session + Redo remote capture protocol negotiation + In rpcapd, report the same error for "invalid user name" and + "invalid password", to make brute-forcing harder + For remote captures, add an error code for "the server requires TLS" + Fix pcap_dump_fopen() on Windows to avoid clashes between + {Win,N}Pcap and application C runtimes + Fix exporting of functions from Windows DLLs (GitHub issue #810) + Fix building as part of Npcap + Allow rpcapd to rebind more rapidly + Fix building shared libpcap library on midipix (midipix.org) + Fix hack to detect UTF-16LE adapter names on Windows not to go past + the end of the string + Fix handling of "wireless WAN" (mobile phone network modems) on + Windows with WinPcap/Npcap (GitHub issue #824) + Have pcap_dump_open_append() create the dump file if it doesn't + exists (GitHub issue #247) + Fix the maximum snapshot length for DLT_USBPCAP + Use -fPIC when building for 64-bit SPARC on Linux (GitHub issue #837) + Fix CMake 64-bit library installation directory on some Linux + distributions + Boost the TPACKET_V3 timeout to the maximum if a timeout of 0 was + specified + Five CVE-2019-15161, CVE-2019-15162, CVE-2019-15163, CVE-2019-15164, CVE-2019-15165 + PCAPNG reader applies some sanity checks before doing malloc(). + +Sunday, June 24, 2018, by mcr@sandelman.ca + Summary for 1.9.0 libpcap release + Added testing system to libpcap, independent of tcpdump + Changes to how pcap_t is activated + Adding support for Large stream buffers on Endace DAG cards + Changes to BSD 3-clause license to 2-clause license + Additions to TCP header parsing, per RFC3168 + Add CMake build process (extensive number of changes) + Assign a value for OpenBSD DLT_OPENFLOW. + Support setting non-blocking mode before activating. + Extensive build support for Windows VS2010 and MINGW (many many changes, over many months) + Added RPCAPD support when --enable-remote (default no) + Add the rpcap daemon source and build instructions. + Put back the greasy "save the capture filter string so we can tweak it" + hack, that keeps libpcap from capturing rpcap traffic. + Fixes for captures on MacOS, utun0 + fixes so that non-AF_INET addresses, are not ==AF_INET6 addresses. + Add a linktype for IBM SDLC frames containing SNA PDUs. + pcap_compile() in 1.8.0 and later is newly thread-safe. + bound snaplen for linux tpacket_v2 to ~64k + Make VLAN filter handle both metadata and inline tags + D-Bus captures can now be up to 128MB in size + Added LORATAP DLT value + Added DLT_VSOCK for https://qemu-project.org/Features/VirtioVsock + probe_devices() fixes not to overrun buffer for name of device + Add linux-specific pcap_set_protocol_linux() to allow specifying a specific capture protocol. + RDMA sniffing support for pcap + Add Nordic Semiconductor Bluetooth LE sniffer link-layer header type. + fixes for reading /etc/ethers + Make it possible to build on Windows without packet.dll. + Add tests for large file support on UN*X. + Solaris fixes to work with 2.8.6 + configuration test now looks for header files, not capture devices present + Fix to work with Berkeley YACC. + fixes for DragonBSD compilation of pcap-netmap.c + Clean up the ether_hostton() stuff. + Add an option to disable Linux memory-mapped capture support. + Add DAG API support checks. + Add Septel, Myricom SNF, and Riverbed TurboCap checks. + Add checks for Linux USB, Linux Bluetooth, D-Bus, and RDMA sniffing support. + Add a check for hardware time stamping on Linux. + Don't bother supporting pre-2005 Visual Studio. + Increased minimum autoconf version requirement to 2.64 + Add DLT value 273 for XRA-31 sniffer + Clean up handing of signal interrupts in pcap_read_nocb_remote(). + Use the XPG 4.2 versions of the networking APIs in Solaris. + Fix, and better explain, the "IPv6 means IPv6, not IPv4" option setting. + Explicitly warn that negative packet buffer timeouts should not be used. + rpcapd: Add support inetd-likes, including xinetd.conf, and systemd units + Rename DLT_IEEE802_15_4 to DLT_IEEE802_15_4_WITHFCS. + Add DISPLAYPORT AUX link type + Remove the sunos4 kernel modules and all references to them. + Add more interface flags to pcap_findalldevs(). + Summary for 1.9.0 libpcap release (to 2017-01-25 by guy@alum.mit.edu) + Man page improvements + Fix Linux cooked mode userspace filtering (GitHub pull request #429) + Fix compilation if IPv6 support not enabled + Fix some Linux memory-mapped capture buffer size issues + Don't fail if kernel filter can't be set on Linux (GitHub issue + #549) + Improve sorting of interfaces for pcap_findalldevs() + Don't list Linux usbmon devices if usbmon module isn't loaded + Report PCAP_ERROR_PERM_DENIED if no permission to open Linux usbmon + devices + Fix DLT_ type for Solaris IPNET devices + Always return an error message for errors finding DAG or Myricom + devices + If possible, don't require that a device be openable when + enumerating them for pcap_findalldevs() + Don't put incompletely-initialized addresses in the address list for + When finding Myricom devices, update description for regular + interfaces that are Myricom devices and handle SNF_FLAGS=0x2(port + aggregation enabled) + Fix compilation error in DAG support + Fix issues with CMake configuration + Add support for stream buffers larger than 2GB on newer DAG cards + Remove support for building against DAG versions without STREAMS + support (before dag-3.0.0 2007) + +Tuesday, Oct. 25, 2016 mcr@sandelman.ca + Summary for 1.8.1 libpcap release + Add a target in Makefile.in for Exuberant Ctags use: 'extags'. + Rename configure.in to configure.ac: autoconf 2.59 + Clean up the name-to-DLT mapping table. + Add some newer DLT_ values: IPMI_HPM_2,ZWAVE_R1_R2,ZWAVE_R3,WATTSTOPPER_DLM,ISO_14443,RDS + Clarify what the return values are for both success and failure. + Many changes to build on windows + Check for the "break the loop" condition in the inner loop for TPACKET_V3. + Fix handling of packet count in the TPACKET_V3 inner loop: GitHub issue #493. + Filter out duplicate looped back CAN frames. + Fix the handling of loopback filters for IPv6 packets. + Add a link-layer header type for RDS (IEC 62106) groups. + Use different intermediate folders for x86 and x64 builds on Windows. + On Linux, handle all CAN captures with pcap-linux.c, in cooked mode. + Removes the need for the "host-endian" link-layer header type. + Compile with '-Wused-but-marked-unused' in devel mode if supported + Have separate DLTs for big-endian and host-endian SocketCAN headers. + Reflect version.h being renamed to pcap_version.h. + Require that version.h be generated: all build procedures we support generate version.h (autoconf, CMake, MSVC)! + Properly check for sock_recv() errors. + Re-impose some of Winsock's limitations on sock_recv(). + Replace sprintf() with pcap_snprintf(). + Fix signature of pcap_stats_ex_remote(). + Initial cmake support for remote packet capture. + Have rpcap_remoteact_getsock() return a SOCKET and supply an "is active" flag. + Clean up {DAG, Septel, Myricom SNF}-only builds. + Do UTF-16-to-ASCII conversion into the right place. + pcap_create_interface() needs the interface name on Linux. + Clean up hardware time stamp support: the "any" device does not support any time stamp types. + Add support for capturing on FreeBSD usbusN interfaces. + Add a LINKTYPE/DLT_ value for FreeBSD USB. + Go back to using PCAP_API on Windows. + CMake support + Add TurboCap support from WinPcap. + Recognize 802.1ad nested VLAN tag in vlan filter. + +Thursday Sep. 3, 2015 guy@alum.mit.edu + Summary for 1.7.5 libpcap release + Man page cleanups. + Add some allocation failure checks. + Fix a number of Linux/ucLinux configure/build issues. + Fix some memory leaks. + Recognize 802.1ad nested VLAN tag in vlan filter. + Fix building Bluetooth Linux Monitor support with BlueZ 5.1+ + +Saturday Jun. 27, 2015 mcr@sandelman.ca + Summary for 1.7.4 libpcap release + Include fix for GitHub issue #424 -- out of tree builds. + +Friday Apr. 10, 2015 guy@alum.mit.edu + Summary for 1.7.3 libpcap release + Work around a Linux bonding driver bug. + +Thursday Feb. 12, 2015 guy@alum.mit.edu/mcr@sandelman.ca + Summary for 1.7.2 libpcap release + Support for filtering Geneve encapsulated packets. + Generalize encapsulation handling, fixing some bugs. + Don't add null addresses to address lists. + Add pcap_dump_open_append() to open for appending. + Fix the swapping of isochronous descriptors in Linux USB. + Attempt to handle TPACKET_V1 with 32-bit userland and 64-bit kernel. + +Wednesday Nov. 12, 2014 guy@alum.mit.edu/mcr@sandelman.ca + Summary for 1.7.0 libpcap release + Fix handling of zones for BPF on Solaris + new DLT for ZWAVE + clarifications for read timeouts. + Use BPF extensions in compiled filters, fixing VLAN filters + some fixes to compilation without stdint.h + EBUSY can now be returned by SNFv3 code. + Fix the range checks in BPF loads + Various DAG fixes. + Various Linux fixes. + +Monday Aug. 12, 2014 guy@alum.mit.edu + Summary for 1.6.2 libpcap release + Don't crash on filters testing a nonexistent link-layer type + field. + Fix sending in non-blocking mode on Linux with memory-mapped + capture. + Fix timestamps when reading pcap-ng files on big-endian + machines. + +Saturday Jul. 19, 2014 mcr@sandelman.ca + Summary for 1.6.1 libpcap release + some fixes for the any device + changes for how --enable-XXX (--enable-sniffing, --enable-can) works + +Wednesday Jul. 2, 2014 mcr@sandelman.ca + Summary for 1.6.0 libpcap release + Don't support D-Bus sniffing on OS X + fixes for byte order issues with NFLOG captures + Handle using cooked mode for DLT_NETLINK in activate_new(). + on platforms where you can not capture on down interfaces, do not list them + but: do list interfaces which are down, if you can capture on them! + +Wednesday December 18, 2013 guy@alum.mit.edu +Summary for 1.5.3 libpcap release + Don't let packets that don't match the current filter get to the + application when TPACKET_V3 is used. (GitHub issue #331) + Fix handling of pcap_loop()/pcap_dispatch() with a packet count + of 0 on some platforms (including Linux with TPACKET_V3). + (GitHub issue #333) + Work around TPACKET_V3 deficiency that causes packets to be lost + when a timeout of 0 is specified. (GitHub issue #335) + Man page formatting fixes. + +Wednesday December 4, 2013 guy@alum.mit.edu +Summary for 1.5.2 libpcap release + Fix libpcap to work when compiled with TPACKET_V3 support and + running on a kernel without TPACKET_V3 support. (GitHub + issue #329) + +Wednesday November 20, 2013 guy@alum.mit.edu +Summary for 1.5.1 libpcap release + Report an error, rather than crashing, if an IPv6 address is + used for link-layer filtering. (Wireshark bug 9376) + +Wednesday October 30, 2013 guy@alum.mit.edu +Summary for 1.5.0 libpcap release + TPACKET_V3 support added for Linux + Point users to the the-tcpdump-group repository on GitHub rather + than the mcr repository + Checks added for malloc()/realloc()/etc. failures + Fixed build on Solaris 11 + Support filtering E1 SS7 traffic on MTP2 layer Annex A + Use "ln -s" to link man pages by default + Add support for getting nanosecond-resolution time stamps when + capturing and reading capture files + Many changes to autoconf to deal better with non-GCC compilers + added many new DLT types + +Saturday April 6, 2013 guy@alum.mit.edu +Summary for 1.4.0 libpcap release + Add netfilter/nfqueue interface. + If we don't have support for IPv6 address resolution, support, + in filter expressions, what IPv6 stuff we can. + Fix pcap-config to include -lpthread if canusb support is + present + Try to fix "pcap_parse not defined" problems when --without-flex + and --without-bison are used when you have Flex and Bison + Fix some issues with the pcap_loop man page. + Fix pcap_getnonblock() and pcap_setnonblock() to fill in the + supplied error message buffer + Fix typo that, it appeared, would cause pcap-libdlpi.c not to + compile (perhaps systems with libdlpi also have BPF and use + that instead) + Catch attempts to call pcap_compile() on a non-activated pcap_t + Fix crash on Linux with CAN-USB support without usbfs + Fix addition of VLAN tags for Linux cooked captures + Check for both EOPNOTSUPP and EINVAL after SIOCETHTOOL ioctl, so + that the driver can report either one if it doesn't support + SIOCETHTOOL + Add DLT_INFINIBAND and DLT_SCTP + Describe "proto XXX" and "protochain XXX" in the pcap-filter man + page + Handle either directories, or symlinks to directories, that + correspond to interfaces in /sys/class/net + Fix handling of VLAN tag insertion to check, on Linux 3.x + kernels, for VLAN tag valid flag + Clean up some man pages + Support libnl3 as well as libnl1 and libnl2 on Linux + Fix handling of Bluetooth devices on 3.x Linux kernels + +Friday March 30, 2012. mcr@sandelman.ca +Summary for 1.3.0 libpcap release + Handle DLT_PFSYNC in {FreeBSD, other *BSD+Mac OS X, other}. + Linux: Don't fail if netfilter isn't enabled in the kernel. + Add new link-layer type for NFC Forum LLCP. + Put the CANUSB stuff into EXTRA_DIST, so it shows up in the release tarball. + Add LINKTYPE_NG40/DLT_NG40. + Add DLT_MPEG_2_TS/LINKTYPE_MPEG_2_TS for MPEG-2 transport streams. + [PATCH] Fix AIX-3.5 crash with read failure during stress + AIX fixes. + Introduce --disable-shared configure option. + Added initial support for canusb devices. + Include the pcap(3PCAP) additions as 1.2.1 changes. + many updates to documentation: pcap.3pcap.in + Improve 'inbound'/'outbound' capture filters under Linux. + Note the cleanup of handling of new DLT_/LINKTYPE_ values. + On Lion, don't build for PPC. + For mac80211 devices we need to clean up monitor mode on exit. + +Friday December 9, 2011. guy@alum.mit.edu. +Summary for 1.2.1 libpcap release + Update README file. + Fix typos in README.linux file. + Clean up some compiler warnings. + Fix Linux compile problems and tests for ethtool.h. + Treat Debian/kFreeBSD and GNU/Hurd as systems with GNU + toolchains. + Support 802.1 QinQ as a form of VLAN in filters. + Treat "carp" as equivalent to "vrrp" in filters. + Fix code generated for "ip6 protochain". + Add some new link-layer header types. + Support capturing NetFilter log messages on Linux. + Clean up some error messages. + Turn off monitor mode on exit for mac80211 interfaces on Linux. + Fix problems turning monitor mode on for non-mac80211 interfaces + on Linux. + Properly fail if /sys/class/net or /proc/net/dev exist but can't + be opened. + Fail if pcap_activate() is called on an already-activated + pcap_t, and add a test program for that. + Fix filtering in pcap-ng files. + Don't build for PowerPC on Mac OS X Lion. + Simplify handling of new DLT_/LINKTYPE_ values. + Expand pcap(3PCAP) man page. + +Sunday July 24, 2011. mcr@sandelman.ca. +Summary for 1.2 libpcap release + All of the changes listed below for 1.1.1 and 1.1.2. + Changes to error handling for pcap_findalldevs(). + Fix the calculation of the frame size in memory-mapped captures. + Add a link-layer header type for STANAG 5066 D_PDUs. + Add a link-layer type for a variant of 3GPP TS 27.010. + Noted real nature of LINKTYPE_ARCNET. + Add a link-layer type for DVB-CI. + Fix configure-script discovery of VLAN acceleration support. + see https://netoptimizer.blogspot.com/2010/09/tcpdump-vs-vlan-tags.html + Linux, HP-UX, AIX, NetBSD and OpenBSD compilation/conflict fixes. + Protect against including AIX 5.x's having been included. + Add DLT_DBUS, for raw D-Bus messages. + Treat either EPERM or EACCES as "no soup for you". + Changes to permissions on DLPI systems. + Add DLT_IEEE802_15_4_NOFCS for 802.15.4 interfaces. + +Fri. August 6, 2010. guy@alum.mit.edu. +Summary for 1.1.2 libpcap release + Return DLT_ values, not raw LINKTYPE_ values from + pcap_datalink() when reading pcap-ng files + Add support for "wlan ra" and "wlan ta", to check the RA and TA + of WLAN frames that have them + Don't crash if "wlan addr{1,2,3,4}" are used without 802.11 + headers + Do filtering on USB and Bluetooth capturing + On FreeBSD/SPARC64, use -fPIC - it's apparently necessary + Check for valid port numbers (fit in a 16-bit unsigned field) in + "port" filters + Reject attempts to put savefiles into non-blocking mode + Check for "no such device" for the "get the media types" ioctl + in *BSD + Improve error messages from bpf_open(), and let it do the error + handling + Return more specific errors from pcap_can_set_rfmon(); fix + documentation + Update description fetching code for FreeBSD, fix code for + OpenBSD + Ignore /sys/net/dev files if we get ENODEV for them, not just + ENXIO; fixes handling of bonding devices on Linux + Fix check for a constant 0 argument to BPF_DIV + Use the right version of ar when cross-building + Free any filter set on a savefile when the savefile is closed + Include the CFLAGS setting when configure was run in the + compiler flags + Add support for 802.15.4 interfaces on Linux + +Thu. April 1, 2010. guy@alum.mit.edu. +Summary for 1.1.1 libpcap release + Update CHANGES to reflect more of the changes in 1.1.0. + Fix build on RHEL5. + Fix shared library build on AIX. + +Thu. March 11, 2010. ken@netfunctional.ca/guy@alum.mit.edu. +Summary for 1.1.0 libpcap release + Add SocketCAN capture support + Add Myricom SNF API support + Update Endace DAG and ERF support + Add support for shared libraries on Solaris, HP-UX, and AIX + Build, install, and un-install shared libraries by default; + don't build/install shared libraries on platforms we don't support + Fix building from a directory other than the source directory + Fix compiler warnings and builds on some platforms + Update config.guess and config.sub + Support monitor mode on mac80211 devices on Linux + Fix USB memory-mapped capturing on Linux; it requires a new DLT_ + value + On Linux, scan /sys/class/net for devices if we have it; scan + it, or /proc/net/dev if we don't have /sys/class/net, even if + we have getifaddrs(), as it'll find interfaces with no + addresses + Add limited support for reading pcap-ng files + Fix BPF driver-loading error handling on AIX + Support getting the full-length interface description on FreeBSD + In the lexical analyzer, free up any addrinfo structure we got back + from getaddrinfo(). + Add support for BPF and libdlpi in OpenSolaris (and SXCE) + Hyphenate "link-layer" everywhere + Add /sys/kernel/debug/usb/usbmon to the list of usbmon locations + In pcap_read_linux_mmap(), if there are no frames available, call + poll() even if we're in non-blocking mode, so we pick up + errors, and check for the errors in question. + Note that poll() works on BPF devices is Snow Leopard + If an ENXIO or ENETDOWN is received, it may mean the device has + gone away. Deal with it. + For BPF, raise the default capture buffer size to from 32k to 512k + Support ps_ifdrop on Linux + Added a bunch of #ifdef directives to make wpcap.dll (WinPcap) compile + under cygwin. + Changes to Linux mmapped captures. + Fix bug where create_ring would fail for particular snaplen and + buffer size combinations + Update pcap-config so that it handles libpcap requiring + additional libraries + Add workaround for threadsafeness on Windows + Add missing mapping for DLT_ENC <-> LINKTYPE_ENC + DLT: Add DLT_CAN_SOCKETCAN + DLT: Add Solaris ipnet + Don't check for DLT_IPNET if it's not defined + Add link-layer types for Fibre Channel FC-2 + Add link-layer types for Wireless HART + Add link-layer types for AOS + Add link-layer types for DECT + Autoconf fixes (AIX, HP-UX, OSF/1, Tru64 cleanups) + Install headers unconditionally, and include vlan.h/bluetooth.h if + enabled + Autoconf fixes+cleanup + Support enabling/disabling bluetooth (--{en,dis}able-bluetooth) + Support disabling SITA support (--without-sita) + Return -1 on failure to create packet ring (if supported but + creation failed) + Fix handling of 'any' device, so that it can be opened, and no longer + attempt to open it in Monitor mode + Add support for snapshot length for USB Memory-Mapped Interface + Fix configure and build on recent Linux kernels + Fix memory-mapped Linux capture to support pcap_next() and + pcap_next_ex() + Fixes for Linux USB capture + DLT: Add DLT_LINUX_EVDEV + DLT: Add DLT_GSMTAP_UM + DLT: Add DLT_GSMTAP_ABIS + +Mon. October 27, 2008. ken@netfunctional.ca. Summary for 1.0.0 libpcap release + Compile with IPv6 support by default + Compile with large file support on by default + Add pcap-config script, which deals with -I/-L flags for compiling + DLT: Add IPMB + DLT: Add LAPD + DLT: Add AX25 (AX.25 w/KISS header) + DLT: Add JUNIPER_ST + 802.15.4 support + Variable length 802.11 header support + X2E data type support + SITA ACN Interface support - see README.sita + Support for memory-mapped capture on Linux + Support for zerocopy BPF on platforms that support it + Support for setting buffer size when opening devices + Support for setting monitor mode when opening 802.11 devices + Better support for dealing with VLAN tagging/stripping on Linux + Fix dynamic library support on OSX + Return PCAP_ERROR_IFACE_NOT_UP if the interface isn't 'UP', so applications + can print better diagnostic information + Return PCAP_ERROR_PERM_DENIED if we don't have permission to open a device, so + applications can tell the user they need to go play with permissions + On Linux, ignore ENETDOWN so we can continue to capture packets if the + interface goes down and comes back up again. + On Linux, support new tpacket frame headers (2.6.27+) + On Mac OS X, add scripts for changing permissions on /dev/bpf* and launchd plist + On Solaris, support 'passive mode' on systems that support it + Fixes to autoconf and general build environment + Man page reorganization + cleanup + Autogenerate VERSION numbers better + +Mon. September 10, 2007. ken@xelerance.com. Summary for 0.9.8 libpcap release + Change build process to put public libpcap headers into pcap subdir + DLT: Add value for IPMI IPMB packets + DLT: Add value for u10 Networks boards + Require for pf definitions - allows reading of pflog formatted + libpcap files on an OS other than where the file was generated + +Wed. April 25, 2007. ken@xelerance.com. Summary for 0.9.6 libpcap release + + Put the public libpcap headers into a pcap subdirectory in both the + source directory and the target include directory, and have include + files at the top-level directory to include those headers, for + backwards compatibility. + Add Bluetooth support + Add USB capturing support on Linux + Add support for the binary USB sniffing interface in Linux + Add support for new FreeBSD BIOCSDIRECTION ioctl + Add additional filter operations for 802.11 frame types + Add support for filtering on MTP2 frame types + Propagate some changes from the main branch, so the x.9 branch has + all the DLT_ and LINKTYPE_ values that the main branch does + Reserved a DLT_ and SAVEFILE_ value for PPI (Per Packet Info) + encapsulated packets + Add LINKTYPE_ for IEEE 802.15.4, with address fields padded as done + by Linux drivers + Add LINKTYPE_ value corresponding to DLT_IEEE802_16_MAC_CPS. + Add DLT for IEEE 802.16 (WiMAX) MAC Common Part Sublayer + Add DLT for Bluetooth HCI UART transport layer + When building a shared library, build with "-fPIC" on Linux to support x86_64 + Link with "$(CC) -shared" rather than "ld -shared" when building a + ".so" shared library + Add support for autoconf 2.60 + Fixes to discard unread packets when changing filters + Changes to handle name changes in the DAG library resulting from + switching to libtool. + Add support for new DAG ERF types. + Add an explicit "-ldag" when building the shared library, so the DAG + library dependency is explicit. + Mac OSX fixes for dealing with "wlt" devices + Fixes in add_or_find_if() & pcap_findalldevs() to optimize generating + device lists + Fixed a bug in pcap_open_live(). The return value of PacketSetHwFilter + was not checked. + +Tue. September 19, 2006. ken@xelerance.com. Summary for 0.9.5 libpcap release + + Support for LAPD frames with vISDN + Support for ERF on channelized T1/E1 cards via DAG API + Fix capitalization that caused issues crossc compiling on Linux + Better failure detection on PacketGetAdapterNames() + Fixes for MPLS packet generation (link layer) + OP_PACKET now matches the beginning of the packet, instead of + beginning+link-layer + Add DLT/LINKTYPE for carrying FRF.16 Multi-link Frame Relay + Fix allocation of buffer for list of link-layer types + Added a new DLT and LINKTYPE value for ARINC 653 Interpartition Communication Messages + Fixed a typo in a DLT value: it should start with DLT_ and not LINKTYPE_ + Redefined DLT_CAN20B and LINKTYPE_CAN20B as #190 (as this is the right value for CAN). + Added definition for DLT_A429 and LINKTYPE_A429 as #184. + Added a new DLT and LINKTYPE value for CAN v2.0B frames. + Add support for DLT_JUNIPER_VP. + Don't double-count received packets on Linux systems that + support the PACKET_STATISTICS getsockopt() argument on + PF_PACKET sockets. + Add support for DLT_IEEE802_11 and DLT_IEEE802_11_RADIO link + layers in Windows + Add support to build libpcap.lib and wpcap.dll under Cygnus and + MingW32. + +Mon. September 5, 2005. ken@xelerance.com. Summary for 0.9.4 libpcap release + + Support for radiotap on Linux (Mike Kershaw) + Fixes for HP-UX + Support for additional Juniper link-layer types + Fixes for filters on MPLS-encapsulated packets + "vlan" filter fixed + "pppoed" and "pppoes" filters added; the latter modifies later + parts of the filter expression to look at the PPP headers and + headers in the PPP payload + +Tue. July 5, 2005. ken@xelerance.com. Summary for 0.9.3 libpcap release + + Fixes for compiling on nearly every platform, + including improved 64bit support + MSDOS Support + Add support for sending packets + OpenBSD pf format support + IrDA capture (Linux only) + +Tue. March 30, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.3 release + + Fixed minor problem in gencode.c that would appear on 64-bit + platforms. + Version number is now sane. + +Mon. March 29, 2004. mcr@sandelman.ottawa.on.ca. Summary for 3.8.2 release + + updates for autoconf 2.5 + fixes for ppp interfaces for freebsd 4.1 + pcap gencode can generate code for 802.11, IEEE1394, and pflog. + +Wed. November 12, 2003. mcr@sandelman.ottawa.on.ca. Summary for 0.8 release + + added pcap_findalldevs() + Win32 patches from NetGroup, Politecnico di Torino (Italy) + OpenBSD pf, DLT_PFLOG added + Many changes to ATM support. + lookup pcap_lookupnet() + Added DLT_ARCNET_LINUX, DLT_ENC, DLT_IEEE802_11_RADIO, DLT_SUNATM, + DLT_IP_OVER_FC, DLT_FRELAY, others. + Sigh. More AIX wonderfulness. + Document updates. + Changes to API: pcap_next_ex(), pcap_breakloop(), pcap_dump_flush(), + pcap_list_datalinks(), pcap_set_datalink(), + pcap_lib_version(), pcap_datalink_val_to_name(), + pcap_datalink_name_to_val(), new error returns. + +Tuesday, February 25, 2003. fenner@research.att.com. 0.7.2 release + + Support link types that use 802.2 always, never, and sometimes. + Don't decrease the size of the BPF buffer from the default. + Support frame relay. + Handle 32-bit timestamps in DLPI, and pass the right buffer size. + Handle Linux systems with modern kernel but without + SOL_PACKET in the userland headers. + Linux support for ARPHRD_RAWHDLC. + Handle 32-bit timestamps in snoop. + Support eg (Octane/O2xxx/O3xxx Gigabit) devices. + Add new reserved DLT types. + +Monday October 23, 2001. mcr@sandelman.ottawa.on.ca. Summary for 0.7 release + + Added pcap_findalldevs() call to get list of interfaces in a MI way. + + pcap_stats() has been documented as to what its counters mean on + each platform. + +Tuesday January 9, 2001. guy@alum.mit.edu. Summary for 0.6 release + + New Linux libpcap implementation, which, in 2.2 and later + kernels, uses PF_PACKET sockets and supports kernel packet + filtering (if compiled into the kernel), and supports the "any" + device for capturing on all interfaces. Cleans up promiscuous + mode better on pre-2.2 kernels, and has various other fixes + (handles 2.4 ARPHRD_IEEE802_TR, handles ISDN devices better, + doesn't show duplicate packets on loopback interface, etc.). + + Fixed HP-UX libpcap implementation to correctly get the PPA for + an interface, to allow interfaces to be opened by interface name. + + libpcap savefiles have system-independent link-layer type values + in the header, rather than sometimes platform-dependent DLT_ + values, to make it easier to exchange capture files between + different OSes. + + Non-standard capture files produced by some Linux tcpdumps, e.g. + the one from Red Hat Linux 6.2 and later, can now be read. + + Updated autoconf stock files. + + Filter expressions can filter on VLAN IDs and various OSI + protocols, and work on Token Ring (with non-source-routed + packets). + + "pcap_open_dead()" added to allow compiling filter expressions + to pcap code without opening a capture device or capture file. + + Header files fixed to allow use in C++ programs. + + Removed dependency on native headers for packet layout. + Removed Linux specific headers that were shipped. + + Security fixes: Strcpy replaced with strlcpy, sprintf replaced + with snprintf. + + Fixed bug that could cause subsequent "pcap_compile()"s to fail + erroneously after one compile failed. + + Assorted other bug fixes. + + README.aix and README.linux files added to describe + platform-specific issues. + + "getifaddrs()" rather than SIOCGIFCONF used, if available. + +v0.5 Sat Jun 10 11:09:15 PDT 2000 + +itojun@iijlab.net +- Brought in KAME IPv6/IPsec bpf compiler. +- Fixes for NetBSD. +- Support added for OpenBSD DLT_LOOP and BSD/OS DLT_C_HDLC (Cisco HDLC), + and changes to work around different BSDs having different DLT_ types + with the same numeric value. + +Assar Westerlund +- Building outside the source code tree fixed. +- Changed to write out time stamps with 32-bit seconds and microseconds + fields, regardless of whether those fields are 32 bits or 64 bits in + the OS's native "struct timeval". +- Changed "pcap_lookupdev()" to dynamically grow the buffer into which + the list of interfaces is read as necessary in order to hold the + entire list. + +Greg Troxel +- Added a new "pcap_compile_nopcap()", which lets you compile a filter + expression into a BPF program without having an open live capture or + capture file. + +v0.4 Sat Jul 25 12:40:09 PDT 1998 + +- Fix endian problem with DLT_NULL devices. From FreeBSD via Bill + Fenner (fenner@parc.xerox.com) + +- Fix alignment problem with FDDI under DLPI. This was causing core + dumps under Solaris. + +- Added configure options to disable flex and bison. Resulted from a + bug report by barnett@grymoire.crd.ge.com (Bruce Barnett). Also added + options to disable gcc and to force a particular packet capture type. + +- Added support for Fore ATM interfaces (qaa and fa) under IRIX. Thanks + to John Hawkinson (jhawk@mit.edu) + +- Change Linux PPP and SLIP to use DLT_RAW since the kernel does not + supply any "link layer" data. + +- Change Linux to use SIOCGIFHWADDR ioctl to determine link layer type. + Thanks to Thomas Sailer (sailer@ife.ee.ethz.ch) + +- Change IRIX PPP to use DLT_RAW since the kernel does not supply any + "link layer" data. + +- Modified to support the new BSD/OS 2.1 PPP and SLIP link layer header + formats. + +- Added some new SGI snoop interface types. Thanks to Steve Alexander + (sca@refugee.engr.sgi.com) + +- Fixes for HP-UX 10.20 (which is similar to HP-UX 9). Thanks to + Richard Allen (ra@hp.is) and Steinar Haug (sthaug@nethelp.no) + +- Fddi supports broadcast as reported by Jeff Macdonald + (jeff@iacnet.com). Also correct ieee802 and arcnet. + +- Determine Linux pcap buffer size at run time or else it might not be + big enough for some interface types (e.g. FDDI). Thanks to Jes + Sorensen (Jes.Sorensen@cern.ch) + +- Fix some linux alignment problems. + +- Document promisc argument to pcap_open_live(). Reported by Ian Marsh + (ianm@sics.se) + +- Support Metricom radio packets under Linux. Thanks to Kevin Lai + (laik@gunpowder.stanford.edu) + +- Bind to interface name under Linux to avoid packets from multiple + interfaces on multi-homed hosts. Thanks to Kevin Lai + (laik@gunpowder.stanford.edu) + +- Change L_SET to SEEK_SET for HP-UX. Thanks to Roland Roberts + (rroberts@muller.com) + +- Fixed an uninitialized memory reference found by Kent Vander Velden + (graphix@iastate.edu) + +- Fixed lex pattern for IDs to allow leading digits. As reported by + Theo de Raadt (deraadt@cvs.openbsd.org) + +- Fixed Linux include file problems when using GNU libc. + +- Ifdef ARPHRD_FDDI since not all versions of the Linux kernel have it. + Reported reported by Eric Jacksch (jacksch@tenebris.ca) + +- Fixed bug in pcap_dispatch() that kept it from returning on packet + timeouts. + +- Changed ISLOOPBACK() macro when IFF_LOOPBACK isn't available to check + for "lo" followed by an eos or digit (newer versions of Linux + apparently call the loopback "lo" instead of "lo0"). + +- Fixed Linux networking include files to use ints instead of longs to + avoid problems with 64 bit longs on the alpha. Thanks to Cristian + Gafton (gafton@redhat.com) + +v0.3 Sat Nov 30 20:56:27 PST 1996 + +- Added Linux support. + +- Fixed savefile bugs. + +- Solaris x86 fix from Tim Rylance (t.rylance@elsevier.nl) + +- Add support for bpf kernel port filters. + +- Remove duplicate atalk protocol table entry. Thanks to Christian + Hopps (chopps@water.emich.edu) + +- Fixed pcap_lookupdev() to ignore nonexistent devices. This was + reported to happen under BSD/OS by David Vincenzetti + (vince@cryptonet.it) + +- Avoid solaris compiler warnings. Thanks to Bruce Barnett + (barnett@grymoire.crd.ge.com) + +v0.2.1 Sun Jul 14 03:02:26 PDT 1996 + +- Fixes for HP-UX 10. Thanks in part to Thomas Wolfram + (wolf@prz.tu-berlin.de) and Rick Jones (raj@hpisrdq.cup.hp.com) + +- Added support for SINIX. Thanks to Andrej Borsenkow + (borsenkow.msk@sni.de) + +- Fixes for AIX (although this system is not yet supported). Thanks to + John Hawkinson (jhawk@mit.edu) + +- Use autoconf's idea of the top level directory in install targets. + Thanks to John Hawkinson. + +- Add missing autoconf packet capture result message. Thanks to Bill + Fenner (fenner@parc.xerox.com) + +- Fixed padding problems in the pf module. + +- Fixed some more alignment problems on the alpha. + +- Added explicit netmask support. Thanks to Steve Nuchia + (steve@research.oknet.com) + +- Fixed to handle raw ip addresses such as 0.0.0.1 without "left + justifying" + +- Add "sca" keyword (for DEC cluster services) as suggested by Terry + Kennedy (terry@spcvxa.spc.edu) + +- Add "atalk" keyword as suggested by John Hawkinson. + +- Add "igrp" keyword. + +- Fixed HID definition in grammar.y to be a string, not a value. + +- Use $CC when checking gcc version. Thanks to Carl Lindberg + (carl_lindberg@blacksmith.com) + +- Removed obsolete reference to pcap_immediate() from the man page. + Michael Stolarchuk (mts@terminator.rs.itd.umich.edu) + +- DLT_NULL has a 4 byte family header. Thanks to Jeffrey Honig + (jch@bsdi.com) + +v0.2 Sun Jun 23 02:28:42 PDT 1996 + +- Add support for HP-UX. Resulted from code contributed by Tom Murray + (tmurray@hpindck.cup.hp.com) and Philippe-Andri Prindeville + (philipp@res.enst.fr) + +- Update INSTALL with a reminder to install include files. Thanks to + Mark Andrews (mandrews@aw.sgi.com) + +- Fix bpf compiler alignment bug on the alpha. + +- Use autoconf to detect architectures that can't handle misaligned + accesses. + +- Added loopback support for snoop. Resulted from report Steve + Alexander (sca@engr.sgi.com) + +v0.1 Fri Apr 28 18:11:03 PDT 1995 + +- Fixed compiler and optimizer bugs. The BPF filter engine uses unsigned + comparison operators, while the code generator and optimizer assumed + signed semantics in several places. Thanks to Charlie Slater + (cslater@imatek.com) for pointing this out. + +- Removed FDDI ifdef's, they aren't really needed. Resulted from report + by Gary Veum (veum@boa.gsfc.nasa.gov). + +- Add pcap-null.c which allows offline use of libpcap on systems that + don't support live package capture. This feature resulting from a + request from Jan van Oorschot (j.p.m.voorschot@et.tudelft.nl). + +- Make bpf_compile() reentrant. Fix thanks to Pascal Hennequin + (Pascal.Hennequin@hugo.int-evry.fr). + +- Port to GNU autoconf. + +- Fix pcap-dlpi.c to work with isdn. Resulted from report by Flemming + Johansen (fsj@csd.cri.dk). + +- Handle multi-digit interface unit numbers (aka ppa's) under dlpi. + Resulted from report by Daniel Ehrlich (ehrlich@cse.psu.edu). + +- Fix pcap-dlpi.c to work in non-promiscuous mode. Resulted from report + by Jeff Murphy (jcmurphy@acsu.buffalo.edu). + +- Add support for "long jumps". Thanks to Jeffrey Mogul + (mogul@pa.dec.com). + +- Fix minor problems when compiling with BDEBUG as noticed by Scott + Bertilson (scott@unet.umn.edu). + +- Declare sys_errlist "const char *const" to avoid problems under + FreeBSD. Resulted from report by jher@eden.com. + +v0.0.6 Fri Apr 28 04:07:13 PDT 1995 + +- Add missing variable declaration missing from 0.0.6 + +v0.0.5 Fri Apr 28 00:22:21 PDT 1995 + +- Workaround for problems when pcap_read() returns 0 due to the timeout + expiring. + +v0.0.4 Thu Apr 20 20:41:48 PDT 1995 + +- Change configuration to not use gcc v2 flags with gcc v1. + +- Fixed a bug in pcap_next(); if pcap_dispatch() returns 0, pcap_next() + should also return 0. Thanks to Richard Stevens (rstevens@noao.edu). + +- Fixed configure to test for snoop before dlpi to avoid problems under + IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). + +- Hack around deficiency in Ultrix's make. + +- Fix two bugs related to the Solaris pre-5.3.2 bufmod bug; handle + savefiles that have more than snapshot bytes of data in them (so we + can read old savefiles) and avoid writing such files. + +- Added checkioctl which is used with gcc to check that the + "fixincludes" script has been run. + +v0.0.3 Tue Oct 18 18:13:46 PDT 1994 + +- Fixed configure to test for snoop before dlpi to avoid problems under + IRIX 5. Thanks to J. Eric Townsend (jet@abulafia.genmagic.com). + +v0.0.2 Wed Oct 12 20:56:37 PDT 1994 + +- Implement timeout in the dlpi pcap_open_live(). Thanks to Richard + Stevens. + +- Determine pcap link type from dlpi media type. Resulted from report + by Mahesh Jethanandani (mahesh@npix.com). + +v0.0.1 Fri Jun 24 14:50:57 PDT 1994 + +- Fixed bug in nit_setflags() in pcap-snit.c. The streams ioctl timeout + wasn't being initialized sometimes resulting in an "NIOCSFLAGS: + Invalid argument" error under OSF/1. Reported by Matt Day + (mday@artisoft.com) and Danny Mitzel (dmitzel@whitney.hitc.com). + +- Turn on FDDI support by default. + +v0.0 Mon Jun 20 19:20:16 PDT 1994 + +- Initial release. + +- Fixed bug with greater/less keywords, reported by Mark Andrews + (mandrews@alias.com). + +- Fix bug where '|' was defined as BPF_AND instead of BPF_OR, reported + by Elan Amir (elan@leeb.cs.berkeley.edu). + +- Machines with little-endian byte ordering are supported thanks to + Jeff Mogul. + +- Add hack for version 2.3 savefiles which don't have caplen and len + swapped thanks to Vern Paxson. + +- Added "&&" and "||" aliases for "and" and "or" thanks to Vern Paxson. + +- Added length, inbound and outbound keywords. diff --git a/src/libpcap-1.10.5/CMakeLists.txt b/src/libpcap-1.10.5/CMakeLists.txt new file mode 100644 index 0000000000..9012ef4176 --- /dev/null +++ b/src/libpcap-1.10.5/CMakeLists.txt @@ -0,0 +1,3612 @@ +if(WIN32) + # + # We need 3.12 or later, so that we can set policy CMP0074; see + # below. + # + cmake_minimum_required(VERSION 3.12) +else(WIN32) + # + # For now: + # + # if this is a version of CMake less than 3.5, require only + # 2.8.12, just in case somebody is configuring with CMake + # on a "long-term support" version # of some OS and that + # version supplies an older version of CMake; + # + # otherwise, require 3.5, so we don't get messages warning + # that support for versions of CMake lower than 3.5 is + # deprecated. + # + if(CMAKE_VERSION VERSION_LESS "3.5") + cmake_minimum_required(VERSION 2.8.12) + else() + cmake_minimum_required(VERSION 3.5) + endif() +endif(WIN32) + +# +# Apple doesn't build with an install_name starting with @rpath, and +# neither do we with autotools; don't do so with CMake, either, and +# suppress warnings about that. +# +# Setting CMAKE_MACOSX_RPATH to FALSE uses the old behavior, +# but removes the POLICY CMP0042 OLD deprecated warning. +# See https://cmake.org/cmake/help/latest/policy/CMP0042.html +# +if (NOT DEFINED CMAKE_MACOSX_RPATH) + set(CMAKE_MACOSX_RPATH FALSE) +endif() +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif() + +# +# Squelch noise about quoted strings in if() statements. +# WE KNOW WHAT WE'RE DOING, WE'RE DOING EVERYTHING THE WAY THAT NEWER +# VERSIONS OF CMAKE EXPECT BY DEFAULT, DON'T WASTE OUR TIME WITH NOISE. +# +if(POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif() + +# +# We want find_file() and find_library() to honor {packagename}_ROOT, +# as that appears to be the only way, with the Visual Studio 2019 IDE +# and its CMake support, to tell CMake where to look for the Npcap +# or WinPcap SDK. +# +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() + +# +# We want check_include_file() to honor CMAKE_REQUIRED_LIBRARIES; see +# the big comment before the check_include_file() test for +# infiniband/verbs.h for the reason. +# +if(POLICY CMP0075) + cmake_policy(SET CMP0075 NEW) +endif() + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) + +# +# We explicitly indicate what languages are used in libpcap to avoid +# checking for a C++ compiler. +# +# One reason to avoid that check is that there's no need to waste +# configuration time performing it. +# +# Another reason is that: +# +# CMake will try to determine the sizes of some data types, including +# void *, early in the process of configuration; apparently, it's done +# as part of processing the project() command. +# +# At least as of CMake 2.8.6, it does so by checking the size of +# "void *" in C, setting CMAKE_C_SIZEOF_DATA_PTR based on that, +# setting CMAKE_SIZEOF_VOID_P to that, and then checking the size +# of "void *" in C++, setting CMAKE_CXX_SIZEOF_DATA_PTR based on +# that, and then setting CMAKE_SIZEOF_VOID_P to *that*. +# +# The compile tests include whatever C flags may have been provided +# to CMake in the CFLAGS and CXXFLAGS environment variables. +# +# If you set an architecture flag such as -m32 or -m64 in CFLAGS +# but *not* in CXXFLAGS, the size for C++ will win, and hilarity +# will ensue. +# +# Or if, at least on Solaris, you have a newer version of GCC +# installed, but *not* a newer version of G++, and you have Oracle +# Studio installed, it will find GCC, which will default to building +# 64-bit, and Oracle Studio's C++ compiler, which will default to +# building 32-bit, the size for C++ will win, and, again, hilarity +# will ensue. +# +project(pcap C) + +# +# Setting CMAKE_MACOSX_RPATH to FALSE causes the installed +# libpcap.A.dylib to have just libpcap.A.dylib as the install +# name; Apple built libpcap with an install_name of /usr/lib/libpcap.A.dylib +# (back when they still shipped individual system dylibs rather than +# shipping a pre-built shared library cache, at least), and we do the +# same with autotools; do the same with CMake. +# +if (NOT DEFINED CMAKE_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) +endif() + +# +# For getting raw lists of --libs and --libs --static information from a +# pkg-config module. +# +# In CMake up to 2.8.12, pkg_check_modules() sets: +# +# _LIBRARIES, which is a list of library names to which, on +# a UN*X, -l can be prefixed - i.e., names, without extensions, +# rather than full paths to the file. +# _LIBRARY_DIRS, which is a list of paths to directories +# containing the libraries, to which, on a UN*X, -L can be +# prefixed. +# _LDFLAGS, which is a list of *all* required linker flags +# _LDFLAGS_OTHER, which is a list of all linker flags other +# than -l and -L flags +# +# In 3.0 (at least as of 3.0.2), it also sets: +# +# _LINK_LIBRARIES, which is a list of full paths to the +# library files. +# +# but if is _STATIC, _LINK_LIBRARIES is +# currently not set by CMake. +# +# Unfortunately, pkg_check_modules() sets the +# PKG_CONFIG_ALLOW_SYSTEM_LIBS environment variable when running +# pkg-config, so the output of --libs, etc. may include a -L for the +# system library, which we do *NOT* want to put in our libpcap.pc and +# pcap-config files. +# +# So we just run pkg-config ourselves, so that we get its output +# directly without any processing by CMake. +# +macro(pkg_get_link_info _prefix _package) + if (PKG_CONFIG_EXECUTABLE) + # + # Get the --libs information. + # + # We force PKG_CONFIG_ALLOW_SYSTEM_LIBS to be undefined, as + # at least some versions of CMake appear to define it in + # pkg_check_modules() before running pkg-config and *not* undefine + # it after running it. + # + unset(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS}) + set(_pkg_config_result "") + execute_process( + COMMAND ${PKG_CONFIG_EXECUTABLE} "--libs" ${_package} + OUTPUT_VARIABLE _pkg_config_result + RESULT_VARIABLE _pkg_config_failed + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if (_pkg_config_failed) + # + # pkg-config failed; assume that means that there is no such + # package for it to find. XXX - what do we do here? + # + set(${_prefix}_FOUND_WITH_PKG_CONFIG FALSE) + else() + # + # pkg-config succeeded; replace CR and LF with spaces. + # + string(REGEX REPLACE "[\r\n]" " " ${_prefix}_LIBS "${_pkg_config_result}") + + # + # Now get the --libs --static information. + # + set(_pkg_config_result "") + execute_process( + COMMAND ${PKG_CONFIG_EXECUTABLE} "--libs" "--static" ${_package} + OUTPUT_VARIABLE _pkg_config_result + RESULT_VARIABLE _pkg_config_failed + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if (_pkg_config_failed) + # + # pkg-config failed; assume that means that there is no such + # package for it to find. XXX - what do we do here? + # + set(${_prefix}_FOUND_WITH_PKG_CONFIG FALSE) + else() + # + # pkg-config succeeded; replace CR and LF with spaces. + # + string(REGEX REPLACE "[\r\n]" " " ${_prefix}_LIBS_STATIC "${_pkg_config_result}") + + # + # List this package in its PACKAGE_NAME variable. + # + set(${_prefix}_PACKAGE_NAME "${_package}") + + # + # It worked. + # + set(${_prefix}_FOUND_WITH_PKG_CONFIG TRUE) + endif() + endif() + endif() +endmacro() + +macro(get_link_info_from_library_path _library_prefix _library_name) + if(NOT ${_library_prefix}_LIBRARY STREQUAL "${_library_prefix}_LIBRARY-NOTFOUND") + get_filename_component(_lib_directory "${${_library_prefix}_LIBRARY}}" DIRECTORY) + + # + # The closest thing to a list of "system library directories" in + # which the linker will, by default, search for libraries appears to + # be CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES, so that's what we use + # when we're trying to construct a -L argument, for insertion into + # pcap-config and libpcap.pc, for a library upon which we depend. + # + # In some versions of CMake it appears to have duplicate entries, + # but that shouldn't affect a search for a directory in that list. + # + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_lib_directory}" _lib_index) + if(_lib_index EQUAL -1) + # + # No, so add a -L flag to get the linker to search in that + # directory. + # + set(${_library_prefix}_LIBS "-L${_lib_directory}") + set(${_library_prefix}_LIBS_STATIC "-L${_lib_directory}") + set(${_libraryprefix}_LIBS_PRIVATE "-L${_lib_directory}") + endif() + set(${_library_prefix}_LIBS "${${_library_prefix}_LIBS} -l${_library_name}") + set(${_library_prefix}_LIBS_STATIC "${${_library_prefix}_LIBS} -l${_library_name}") + set(${_library_prefix}_LIBS_PRIVATE "${${_library_prefix}_LIBS} -l${_library_name}") + endif() +endmacro() + +# +# Show the bit width for which we're compiling. +# This can help debug problems if you're dealing with a compiler that +# defaults to generating 32-bit code even when running on a 64-bit +# platform, and where that platform may provide only 64-bit versions of +# libraries that we might use (looking at *you*, Oracle Studio!). +# +if(CMAKE_SIZEOF_VOID_P EQUAL 4) + message(STATUS "Building 32-bit") +elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + message(STATUS "Building 64-bit") +endif() + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or something), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") + # + # Note: string(REPLACE) does not appear to support using ENV{...} + # as an argument, so we set a variable and then use set() to set + # the environment variable. + # + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # 64-bit build. If /usr/lib/pkgconfig appears in the path, + # prepend /usr/lib/amd64/pkgconfig to it; otherwise, + # put /usr/lib/amd64 at the end. + # + if((NOT DEFINED ENV{PKG_CONFIG_PATH}) OR "$ENV{PKG_CONFIG_PATH}" EQUAL "") + # + # Not set, or empty. Set it to /usr/lib/amd64/pkgconfig. + # + set(fixed_path "/usr/lib/amd64/pkgconfig") + elseif("$ENV{PKG_CONFIG_PATH}" MATCHES "/usr/lib/pkgconfig") + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + string(REPLACE "/usr/lib/pkgconfig" + "/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig" + fixed_path "$ENV{PKG_CONFIG_PATH}") + else() + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + set(fixed_path "$ENV{PKG_CONFIG_PATH}:/usr/lib/amd64/pkgconfig") + endif() + set(ENV{PKG_CONFIG_PATH} "${fixed_path}") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears in the path, + # prepend /usr/lib/pkgconfig to it. + # + if("$ENV{PKG_CONFIG_PATH}" MATCHES "/usr/lib/amd64/pkgconfig") + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + string(REPLACE "/usr/lib/amd64/pkgconfig" + "/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig" + fixed_path "$ENV{PKG_CONFIG_PATH}") + set(ENV{PKG_CONFIG_PATH} "${fixed_path}") + endif() + endif() +endif() + +include(CheckCCompilerFlag) + +# +# For checking if a compiler flag works and adding it if it does. +# +macro(check_and_add_compiler_option _option) + message(STATUS "Checking C compiler flag ${_option}") + string(REPLACE "=" "-" _temp_option_variable ${_option}) + string(REGEX REPLACE "^-" "" _option_variable ${_temp_option_variable}) + check_c_compiler_flag("${_option}" ${_option_variable}) + if(${${_option_variable}}) + set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} ${_option}") + endif() +endmacro() + +# +# If we're building with Visual Studio, we require Visual Studio 2015, +# in order to get sufficient C99 compatibility. Check for that. +# +# If not, try the appropriate flag for the compiler to enable C99 +# features. +# +set(C_ADDITIONAL_FLAGS "") +if(MSVC) + if(MSVC_VERSION LESS 1900) + message(FATAL_ERROR "Visual Studio 2015 or later is required") + endif() + + # + # Treat source files as being in UTF-8 with MSVC if it's not using + # the Clang front end. + # We assume that UTF-8 source is OK with other compilers and with + # MSVC if it's using the Clang front end. + # + if(NOT ${CMAKE_C_COMPILER} MATCHES "clang*") + set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} /utf-8") + endif(NOT ${CMAKE_C_COMPILER} MATCHES "clang*") +else(MSVC) + # + # For checking if a compiler flag works, failing if it doesn't, + # and adding it otherwise. + # + macro(require_and_add_compiler_option _option) + message(STATUS "Checking C compiler flag ${_option}") + string(REPLACE "=" "-" _temp_option_variable ${_option}) + string(REGEX REPLACE "^-" "" _option_variable ${_temp_option_variable}) + check_c_compiler_flag("${_option}" ${_option_variable}) + if(${${_option_variable}}) + set(C_ADDITIONAL_FLAGS "${C_ADDITIONAL_FLAGS} ${_option}") + else() + message(FATAL_ERROR "C99 support is required, but the compiler doesn't support a compiler flag to enable it") + endif() + endmacro() + + # + # Try to enable as many C99 features as we can. + # At minimum, we want C++/C99-style // comments. + # + # Newer versions of compilers might default to supporting C99, but + # older versions may require a special flag. + # + # Prior to CMake 3.1, setting CMAKE_C_STANDARD will not have any effect, + # so, unless and until we require CMake 3.1 or later, we have to do it + # ourselves on pre-3.1 CMake, so we just do it ourselves on all versions + # of CMake. + # + # Note: with CMake 3.1 through 3.5, the only compilers for which CMake + # handles CMAKE_C_STANDARD are GCC and Clang. 3.6 adds support only + # for Intel C; 3.9 adds support for PGI C, Sun C, and IBM XL C, and + # 3.10 adds support for Cray C and IAR C, but no version of CMake has + # support for HP C. Therefore, even if we use CMAKE_C_STANDARD with + # compilers for which CMake supports it, we may still have to do it + # ourselves on other compilers. + # + # See the CMake documentation for the CMAKE__COMPILER_ID variables + # for a list of compiler IDs. + # + # XXX - this just tests whether the option works, fails if it doesn't, + # and adds it if it does. We don't test whether it's necessary in order + # to get the C99 features that we use, or whether, if it's used, it + # enables all the features that we require. + # + if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR + CMAKE_C_COMPILER_ID MATCHES "Clang") + require_and_add_compiler_option("-std=gnu99") + elseif(CMAKE_C_COMPILER_ID MATCHES "XL") + # + # We want support for extensions picked up for GNU C compatibility, + # so we use -qlanglvl=extc99. + # + require_and_add_compiler_option("-qlanglvl=extc99") + elseif(CMAKE_C_COMPILER_ID MATCHES "HP") + require_and_add_compiler_option("-AC99") + elseif(CMAKE_C_COMPILER_ID MATCHES "Sun") + require_and_add_compiler_option("-xc99") + elseif(CMAKE_C_COMPILER_ID MATCHES "Intel") + require_and_add_compiler_option("-c99") + endif() +endif(MSVC) + +# +# If we're building with MinGW, we need to specify _WIN32_WINNT as +# 0x0600 ("NT 6.0", a/k/a Vista/Windows Server 2008) or higher +# in order to get the full IPv6 API, including inet_ntop(), and we +# need to specify it as 0x0601 ("NT 6.1", a/k/a Windows 7) or higher +# in order to get NdisMediumIP. +# +# NOTE: pcap does *NOT* work with msvcrt.dll; it must link with +# a newer version of the C library, i.e. Visual Studio 2015 or +# later, as it depends on C99 features introduced in VS 2015. +# +if(MINGW) + add_definitions(-D_WIN32_WINNT=0x0601) +endif(MINGW) + +# +# Build all runtimes in the top-level binary directory; that way, +# on Windows, the executables will be in the same directory as +# the DLLs, so the system will find pcap.dll when any of the +# executables are run. +# +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/run) + +################################################################### +# Parameters +################################################################### + +if(WIN32) + # + # On Windows, allow the library name to be overridden, for the + # benefit of projects that combine libpcap with their own + # kernel-mode code to support capturing. + # + set(LIBRARY_NAME pcap CACHE STRING "Library name") +else() + # + # On UN*X, it's always been libpcap. + # + set(LIBRARY_NAME pcap) +endif() + +option(INET6 "Enable IPv6" ON) +if(WIN32) + option(USE_STATIC_RT "Use static Runtime" ON) +endif(WIN32) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) +set(dpdk_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for DPDK") +if(WIN32) + set(Packet_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for packet.dll") + set(AirPcap_ROOT "" CACHE PATH "Path to directory with include and lib subdirectories for airpcap.dll") +endif(WIN32) + +option(ENABLE_PROFILING "Enable code profiling" OFF) + +# To pacify those who hate the protochain instruction +option(NO_PROTOCHAIN "Disable protochain instruction" OFF) + +# +# Start out with the capture mechanism type unspecified; the user +# can explicitly specify it and, if they don't, we'll pick an +# appropriate one. +# +set(PCAP_TYPE "" CACHE STRING "Packet capture type") + +# +# Default to having remote capture support on Windows and, for now, to +# not having it on UN*X. +# +if(WIN32) + option(ENABLE_REMOTE "Enable remote capture" ON) +else() + option(ENABLE_REMOTE "Enable remote capture" OFF) +endif(WIN32) + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + option(BUILD_WITH_LIBNL "Build with libnl" ON) +endif() + +# +# Additional capture modules. +# +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + option(DISABLE_LINUX_USBMON "Disable Linux usbmon USB sniffing support" OFF) +endif() +option(DISABLE_BLUETOOTH "Disable Bluetooth sniffing support" OFF) +option(DISABLE_NETMAP "Disable netmap support" OFF) +option(DISABLE_DPDK "Disable DPDK support" OFF) + +# +# We don't support D-Bus sniffing on macOS; see +# +# https://bugs.freedesktop.org/show_bug.cgi?id=74029 +# +if(APPLE) + option(DISABLE_DBUS "Disable D-Bus sniffing support" ON) +else(APPLE) + option(DISABLE_DBUS "Disable D-Bus sniffing support" OFF) +endif(APPLE) +option(DISABLE_RDMA "Disable RDMA sniffing support" OFF) + +option(DISABLE_DAG "Disable Endace DAG card support" OFF) + +option(DISABLE_SEPTEL "Disable Septel card support" OFF) +set(SEPTEL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../septel" CACHE PATH "Path to directory with include and lib subdirectories for Septel API") + +option(DISABLE_SNF "Disable Myricom SNF support" OFF) + +option(DISABLE_TC "Disable Riverbed TurboCap support" OFF) + +# +# Debugging options. +# +option(BDEBUG "Build optimizer debugging code" OFF) +option(YYDEBUG "Build parser debugging code" OFF) + +################################################################### +# Versioning +################################################################### + +# Get, parse, format and set pcap's version string from [pcap_root]/VERSION +# for later use. + +# Get MAJOR, MINOR, PATCH & SUFFIX +file(STRINGS ${pcap_SOURCE_DIR}/VERSION + PACKAGE_VERSION + LIMIT_COUNT 1 # Read only the first line +) + +# Get "just" MAJOR +string(REGEX MATCH "^([0-9]+)" PACKAGE_VERSION_MAJOR "${PACKAGE_VERSION}") + +# Get MAJOR, MINOR & PATCH +string(REGEX MATCH "^([0-9]+.)?([0-9]+.)?([0-9]+)" PACKAGE_VERSION_NOSUFFIX "${PACKAGE_VERSION}") + +if(WIN32) + # Convert PCAP_VERSION_NOSUFFIX to Windows preferred version format + string(REPLACE "." "," PACKAGE_VERSION_PREDLL ${PACKAGE_VERSION_NOSUFFIX}) + + # Append NANO (used for Windows internal versioning) to PCAP_VERSION_PREDLL + # 0 means unused. + set(PACKAGE_VERSION_DLL ${PACKAGE_VERSION_PREDLL},0) +endif(WIN32) + +set(PACKAGE_NAME "${LIBRARY_NAME}") +set(PACKAGE_STRING "${LIBRARY_NAME} ${PACKAGE_VERSION}") + +###################################### +# Project settings +###################################### + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${pcap_SOURCE_DIR} +) + +include(CheckFunctionExists) +include(CMakePushCheckState) +include(CheckSymbolExists) + +if(WIN32) + + if(IS_DIRECTORY ${CMAKE_HOME_DIRECTORY}/../../Common) + include_directories(${CMAKE_HOME_DIRECTORY}/../../Common) + endif(IS_DIRECTORY ${CMAKE_HOME_DIRECTORY}/../../Common) + + find_package(Packet) + if(Packet_FOUND) + set(HAVE_PACKET32 TRUE) + include_directories(${Packet_INCLUDE_DIRS}) + # + # Check whether we have the NPcap PacketIsLoopbackAdapter() + # function. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES ${Packet_LIBRARIES}) + check_function_exists(PacketIsLoopbackAdapter HAVE_PACKET_IS_LOOPBACK_ADAPTER) + check_function_exists(PacketGetTimestampModes HAVE_PACKET_GET_TIMESTAMP_MODES) + cmake_pop_check_state() + endif(Packet_FOUND) + + message(STATUS "checking for Npcap's version.h") + check_symbol_exists(WINPCAP_PRODUCT_NAME "${CMAKE_SOURCE_DIR}/../../version.h" HAVE_VERSION_H) + if(HAVE_VERSION_H) + message(STATUS "HAVE version.h") + else(HAVE_VERSION_H) + message(STATUS "MISSING version.h") + endif(HAVE_VERSION_H) + +endif(WIN32) + +if(MSVC) + add_definitions(-D__STDC__) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif(MSVC) + +if(USE_STATIC_RT) + message(STATUS "Use STATIC runtime") + if(MSVC) + foreach(RT_FLAG + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) + string(REGEX REPLACE "/MD" "/MT" ${RT_FLAG} "${${RT_FLAG}}") + endforeach(RT_FLAG) + elseif(MINGW) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc") + endif() +else (USE_STATIC_RT) + message(STATUS "Use DYNAMIC runtime") +endif(USE_STATIC_RT) + +################################################################### +# Detect available platform features +################################################################### + +include(CheckIncludeFile) +include(CheckIncludeFiles) +include(CheckStructHasMember) +include(CheckTypeSize) + +# +# Tests are a bit expensive with Visual Studio on Windows, so, on +# Windows, we skip tests for UN*X-only headers and functions. +# + +# +# Header files. +# +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(unistd.h HAVE_UNISTD_H) +if(NOT HAVE_UNISTD_H) + add_definitions(-DYY_NO_UNISTD_H) +endif(NOT HAVE_UNISTD_H) +check_include_file(bitypes.h HAVE_SYS_BITYPES_H) +if(NOT WIN32) + check_include_file(sys/ioccom.h HAVE_SYS_IOCCOM_H) + check_include_file(sys/sockio.h HAVE_SYS_SOCKIO_H) + check_include_file(sys/select.h HAVE_SYS_SELECT_H) + + check_include_file(netpacket/packet.h HAVE_NETPACKET_PACKET_H) + check_include_file(netinet/if_ether.h HAVE_NETINET_IF_ETHER_H) +endif(NOT WIN32) + +# +# Functions. +# +# First, check for the __atomic_load_n() and __atomic_store_n() +# builtins. +# +# We can't use check_function_exists(), as it tries to declare +# the function, and attempting to declare a compiler builtin +# can produce an error. +# +# We don't use check_symbol_exists(), as it expects a header +# file to be specified to declare the function, but there isn't +# such a header file. +# +# So we use check_c_source_compiles(). +# +check_c_source_compiles( +"int +main(void) +{ + int i = 17; + return __atomic_load_n(&i, __ATOMIC_RELAXED); +} +" + HAVE___ATOMIC_LOAD_N) +check_c_source_compiles( +"int +main(void) +{ + int i; + __atomic_store_n(&i, 17, __ATOMIC_RELAXED); + return 0; +} +" + HAVE___ATOMIC_STORE_N) + +# +# Now check for various system functions. +# +check_function_exists(strerror_r HAVE_STRERROR_R) +if(HAVE_STRERROR_R) + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + check_c_source_compiles( +"#define _GNU_SOURCE +#include + +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} +" + HAVE_GNU_STRERROR_R) + if(NOT HAVE_GNU_STRERROR_R) + set(HAVE_POSIX_STRERROR_R YES) + endif(NOT HAVE_GNU_STRERROR_R) +else(HAVE_STRERROR_R) + # + # We don't have strerror_r; do we have _wcserror_s? + # + check_function_exists(_wcserror_s HAVE__WCSERROR_S) +endif(HAVE_STRERROR_R) + +# +# Make sure we have vsnprintf() and snprintf(); we require them. +# We use check_symbol_exists(), as they aren't necessarily external +# functions - in Visual Studio, for example, they're inline functions +# calling a common external function. +# +check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) +if(NOT HAVE_VSNPRINTF) + message(FATAL_ERROR "vsnprintf() is required but wasn't found") +endif(NOT HAVE_VSNPRINTF) +check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) +if(NOT HAVE_SNPRINTF) + message(FATAL_ERROR "snprintf() is required but wasn't found") +endif() + +check_function_exists(strlcpy HAVE_STRLCPY) +check_function_exists(strlcat HAVE_STRLCAT) +check_function_exists(asprintf HAVE_ASPRINTF) +check_function_exists(vasprintf HAVE_VASPRINTF) +check_function_exists(strtok_r HAVE_STRTOK_R) +if(NOT WIN32) + check_function_exists(vsyslog HAVE_VSYSLOG) +endif() + +# +# Look for various networking-related libraries that we may need. +# +# We need getaddrinfo() to translate host names in filters to IP +# addresses. We use getaddrinfo() because we want a portable +# thread-safe way of getting information for a host name or port; +# there exist _r versions of gethostbyname() and getservbyname() on +# some platforms, but not on all platforms. +# +# We may also need socket() and other socket functions to support: +# +# Local packet capture with capture mechanisms that use sockets. +# +# Local capture device enumeration if a socket call is needed to +# enumerate devices or get device attributes. +# +# Packet capture from services that put captured packets on the +# network, such as rpcap servers. +# +# We may also need getnameinfo() for packet capture from services +# that put packets on the network. +# +set(PCAP_LINK_LIBRARIES "") +set(LIBS "") +set(LIBS_STATIC "") +set(REQUIRES_PRIVATE "") +set(LIBS_PRIVATE "") +include(CheckLibraryExists) +if(WIN32) + # + # Windows. + # + # We need winsock2.h and ws2tcpip.h. + # + # On Windows, getaddrinfo() is in the ws2_32 library. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES ws2_32) + check_symbol_exists(getaddrinfo "winsock2.h;ws2tcpip.h" LIBWS2_32_HAS_GETADDRINFO) + cmake_pop_check_state() + if(LIBWS2_32_HAS_GETADDRINFO) + set(PCAP_LINK_LIBRARIES ws2_32 ${PCAP_LINK_LIBRARIES}) + else(LIBWS2_32_HAS_GETADDRINFO) + message(FATAL_ERROR "getaddrinfo is required, but wasn't found") + endif(LIBWS2_32_HAS_GETADDRINFO) +else(WIN32) + # + # UN*X. + # + # Most UN*Xes have getaddrinfo(), and the other routines we may + # need, in the default searched libraries (e.g., libc). + # Check there first. + # + # NOTE: if you hand check_library_exists as its last argument a + # variable that's been set, it skips the test, so we need different + # variables for different libraries. + # + check_function_exists(getaddrinfo STDLIBS_HAVE_GETADDRINFO) + if(NOT STDLIBS_HAVE_GETADDRINFO) + # + # Not found in the standard system libraries. + # + # In some versions of Solaris, we need to link with libsocket + # and libnsl, so check in libsocket and also link with liblnsl + # when doing this test. + # + # Linking with libsocket and libnsl will find all the routines + # we need. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES nsl) + check_library_exists(socket getaddrinfo "" LIBSOCKET_HAS_GETADDRINFO) + cmake_pop_check_state() + if(LIBSOCKET_HAS_GETADDRINFO) + # + # OK, we found it in libsocket. + # + set(PCAP_LINK_LIBRARIES socket nsl ${PCAP_LINK_LIBRARIES}) + set(LIBS "-lsocket -lnsl ${LIBS}") + set(LIBS_STATIC "-lsocket -lnsl ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lsocket -lnsl ${LIBS_PRIVATE}") + else(LIBSOCKET_HAS_GETADDRINFO) + # + # Not found in libsocket; test for it in libnetwork, which + # is where it is in Haiku. + # + # Linking with libnetwork will find all the routines we + # need. + # + check_library_exists(network getaddrinfo "" LIBNETWORK_HAS_GETADDRINFO) + if(LIBNETWORK_HAS_GETADDRINFO) + # + # OK, we found it in libnetwork. + # + set(PCAP_LINK_LIBRARIES network ${PCAP_LINK_LIBRARIES}) + set(LIBS "-lnetwork ${LIBS}") + set(LIBS_STATIC "-lnetwork ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lnetwork ${LIBS_PRIVATE}") + else(LIBNETWORK_HAS_GETADDRINFO) + # + # We didn't find it. + # + message(FATAL_ERROR "getaddrinfo is required, but wasn't found") + endif(LIBNETWORK_HAS_GETADDRINFO) + endif(LIBSOCKET_HAS_GETADDRINFO) + + # + # We require a version of recvmsg() that conforms to the Single + # UNIX Specification, so that we can check whether a datagram + # received with recvmsg() was truncated when received due to the + # buffer being too small. + # + # On most systems, the version of recvmsg() in the libraries + # found above conforms to the SUS. + # + # On at least some versions of Solaris, it does not conform to + # the SUS, and we need the version in libxnet, which does + # conform. + # + # Check whether libxnet exists and has a version of recvmsg(); + # if it does, link with libxnet before we link with libsocket, + # to get that version. + # + # This test also links with libsocket and libnsl. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES socket nsl) + check_library_exists(xnet recvmsg "" LIBXNET_HAS_RECVMSG) + cmake_pop_check_state() + if(LIBXNET_HAS_RECVMSG) + # + # libxnet has recvmsg(); link with it as well. + # + set(PCAP_LINK_LIBRARIES xnet ${PCAP_LINK_LIBRARIES}) + set(LIBSC "-lxnet ${LIBS_LIBS}") + set(LIBS_STATIC "-lxnet ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lxnet ${LIBS_PRIVATE}") + endif(LIBXNET_HAS_RECVMSG) + endif(NOT STDLIBS_HAVE_GETADDRINFO) + + # + # DLPI needs putmsg under HP-UX, so test for -lstr while we're at it. + # + check_function_exists(putmsg STDLIBS_HAVE_PUTMSG) + if(NOT STDLIBS_HAVE_PUTMSG) + check_library_exists(str putmsg "" LIBSTR_HAS_PUTMSG) + if(LIBSTR_HAS_PUTMSG) + set(PCAP_LINK_LIBRARIES str ${PCAP_LINK_LIBRARIES}) + set(LIBS "-lstr ${LIBS}") + set(LIBS_STATIC "-lstr ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lstr ${LIBS_PRIVATE}") + endif(LIBSTR_HAS_PUTMSG) + endif(NOT STDLIBS_HAVE_PUTMSG) + + # Haiku has getpass in libbsd + check_function_exists(getpass STDLIBS_HAVE_GETPASS) + if(NOT STDLIBS_HAVE_GETPASS) + check_library_exists(bsd getpass "" LIBBSD_HAS_GETPASS) + if(LIBBSD_HAS_GETPASS) + set(PCAP_LINK_LIBRARIES bsd ${PCAP_LINK_LIBRARIES}) + endif(LIBBSD_HAS_GETPASS) + endif(NOT STDLIBS_HAVE_GETPASS) +endif(WIN32) + +# +# Check for reentrant versions of getnetbyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getnetbyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getnetbyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +cmake_push_check_state() +set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LINK_LIBRARIES}) +check_symbol_exists(getnetbyname_r netdb.h NETDB_H_DECLARES_GETNETBYNAME_R) +if(NETDB_H_DECLARES_GETNETBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct netent netent_buf; + char buf[1024]; + struct netent *resultp; + int h_errnoval; + + return getnetbyname_r((const char *)0, &netent_buf, buf, sizeof buf, &resultp, &h_errnoval); +} +" + HAVE_LINUX_GETNETBYNAME_R) + if(NOT HAVE_LINUX_GETNETBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct netent netent_buf; + char buf[1024]; + + return getnetbyname_r((const char *)0, &netent_buf, buf, (int)sizeof buf) != NULL; +} +" + HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + if(NOT HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct netent netent_buf; + struct netent_data net_data; + + return getnetbyname_r((const char *)0, &netent_buf, &net_data); +} +" + HAVE_AIX_GETNETBYNAME_R) + endif(NOT HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + endif(NOT HAVE_LINUX_GETNETBYNAME_R) +endif(NETDB_H_DECLARES_GETNETBYNAME_R) +cmake_pop_check_state() + +# +# Check for reentrant versions of getprotobyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getprotobyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getprotobyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +cmake_push_check_state() +set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LINK_LIBRARIES}) +check_symbol_exists(getprotobyname_r netdb.h NETDB_H_DECLARES_GETPROTOBYNAME_R) +if(NETDB_H_DECLARES_GETPROTOBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct protoent protoent_buf; + char buf[1024]; + struct protoent *resultp; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, sizeof buf, &resultp); +} +" + HAVE_LINUX_GETPROTOBYNAME_R) + if(NOT HAVE_LINUX_GETPROTOBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct protoent protoent_buf; + char buf[1024]; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, (int)sizeof buf) != NULL; +} +" + HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R) + if(NOT HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R) + check_c_source_compiles( +"#include + +int +main(void) +{ + struct protoent protoent_buf; + struct protoent_data proto_data; + + return getprotobyname_r((const char *)0, &protoent_buf, &proto_data); +} +" + HAVE_AIX_GETPROTOBYNAME_R) + endif(NOT HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R) + endif(NOT HAVE_LINUX_GETPROTOBYNAME_R) +endif(NETDB_H_DECLARES_GETPROTOBYNAME_R) +cmake_pop_check_state() + +# +# Data types. +# +# XXX - there's no check_type() macro that's like check_type_size() +# except that it only checks for the existence of the structure type, +# so we use check_type_size() and ignore the size. +# +cmake_push_check_state() +if(WIN32) + set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h) +else(WIN32) + set(CMAKE_EXTRA_INCLUDE_FILES unistd.h sys/socket.h) +endif(WIN32) +check_type_size("struct sockaddr_storage" STRUCT_SOCKADDR_STORAGE) +check_type_size("socklen_t" SOCKLEN_T) +cmake_pop_check_state() + +# +# Structure fields. +# +if(WIN32) + check_struct_has_member("struct sockaddr" sa_len winsock2.h HAVE_STRUCT_SOCKADDR_SA_LEN) +else(WIN32) + check_struct_has_member("struct sockaddr" sa_len sys/socket.h HAVE_STRUCT_SOCKADDR_SA_LEN) +endif(WIN32) + +# +# Do we have ffs(), and is it declared in ? +# +check_function_exists(ffs HAVE_FFS) +if(HAVE_FFS) + # + # OK, we have ffs(). Is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ffs(). + # + check_symbol_exists(ffs strings.h STRINGS_H_DECLARES_FFS) +endif() + +# +# This requires the libraries that we require, as ether_hostton might be +# in one of those libraries. That means we have to do this after +# we check for those libraries. +# +# You are in a twisty little maze of UN*Xes, all different. +# Some might not have ether_hostton(). +# Some might have it and declare it in . +# Some might have it and declare it in +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and not declare it in any header file. +# +# Before you is a C compiler. +# +cmake_push_check_state() +set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LINK_LIBRARIES}) +check_function_exists(ether_hostton HAVE_ETHER_HOSTTON) +if(HAVE_ETHER_HOSTTON) + # + # OK, we have ether_hostton(). Is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ether_hostton(). + # + check_symbol_exists(ether_hostton net/ethernet.h NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) + if(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) + # + # Yes - we have it declared. + # + set(HAVE_DECL_ETHER_HOSTTON TRUE) + endif() + # + # Did that succeed? + # + if(NOT HAVE_DECL_ETHER_HOSTTON) + # + # No - how about , as on Linux? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + check_symbol_exists(ether_hostton netinet/ether.h NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) + if(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) + # + # Yes - we have it declared. + # + set(HAVE_DECL_ETHER_HOSTTON TRUE) + endif() + endif() + # + # Did that succeed? + # + if(NOT HAVE_DECL_ETHER_HOSTTON) + # + # No - how about , as on Solaris 10 and later? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + check_symbol_exists(ether_hostton sys/ethernet.h SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) + if(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) + # + # Yes - we have it declared. + # + set(HAVE_DECL_ETHER_HOSTTON TRUE) + endif() + endif() + # + # Did that succeed? + # + if(NOT HAVE_DECL_ETHER_HOSTTON) + # + # No, how about , as on AIX? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + check_symbol_exists(ether_hostton arpa/inet.h ARPA_INET_H_DECLARES_ETHER_HOSTTON) + if(ARPA_INET_H_DECLARES_ETHER_HOSTTON) + # + # Yes - we have it declared. + # + set(HAVE_DECL_ETHER_HOSTTON TRUE) + endif() + endif() + # + # Did that succeed? + # + if(NOT HAVE_DECL_ETHER_HOSTTON) + # + # No, how about ? + # On some platforms, it requires and + # , and we always include it with + # both of them, so test it with both of them. + # + # This test fails if we don't have + # and the headers we include before it, or if we do but + # doesn't declare ether_hostton(). + # + check_symbol_exists(ether_hostton "sys/types.h;sys/socket.h;net/if.h;netinet/in.h;netinet/if_ether.h" NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) + if(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) + # + # Yes - we have it declared. + # + set(HAVE_DECL_ETHER_HOSTTON TRUE) + endif() + endif() + # + # After all that, is ether_hostton() declared? + # + if(NOT HAVE_DECL_ETHER_HOSTTON) + # + # No, we'll have to declare it ourselves. + # Do we have "struct ether_addr" if we include ? + # + # XXX - there's no check_type() macro that's like check_type_size() + # except that it only checks for the existence of the structure type, + # so we use check_type_size() and ignore the size. + # + cmake_push_check_state() + set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h sys/socket.h net/if.h netinet/in.h netinet/if_ether.h) + check_type_size("struct ether_addr" STRUCT_ETHER_ADDR) + cmake_pop_check_state() + endif() +endif() +cmake_pop_check_state() + +# +# Large file support on UN*X, a/k/a LFS. +# +if(NOT WIN32) + include(FindLFS) + if(LFS_FOUND) + # + # Add the required #defines. + # + add_definitions(${LFS_DEFINITIONS}) + endif() + + # + # Check for fseeko as well. + # + include(FindFseeko) + if(FSEEKO_FOUND) + set(HAVE_FSEEKO ON) + + # + # Add the required #defines. + # + add_definitions(${FSEEKO_DEFINITIONS}) + endif() +endif() + +if(INET6) + message(STATUS "Support IPv6") +endif(INET6) + +# +# Pthreads. +# We might need them, because some libraries we use might use them, +# but we don't necessarily need them. +# That's only on UN*X; on Windows, if they use threads, we assume +# they're native Windows threads. +# +if(NOT WIN32) + set(CMAKE_THREAD_PREFER_PTHREAD ON) + find_package(Threads) + if(NOT CMAKE_USE_PTHREADS_INIT) + # + # If it's not pthreads, we won't use it; we use it for libraries + # that require it. + # + set(CMAKE_THREAD_LIBS_INIT "") + endif(NOT CMAKE_USE_PTHREADS_INIT) +endif(NOT WIN32) + +if(ENABLE_PROFILING) + if(NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") + endif() +endif() + +# +# Based on +# +# https://github.com/commonmark/cmark/blob/master/FindAsan.cmake +# +# The MIT License (MIT) +# +# Copyright (c) 2013 Matthew Arsenault +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# Test if the each of the sanitizers in the ENABLE_SANITIZERS list are +# supported by the compiler, and, if so, adds the appropriate flags to +# CMAKE_C_FLAGS, and SANITIZER_FLAGS. If not, it fails. +# +# Do this last, in the hope that it will prevent configuration on Linux +# from somehow deciding it doesn't need -lpthread when building rpcapd +# (it does require it, but somehow, in some mysterious fashion that no +# obvious CMake debugging flag reveals, it doesn't realize that if we +# turn sanitizer stuff on). +# +# Note: apparently, some projects have decided that ENABLE_SANITIZERS +# is a Boolean, with OFF meaning "no sanitizers" and ON meaning "all +# sanitizers". Whoever decided that didn't put it up as a common +# CMake idiom, as far as I can tell; we only discovered this because +# JetBrains' CLion "helpfully" appears to pass -DENABLE_SANITIZERS=OFF +# to CMake by default, which causes CMake to fail on libpcap. Thanks! +# +# We thus also allow a setting of OFF to mean "no sanitizers" and ON to +# mean "all supported sanitizers that we know about and that can all +# be used together". +# +macro(test_sanitizer _sanitizer _sanitizer_flag) + message(STATUS "Checking sanitizer ${_sanitizer}") + set(sanitizer_variable "sanitize_${_sanitizer}") + # Set -Werror to catch "argument unused during compilation" warnings + set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=${_sanitizer}") + check_c_compiler_flag("-fsanitize=${_sanitizer}" ${sanitizer_variable}) + if(${${sanitizer_variable}}) + set(${_sanitizer_flag} "-fsanitize=${_sanitizer}") + else() + # + # Try the versions supported prior to Clang 3.2. + # If the sanitizer is "address", try -fsanitize-address. + # If it's "undefined", try -fcatch-undefined-behavior. + # Otherwise, give up. + # + set(sanitizer_variable "OLD_${sanitizer_variable}") + if ("${_sanitizer}" STREQUAL "address") + set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize-address") + check_c_compiler_flag("-fsanitize-address" ${sanitizer_variable}) + if(${${sanitizer_variable}}) + set(${_sanitizer_flag} "-fsanitize-address") + endif() + elseif("${_sanitizer}" STREQUAL "undefined") + set(CMAKE_REQUIRED_FLAGS "-Werror -fcatch-undefined-behavior") + check_c_compiler_flag("-fcatch-undefined-behavior" ${sanitizer_variable}) + if(${${sanitizer_variable}}) + set(${_sanitizer_flag} "-fcatch-undefined-behavior") + endif() + endif() + endif() + unset(CMAKE_REQUIRED_FLAGS) +endmacro(test_sanitizer) + +set(SANITIZER_FLAGS "") +if("${ENABLE_SANITIZERS}") + # + # This appears to indicate that ENABLE_SANITIZERS was set to a + # string value that is "one of the true constants", meaning + # "1, ON, YES, TRUE, Y, or a non-zero number". + # + # It does not appear to happen for other settings, including + # setting it to a list of one or more sanitizers. + # + # This setting means "enable all sanitizers that the compiler + # supports". + # + foreach(sanitizer "address" "undefined") + unset(SANITIZER_FLAG) + test_sanitizer(${sanitizer} SANITIZER_FLAG) + if(SANITIZER_FLAG) + message(STATUS "${sanitizer} sanitizer supported using ${SANITIZER_FLAG}") + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} ${SANITIZER_FLAG}") + else() + message(STATUS "${sanitizer} isn't a supported sanitizer") + endif() + endforeach() + if("${SANITIZER_FLAGS}" STREQUAL "") + message(FATAL_ERROR "No supported sanitizers found") + endif() +else() + # + # This appears to indicate that ENABLE_SANITIZERS was either: + # + # not set; + # set to a set to a string value that is not "one of the true + # constants", meaning "1, ON, YES, TRUE, Y, or a non-zero number". + # + # The latter includes setting it to "one of the false constants", + # meaning the string "is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, + # the empty string, or ends in the suffix -NOTFOUND." + # + # It also includes setting it to a list of one or more sanitizers. + # + # We want to treat "not set" and "set to one of the false constants" + # as meaning "do not enable any sanitizers". + # + # We want to treat "set to a list of one or more sanitizers" as + # meaning "enable all the sanitizers in the list". + # + # This requires that we distinguish between those two cases. + # + if(ENABLE_SANITIZERS) + # + # This appears to indicate that ENABLE_SANITIZERS was set to + # a string value that is "not one of the false constants". + # + # We already know it's "not one of the true constants", so + # we treat it as a list of sanitizers. + # + foreach(sanitizer IN LISTS ENABLE_SANITIZERS) + unset(SANITIZER_FLAG) + test_sanitizer(${sanitizer} SANITIZER_FLAG) + if(SANITIZER_FLAG) + message(STATUS "${sanitizer} sanitizer supported using ${SANITIZER_FLAG}") + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} ${SANITIZER_FLAG}") + else() + message(FATAL_ERROR "${sanitizer} isn't a supported sanitizer") + endif() + endforeach() + else() + # + # This appears to indicate that ENABLE_SANITIZERS was either: + # + # not set; + # set to a value that's "one of the false constants"; + # + # so we don't enable any sanitizers. + # + message(STATUS "Not enabling sanitizers") + endif() +endif() + +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -g ${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls") +endif() + +if(ENABLE_REMOTE) + # + # OpenSSL/libressl. + # + find_package(OpenSSL) + if(OPENSSL_FOUND) + # + # We have OpenSSL. + # + include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR}) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${OPENSSL_LIBRARIES}) + + # + # The find_package() module CMake provides for OpenSSL uses does not + # give us a defined indication of whether it found OpenSSL with + # pkg-config or not. We need to know that as, if it was found with + # pkg-config, we should set the Requires.private value in libpcap.pc + # to include its package name, openssl, otherwise we should add the + # names for the static libraries to Libs.private. + # + # On UN*X, FindOpenSSL happens to use pkg-config to find OpenSSL, but + # it doesn't appear to be documented as doing so; therefore, we don't + # assume that, if we got here, we have pkg-config. + # + # So we use pkg_get_link_info() to run pkg-config ourselves, both + # because FindOpenSSL doesn't set the OPENSSL_LDFLAGS or + # OPENSSL_STATIC_LDFLAGS variables and because, for reasons explained + # in the comment before the pkg_get_link_info() macro, even if it did, + # it wouldn't be what we want anyway. + # + if (PKG_CONFIG_EXECUTABLE) + pkg_get_link_info(OPENSSL openssl) + if (OPENSSL_FOUND_WITH_PKG_CONFIG) + # + # pkg-config failed; assume that means that there is no openssl + # package for it to find. Just add OPENSSL_LIBRARIES to + # LIBS_PRIVATE AND LIBS_STATIC, as that's the + # best we can do. XXX - need list of -l and -L flags to add.... + # + set(LIBS "${LIBS} ${OPENSSL_LIBS}") + set(LIBS_STATIC "${LIBS_STATIC} ${OPENSSL_LIBS_STATIC}") + set(REQUIRES_PRIVATE "${REQUIRES_PRIVATE} ${OPENSSL_PACKAGE_NAME}") + endif() + else() + # Get it from OPENSSL_LIBRARIES + foreach(_lib IN LISTS OPENSSL_LIBRARIES) + # + # Get the directory in which the library resides. + # + get_filename_component(_lib_directory "${_lib}" DIRECTORY) + + # + # Is the library directory in CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES? + # (See comment above on why we use that.) + # + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_lib_directory}" _lib_index) + if(_lib_index EQUAL -1) + # + # No, so add a -L flag to get the linker to search in that + # directory. + # + set(LIBS "${LIBS} -L${_lib_directory}") + set(LIBS_STATIC "${LIBS_STATIC} -L${_lib_directory}") + set(LIBS_PRIVATE "${LIBS_PRIVATE} -L${_lib_directory}") + endif() + + # + # Get the file name of the library, without the extension. + # + get_filename_component(_lib_filename "${_lib}" NAME_WE) + + # + # Strip off the "lib" prefix to get the library name, and + # add a -l flag based on that. + # + string(REGEX REPLACE "^lib" "" _library_name "${_lib_filename}") + set(LIBS "${LIBS} -l${_library_name}") + set(LIBS_STATIC "${LIBS_STATIC} -l${_library_name}") + set(LIBS_PRIVATE "${LIBS_PRIVATE} -l${_library_name}") + endforeach() + endif() + set(HAVE_OPENSSL YES) + endif(OPENSSL_FOUND) +endif(ENABLE_REMOTE) + +# +# On macOS, build libpcap for the appropriate architectures, if +# CMAKE_OSX_ARCHITECTURES isn't set (if it is, let that control +# the architectures for which to build it). +# +if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + # + # Get the major version of Darwin. + # + string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MAJOR "${CMAKE_SYSTEM_VERSION}") + + if(SYSTEM_VERSION_MAJOR LESS 8) + # + # Pre-Tiger. + # + # Build libraries and executables only for 32-bit PowerPC, as + # that's all that is supported. + # + set(OSX_LIBRARY_ARCHITECTURES "ppc") + set(OSX_EXECUTABLE_ARCHITECTURES "ppc") + elseif(SYSTEM_VERSION_MAJOR EQUAL 8) + # + # Tiger. Is this prior to, or with, Intel support? + # + # Get the minor version of Darwin. + # + string(REPLACE "${SYSTEM_VERSION_MAJOR}." "" SYSTEM_MINOR_AND_PATCH_VERSION ${CMAKE_SYSTEM_VERSION}) + string(REGEX MATCH "^([0-9]+)" SYSTEM_VERSION_MINOR "${SYSTEM_MINOR_AND_PATCH_VERSION}") + if(SYSTEM_VERSION_MINOR LESS 4) + # + # Prior to Intel support. + # + # Build libraries and executables for 32-bit PowerPC and + # 64-bit PowerPC, with 32-bit PowerPC first, as those + # are both supported. (I'm guessing that's what Apple + # does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64") + set(OSX_EXECUTABLE_ARCHITECTURES "ppc;ppc64") + elseif(SYSTEM_VERSION_MINOR LESS 7) + # + # With Intel support but prior to x86-64 support. + # + # Build for 32-bit PowerPC, 64-bit PowerPC, and 32-bit x86, + # with 32-bit PowerPC first, as those are all supported. + # (I'm guessing that's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386") + set(OSX_EXECUTABLE_ARCHITECTURES "ppc;ppc64;i386") + else() + # + # With Intel support including x86-64 support. + # + # Build for 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first, as those are + # all supported. (I'm guessing that's what Apple does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386;x86_64") + set(OSX_EXECUTABLE_ARCHITECTURES "ppc;ppc64;i386;x86_64") + endif() + elseif(SYSTEM_VERSION_MAJOR EQUAL 9) + # + # Leopard. + # + # Build libraries and executables for 32-bit PowerPC, 64-bit + # PowerPC, 32-bit x86, and x86-64, with 32-bit PowerPC + # first, as those are all supported. (That's what Apple + # does.) + # + set(OSX_LIBRARY_ARCHITECTURES "ppc;ppc64;i386;x86_64") + set(OSX_EXECUTABLE_ARCHITECTURES "ppc;ppc64;i386;x86_64") + elseif(SYSTEM_VERSION_MAJOR EQUAL 10) + # + # Snow Leopard. + # + # Build libraries for x86-64, 32-bit x86, and 32-bit PowerPC, + # with x86-64 first, because 32-bit PowerPC executables are + # supported with Rosetta. (That's what Apple does, even though + # Snow Leopard doesn't run on PPC, so PPC libpcap runs under + # Rosetta, and Rosetta doesn't support BPF ioctls, so PPC + # executables can't do live captures.) + # + set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386;ppc") + + # + # Build executables only for 32-bit x86 and 64-bit x86, as PPC + # machines are no longer supported. + # + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64;i386") + elseif(SYSTEM_VERSION_MAJOR GREATER 10 AND SYSTEM_VERSION_MAJOR LESS 19) + # + # Post-Snow Leopard, pre-Catalina. + # + # Build libraries for 64-bit x86 and 32-bit x86, with 64-bit x86 + # first, as PPC machines are no longer supported, but 32-bit + # x86 executables are. (That's what Apple does.) + # + # First, check whether we're building with OpenSSL. + # If so, don't bother trying to build fat. + # + if(HAVE_OPENSSL) + set(X86_32_BIT_SUPPORTED NO) + set(OSX_LIBRARY_ARCHITECTURES "x86_64") + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64") + message(WARNING "We're assuming the OpenSSL libraries are 64-bit only, so we're not compiling for 32-bit x86") + else() + # + # Now, check whether we *can* build for i386. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "-arch i386") + check_c_source_compiles( +"int +main(void) +{ + return 0; +} +" + X86_32_BIT_SUPPORTED) + cmake_pop_check_state() + if(X86_32_BIT_SUPPORTED) + set(OSX_LIBRARY_ARCHITECTURES "x86_64;i386") + else() + set(OSX_LIBRARY_ARCHITECTURES "x86_64") + # + # We can't build fat; suggest that the user install the + # /usr/include headers if they want to build fat. + # + if(SYSTEM_VERSION_MAJOR LESS 18) + # + # Pre-Mojave; the command-line tools should be sufficient to + # enable 32-bit x86 builds. + # + message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools") + else() + message(WARNING "Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package") + endif() + endif() + endif() + + # + # Build executables only for 64-bit x86, as 32-bit x86 machines + # are no longer supported. + # + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64") + elseif(SYSTEM_VERSION_MAJOR EQUAL 19) + # + # Catalina. + # + # Build libraries and executables only for x86-64, as 32-bit + # executables are no longer supported. (That's what Apple + # does.) + # + set(OSX_LIBRARY_ARCHITECTURES "x86_64") + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64") + else() + # + # Post-Catalina. Build libraries and + # executables for x86-64 and ARM64. + # (That's what Apple does, except they + # build for arm64e, which may include + # some of the pointer-checking extensions.) + # + # If we're building with libssl, make sure + # we can build fat with it (i.e., that it + # was built fat); if we can't, don't set + # the target architectures, and just + # build for the host we're on. + # + # Otherwise, just add both of them. + # + if(HAVE_OPENSSL) + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "-arch x86_64 -arch arm64") + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) + # + # We must test whether this compiles and links, so + # check_symbol_exists() isn't sufficient. + # + # SSL_library_init() may be a macro that's #defined + # to be the real function to call, so we have to + # include , and check_function_exists() + # isn't sufficient. + # + check_c_source_compiles( +"#include +int +main(void) +{ + SSL_library_init(); + return 0; +} +" + FAT_SSL_BUILDS_SUPPORTED) + cmake_pop_check_state() + if(FAT_SSL_BUILDS_SUPPORTED) + set(OSX_LIBRARY_ARCHITECTURES "x86_64;arm64") + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64;arm64") + endif() + else() + set(OSX_LIBRARY_ARCHITECTURES "x86_64;arm64") + set(OSX_EXECUTABLE_ARCHITECTURES "x86_64;arm64") + endif() + endif() +endif() + +# +# Additional linker flags. +# +set(LINKER_FLAGS "${SANITIZER_FLAGS}") +if(ENABLE_PROFILING) + if(MSVC) + set(LINKER_FLAGS " /PROFILE") + else() + set(LINKER_FLAGS " -pg") + endif() +endif() + +###################################### +# Input files +###################################### + +set(PROJECT_SOURCE_LIST_C + bpf_dump.c + bpf_filter.c + bpf_image.c + etherent.c + fmtutils.c + gencode.c + nametoaddr.c + optimize.c + pcap-common.c + pcap-util.c + pcap.c + savefile.c + sf-pcapng.c + sf-pcap.c +) + +if(WIN32) + # + # We add the character set conversion routines; they're Windows-only + # for now. + # + # We assume we don't have asprintf(), and provide an implementation + # that uses _vscprintf() to determine how big the string needs to be. + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} + charconv.c missing/win_asprintf.c) +else() + if(NOT HAVE_ASPRINTF) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/asprintf.c) + endif() + if(NOT HAVE_STRLCAT) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strlcat.c) + endif(NOT HAVE_STRLCAT) + if(NOT HAVE_STRLCPY) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strlcpy.c) + endif(NOT HAVE_STRLCPY) + if(NOT HAVE_STRTOK_R) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} missing/strtok_r.c) + endif(NOT HAVE_STRTOK_R) +endif(WIN32) + +# +# Determine the main pcap-XXX.c file to use, and the libraries with +# which we need to link libpcap, if any. +# +if(WIN32) + # + # Windows. + # + # Has the user explicitly specified a capture type? + # + if(PCAP_TYPE STREQUAL "") + # + # The user didn't explicitly specify a capture mechanism. + # Check whether we have packet.dll. + # + if(HAVE_PACKET32) + # + # We have packet.dll. + # Set the capture type to NPF. + # + set(PCAP_TYPE npf) + else() + # + # We don't have any capture type we know about. + # Report an error, and tell the user to configure with + # -DPCAP_TYPE=null if they want a libpcap that can't + # capture but that can read capture files. That way, + # nobody gets surprised by getting a no-capture + # libpcap without asking for that. + # + message(FATAL_ERROR "No supported packet capture interface was found. +In order to build a version of libpcap that supports packet capture +on Windows, you will need to install Npcap and the Npcap SDK, or +WinPcap and the WinPcap SDK, and run cmake with -DPacket_ROOT={path of SDK}, +where {path of SDK} is the path name of the top-level directory of the SDK. +That argument may have to be quoted if the path contains blanks. +If you want a libpcap that cannot capture packets but that can read +pcap and pcapng files, run cmake with -DPCAP_TYPE=null.") + endif() + endif() +else() + # + # UN*X. + # + # Figure out what type of packet capture mechanism we have, and + # what libraries we'd need to link libpcap with, if any. + # + + # + # Has the user explicitly specified a capture type? + # + if(PCAP_TYPE STREQUAL "") + # + # Check for a bunch of headers for various packet capture mechanisms. + # + check_include_files("sys/types.h;net/bpf.h" HAVE_NET_BPF_H) + if(HAVE_NET_BPF_H) + # + # Does it define BIOCSETIF? + # I.e., is it a header for an LBL/BSD-style capture + # mechanism, or is it just a header for a BPF filter + # engine? Some versions of Arch Linux, for example, + # have a net/bpf.h that doesn't define BIOCSETIF; + # as it's a Linux, it should use packet sockets, + # instead. + # + # We need: + # + # sys/types.h, because FreeBSD 10's net/bpf.h + # requires that various BSD-style integer types + # be defined; + # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # + # sys/ioctl.h and, if we have it, sys/ioccom.h, + # because net/bpf.h defines ioctls; + # + # net/if.h, because it defines some structures + # used in ioctls defined by net/bpf.h; + # + # sys/socket.h, because OpenBSD 5.9's net/bpf.h + # defines some structure fields as being + # struct sockaddrs; + # + # and net/bpf.h doesn't necessarily include all + # of those headers itself. + # + if(HAVE_SYS_IOCCOM_H) + check_symbol_exists(BIOCSETIF "sys/types.h;sys/time.h;sys/ioctl.h;sys/socket.h;sys/ioccom.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) + else(HAVE_SYS_IOCCOM_H) + check_symbol_exists(BIOCSETIF "sys/types.h;sys/time.h;sys/ioctl.h;sys/socket.h;net/bpf.h;net/if.h" BPF_H_DEFINES_BIOCSETIF) + endif(HAVE_SYS_IOCCOM_H) + endif(HAVE_NET_BPF_H) + check_include_file(net/pfilt.h HAVE_NET_PFILT_H) + check_include_file(net/enet.h HAVE_NET_ENET_H) + check_include_file(net/nit.h HAVE_NET_NIT_H) + check_include_file(sys/net/nit.h HAVE_SYS_NET_NIT_H) + check_include_file(linux/socket.h HAVE_LINUX_SOCKET_H) + check_include_file(net/raw.h HAVE_NET_RAW_H) + check_include_file(sys/dlpi.h HAVE_SYS_DLPI_H) + check_include_file(config/HaikuConfig.h HAVE_CONFIG_HAIKUCONFIG_H) + + if(BPF_H_DEFINES_BIOCSETIF) + # + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. + # + set(PCAP_TYPE bpf) + elseif(HAVE_LINUX_SOCKET_H) + # + # No prizes for guessing this one. + # + set(PCAP_TYPE linux) + elseif(HAVE_NET_PFILT_H) + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # + set(PCAP_TYPE pf) + elseif(HAVE_NET_ENET_H) + # + # Stanford Enetfilter. + # + set(PCAP_TYPE enet) + elseif(HAVE_NET_NIT_H) + # + # SunOS 4.x STREAMS NIT. + # + set(PCAP_TYPE snit) + elseif(HAVE_SYS_NET_NIT_H) + # + # Pre-SunOS 4.x non-STREAMS NIT. + # + set(PCAP_TYPE nit) + elseif(HAVE_NET_RAW_H) + # + # IRIX snoop. + # + set(PCAP_TYPE snoop) + elseif(HAVE_SYS_DLPI_H) + # + # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. + # + set(PCAP_TYPE dlpi) + elseif(HAVE_CONFIG_HAIKUCONFIG_H) + # + # Haiku. + # + set(PCAP_TYPE haiku) + else() + # + # We don't have any capture type we know about. + # Report an error, and tell the user to configure with + # -DPCAP_TYPE=null if they want a libpcap that can't + # capture but that can read capture files. That way, + # nobody gets surprised by getting a no-capture + # libpcap without asking for that. + # + message(FATAL_ERROR "No supported packet capture interface was found. +See the INSTALL.md file for information on packet capture support in +various operating systems. +If you want a libpcap that cannot capture packets but that can read +pcap and pcapng files, run cmake with -DPCAP_TYPE=null.") + endif() + endif() +endif(WIN32) +message(STATUS "Packet capture mechanism type: ${PCAP_TYPE}") + +find_package(PkgConfig QUIET) + +# +# Do capture-mechanism-dependent tests. +# +if(WIN32) + if(PCAP_TYPE STREQUAL "npf") + # + # Link with packet.dll before Winsock2. + # + set(PCAP_LINK_LIBRARIES ${Packet_LIBRARIES} ${PCAP_LINK_LIBRARIES}) + elseif(PCAP_TYPE STREQUAL "null") + else() + message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type") + endif() +else(WIN32) + if(PCAP_TYPE STREQUAL "dlpi") + # + # Needed for common functions used by pcap-[dlpi,libdlpi].c + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} dlpisubs.c) + + # + # Checks for some header files. + # + check_include_file(sys/bufmod.h HAVE_SYS_BUFMOD_H) + check_include_file(sys/dlpi_ext.h HAVE_SYS_DLPI_EXT_H) + + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "-L/lib") + set(CMAKE_REQUIRED_LIBRARIES dlpi) + check_function_exists(dlpi_walk HAVE_LIBDLPI) + cmake_pop_check_state() + if(HAVE_LIBDLPI) + # + # XXX - add -L/lib + # + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} dlpi) + set(LIBS "${LIBS} -ldlpi") + set(LIBS_STATIC "${LIBS_STATIC} -ldlpi") + set(LIBS_PRIVATE "${LIBS_PRIVATE} -ldlpi") + set(PCAP_TYPE libdlpi) + endif() + + # + # This check is for Solaris with DLPI support for passive modes. + # See dlpi(7P) for more details. + # + # XXX - there's no check_type() macro that's like check_type_size() + # except that it only checks for the existence of the structure type, + # so we use check_type_size() and ignore the size. + # + cmake_push_check_state() + set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h sys/dlpi.h) + check_type_size(dl_passive_req_t DL_PASSIVE_REQ_T) + cmake_pop_check_state() + elseif(PCAP_TYPE STREQUAL "linux") + # + # Do we have the wireless extensions? + # linux/wireless.h requires sys/socket.h. + # + check_include_files("sys/socket.h;linux/wireless.h" HAVE_LINUX_WIRELESS_H) + + # + # Do we have libnl? + # We only want version 3. Version 2 was, apparently, + # short-lived, and version 1 is source and binary + # incompatible with version 3, and it appears that, + # these days, everybody's using version 3. We're + # not supporting older versions of the Linux kernel; + # let's drop support for older versions of libnl, too. + # + if(BUILD_WITH_LIBNL) + pkg_check_modules(LIBNL libnl-genl-3.0) + if(LIBNL_FOUND) + set(PCAP_LINK_LIBRARIES ${LIBNL_LIBRARIES} ${PCAP_LINK_LIBRARIES}) + + # + # Get raw link flags from pkg-config. + # + pkg_get_link_info(LIBNL libnl-genl-3.0) + set(LIBS "${LIBNL_LIBS} ${LIBS}") + set(LIBS_STATIC "${LIBNL_LIBS_STATIC} ${LIBS_STATIC}") + set(REQUIRES_PRIVATE "${LIBNL_PACKAGE_NAME} ${REQUIRES_PRIVATE}") + else() + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES nl-3) + check_function_exists(nl_socket_alloc HAVE_LIBNL) + cmake_pop_check_state() + if(HAVE_LIBNL) + # + # Yes, we have libnl 3.x. + # + set(PCAP_LINK_LIBRARIES nl-genl-3 nl-3 ${PCAP_LINK_LIBRARIES}) + include_directories("/usr/include/libnl3") + set(LIBS "-lnl-genl-3 -lnl-3 ${LIBS}") + set(LIBS_STATIC "-lnl-genl-3 -lnl-3 ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lnl-genl-3 -lnl-3 ${LIBS_PRIVATE}") + endif() + endif() + else() + unset(HAVE_LIBNL CACHE) # check_function_exists stores results in cache + endif() + + check_struct_has_member("struct tpacket_auxdata" tp_vlan_tci linux/if_packet.h HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI) + elseif(PCAP_TYPE STREQUAL "bpf") + # + # Check whether we have the *BSD-style ioctls. + # + check_include_files("sys/types.h;net/if_media.h" HAVE_NET_IF_MEDIA_H) + + # + # Check whether we have struct BPF_TIMEVAL. + # + # XXX - there's no check_type() macro that's like check_type_size() + # except that it only checks for the existence of the structure type, + # so we use check_type_size() and ignore the size. + # + cmake_push_check_state() + if(HAVE_SYS_IOCCOM_H) + set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h sys/ioccom.h net/bpf.h) + check_type_size("struct BPF_TIMEVAL" STRUCT_BPF_TIMEVAL) + else() + set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h net/bpf.h) + check_type_size("struct BPF_TIMEVAL" STRUCT_BPF_TIMEVAL) + endif() + cmake_pop_check_state() + + # + # Check whether there's a inet/ipnet.h header and, + # if so, whether it defines IPNET_ANY_LINK - if so, + # we assume we have the "any" device (that's a + # Solaris header, and later versions of Solaris + # have an "any" device). + # + # Attempting to include it at compile time could + # be a pain, as it's a kernel header. + # + message(STATUS "Checking whether the Solaris \"any\" device is supported") + if(EXISTS /usr/include/inet/ipnet.h) + file(STRINGS /usr/include/inet/ipnet.h IPNET_ANY_LINK_LINES REGEX IPNET_ANY_LINK) + if(NOT IPNET_ANY_LINK_LINES STREQUAL "") + set(HAVE_SOLARIS_ANY_DEVICE TRUE) + endif() + endif() + if(HAVE_SOLARIS_ANY_DEVICE) + message(STATUS "Checking whether the Solaris \"any\" device is supported - supported") + else() + message(STATUS "Checking whether the Solaris \"any\" device is supported - not supported") + endif() + elseif(PCAP_TYPE STREQUAL "haiku") + # + # Check for some headers just in case. + # + check_include_files("net/if.h;net/if_dl.h;net/if_types.h" HAVE_NET_IF_TYPES_H) + set(PCAP_SRC pcap-${PCAP_TYPE}.c) + elseif(PCAP_TYPE STREQUAL "null") + else() + message(FATAL_ERROR "${PCAP_TYPE} is not a valid pcap type") + endif() +endif(WIN32) + +if(NOT DEFINED PCAP_SRC) +set(PCAP_SRC pcap-${PCAP_TYPE}.c) +endif() + +set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${PCAP_SRC}) + +# +# Now figure out how we get a list of interfaces and addresses, +# if we support capturing. Don't bother if we don't support +# capturing. +# +if(NOT WIN32) + # + # UN*X - figure out what type of interface list mechanism we + # have. + # + # If the capture type is null, that means we can't capture, + # so we can't open any capture devices, so we won't return + # any interfaces. + # + if(NOT PCAP_TYPE STREQUAL "null") + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LINK_LIBRARIES}) + check_function_exists(getifaddrs HAVE_GETIFADDRS) + cmake_pop_check_state() + if(NOT HAVE_GETIFADDRS) + # + # It's not in the libraries that, at this point, we've + # found we need to link libpcap with. + # + # It's in libsocket on Solaris and possibly other OSes; + # as long as we're not linking with libxnet, check there. + # + # NOTE: if you hand check_library_exists as its last + # argument a variable that's been set, it skips the test, + # so we need different variables. + # + if(NOT LIBXNET_HAS_GETHOSTBYNAME) + check_library_exists(socket getifaddrs "" SOCKET_HAS_GETIFADDRS) + if(SOCKET_HAS_GETIFADDRS) + set(PCAP_LINK_LIBRARIES socket ${PCAP_LINK_LIBRARIES}) + set(LIBS "-lsocket ${LIBS}") + set(LIBS_STATIC "-lsocket ${LIBS_STATIC}") + set(LIBS_PRIVATE "-lsocket ${LIBS_PRIVATE}") + set(HAVE_GETIFADDRS TRUE) + endif() + endif() + endif() + if(HAVE_GETIFADDRS) + # + # We have "getifaddrs()"; make sure we have + # as well, just in case some platform is really weird. + # It may require that sys/types.h be included first, + # so include it first. + # + check_include_files("sys/types.h;ifaddrs.h" HAVE_IFADDRS_H) + if(HAVE_IFADDRS_H) + # + # We have the header, so we use "getifaddrs()" to + # get the list of interfaces. + # + set(FINDALLDEVS_TYPE getad) + else() + # + # We don't have the header - give up. + # XXX - we could also fall back on some other + # mechanism, but, for now, this'll catch this + # problem so that we can at least try to figure + # out something to do on systems with "getifaddrs()" + # but without "ifaddrs.h", if there is something + # we can do on those systems. + # + message(FATAL_ERROR "Your system has getifaddrs() but doesn't have a usable .") + endif() + else() + # + # Well, we don't have "getifaddrs()", at least not with the + # libraries with which we've decided we need to link + # libpcap with, so we have to use some other mechanism. + # + # Note that this may happen on Solaris, which has + # getifaddrs(), but in -lsocket, not in -lxnet, so we + # won't find it if we link with -lxnet, which we want + # to do for other reasons. + # + # For now, we use either the SIOCGIFCONF ioctl or the + # SIOCGLIFCONF ioctl, preferring the latter if we have + # it; the latter is a Solarisism that first appeared + # in Solaris 8. (Solaris's getifaddrs() appears to + # be built atop SIOCGLIFCONF; using it directly + # avoids a not-all-that-useful middleman.) + # + try_compile(HAVE_SIOCGLIFCONF ${CMAKE_CURRENT_BINARY_DIR} "${pcap_SOURCE_DIR}/cmake/have_siocglifconf.c" ) + if(HAVE_SIOCGLIFCONF) + set(FINDALLDEVS_TYPE glifc) + else() + set(FINDALLDEVS_TYPE gifc) + endif() + endif() + message(STATUS "Find-interfaces mechanism type: ${FINDALLDEVS_TYPE}") + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} fad-${FINDALLDEVS_TYPE}.c) + endif() +endif() + +# Check for hardware timestamp support. +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + check_include_file(linux/net_tstamp.h HAVE_LINUX_NET_TSTAMP_H) +endif() + +# +# Check for additional native sniffing capabilities. +# + +# +# Various Linux-specific mechanisms. +# +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Check for usbmon USB sniffing support. + if(NOT DISABLE_LINUX_USBMON) + set(PCAP_SUPPORT_LINUX_USBMON TRUE) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-usb-linux.c) + # + # Do we have a version of available? + # If so, we might need it for . + # + check_include_files("linux/compiler.h" HAVE_LINUX_COMPILER_H) + if(HAVE_LINUX_COMPILER_H) + # + # Yes - include it when testing for . + # + check_include_files("linux/compiler.h;linux/usbdevice_fs.h" HAVE_LINUX_USBDEVICE_FS_H) + else(HAVE_LINUX_COMPILER_H) + check_include_files("linux/usbdevice_fs.h" HAVE_LINUX_USBDEVICE_FS_H) + endif(HAVE_LINUX_COMPILER_H) + if(HAVE_LINUX_USBDEVICE_FS_H) + # + # OK, does it define bRequestType? Older versions of the kernel + # define fields with names like "requesttype, "request", and + # "value", rather than "bRequestType", "bRequest", and + # "wValue". + # + if(HAVE_LINUX_COMPILER_H) + check_struct_has_member("struct usbdevfs_ctrltransfer" bRequestType "linux/compiler.h;linux/usbdevice_fs.h" HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE) + else(HAVE_LINUX_COMPILER_H) + check_struct_has_member("struct usbdevfs_ctrltransfer" bRequestType "linux/usbdevice_fs.h" HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE) + endif(HAVE_LINUX_COMPILER_H) + endif() + endif() + + # + # Check for netfilter sniffing support. + # + # Life's too short to deal with trying to get this to compile + # if you don't get the right types defined with + # __KERNEL_STRICT_NAMES getting defined by some other include. + # + # Check whether the includes Just Work. If not, don't turn on + # netfilter support. + # + check_c_source_compiles( +"#include +#include +#include + +#include +#include +#include +#include +#include + +int +main(void) +{ + return 0; +} +" + PCAP_SUPPORT_NETFILTER) + if(PCAP_SUPPORT_NETFILTER) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-netfilter-linux.c) + endif(PCAP_SUPPORT_NETFILTER) +endif() + +# Check for netmap sniffing support. +if(NOT DISABLE_NETMAP) + # + # Check whether net/netmap_user.h is usable if NETMAP_WITH_LIBS is + # defined; it's not usable on DragonFly BSD 4.6 if NETMAP_WITH_LIBS + # is defined, for example, as it includes a nonexistent malloc.h + # header. + # + check_c_source_compiles( +"#define NETMAP_WITH_LIBS +#include + +int +main(void) +{ + return 0; +} +" + PCAP_SUPPORT_NETMAP) + if(PCAP_SUPPORT_NETMAP) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-netmap.c) + endif(PCAP_SUPPORT_NETMAP) +endif() + +# Check for DPDK sniffing support +if(NOT DISABLE_DPDK) + find_package(dpdk) + if(dpdk_FOUND) + # + # We call rte_eth_dev_count_avail(), and older versions of DPDK + # didn't have it, so check for it. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${dpdk_LIBRARIES}) + check_function_exists(rte_eth_dev_count_avail HAVE_RTE_ETH_DEV_COUNT_AVAIL) + cmake_pop_check_state() + if(HAVE_RTE_ETH_DEV_COUNT_AVAIL) + set(DPDK_C_FLAGS "-march=native") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DPDK_C_FLAGS}") + include_directories(AFTER ${dpdk_INCLUDE_DIRS}) + link_directories(AFTER ${dpdk_LIBRARIES}) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${dpdk_LIBRARIES}) + set(LIBS "${LIBS} ${dpdk_LIBS}") + set(LIBS_STATIC "${LIBS_STATIC} ${dpdk_LIBS_STATIC}") + set(REQUIRES_PRIVATE "${REQUIRES_PRIVATE} ${dpdk_PACKAGE_NAME}") + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dpdk.c) + set(PCAP_SUPPORT_DPDK TRUE) + + # + # Check whether the rte_ether.h file defines + # struct ether_addr or struct rte_ether_addr. + # + # ("API compatibility? That's for losers!") + # + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${dpdk_INCLUDE_DIRS}) + set(CMAKE_EXTRA_INCLUDE_FILES rte_ether.h) + check_type_size("struct rte_ether_addr" STRUCT_RTE_ETHER_ADDR) + cmake_pop_check_state() + endif() + else() + message(WARNING, +"We couldn't find DPDK with pkg-config. If you want DPDK support, +make sure that pkg-config is installed, that DPDK 18.02.2 or later is +installed, and that DPDK provides a .pc file.") + endif() +endif() + +# Check for Bluetooth sniffing support +if(NOT DISABLE_BLUETOOTH) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + check_include_file(bluetooth/bluetooth.h HAVE_BLUETOOTH_BLUETOOTH_H) + if(HAVE_BLUETOOTH_BLUETOOTH_H) + set(PCAP_SUPPORT_BT TRUE) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-bt-linux.c) + # + # OK, does struct sockaddr_hci have an hci_channel + # member? + # + check_struct_has_member("struct sockaddr_hci" hci_channel "bluetooth/bluetooth.h;bluetooth/hci.h" HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL) + if(HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL) + # + # OK, is HCI_CHANNEL_MONITOR defined? + # + check_c_source_compiles( +"#include +#include + +int +main(void) +{ + int i = HCI_CHANNEL_MONITOR; + return 0; +} +" + PCAP_SUPPORT_BT_MONITOR) + if(PCAP_SUPPORT_BT_MONITOR) + # + # Yes, so we can also support Bluetooth monitor + # sniffing. + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-bt-monitor-linux.c) + endif(PCAP_SUPPORT_BT_MONITOR) + endif(HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL) + endif(HAVE_BLUETOOTH_BLUETOOTH_H) + endif() +else() + unset(PCAP_SUPPORT_BT_MONITOR CACHE) +endif() + +# Check for D-Bus sniffing support +if(NOT DISABLE_DBUS) + # + # We don't support D-Bus sniffing on macOS; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + if(APPLE) + message(FATAL_ERROR "Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS") + endif(APPLE) + pkg_check_modules(DBUS dbus-1) + if(DBUS_FOUND) + set(PCAP_SUPPORT_DBUS TRUE) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dbus.c) + include_directories(${DBUS_INCLUDE_DIRS}) + + # + # This "helpfully" supplies DBUS_LIBRARIES as a bunch of + # library names - not paths - and DBUS_LIBRARY_DIRS as + # a bunch of directories. + # + # CMake *really* doesn't like the notion of specifying "here are + # the directories in which to look for libraries" except in + # find_library() calls; it *really* prefers using full paths to + # library files, rather than library names. + # + # Find the libraries and add their full paths. + # + set(DBUS_LIBRARY_FULLPATHS) + foreach(_lib IN LISTS DBUS_LIBRARIES) + # + # Try to find this library, so we get its full path. + # + find_library(_libfullpath ${_lib} HINTS ${DBUS_LIBRARY_DIRS}) + list(APPEND DBUS_LIBRARY_FULLPATHS ${_libfullpath}) + endforeach() + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${DBUS_LIBRARY_FULLPATHS}) + + # + # Get library information for DPDK. + # + pkg_get_link_info(DBUS dbus-1) + set(LIBS "${LIBS} ${DBUS_LIBS}") + set(LIBS_STATIC "${LIBS_STATIC} ${DBUS_LIBS_STATIC}") + set(REQUIRES_PRIVATE "${REQUIRES_PRIVATE} ${DBUS_PACKAGE_NAME}") + endif(DBUS_FOUND) +endif(NOT DISABLE_DBUS) + +# Check for RDMA sniffing support +if(NOT DISABLE_RDMA) + pkg_check_modules(LIBIBVERBS libibverbs) + if(LIBIBVERBS_FOUND) + # + # pkg-config found it; remember its pkg-config name. + # + set(LIBIBVERBS_REQUIRES_PRIVATE ${LIBIBVERBS_PACKAGE_NAME}) + + # + # Get static linking information for it. + # + pkg_get_link_info(LIBIBVERBS libibverbs) + else() + # + # pkg-config didn't find it; try to look for it ourselves + # + check_library_exists(ibverbs ibv_get_device_list "" LIBIBVERBS_HAS_IBV_GET_DEVICE_LIST) + if(LIBIBVERBS_HAS_IBV_GET_DEVICE_LIST) + set(LIBIBVERBS_FOUND TRUE) + set(LIBIBVERBS_LIBRARIES ibverbs) + # XXX - at least on Ubuntu 20.04, there are many more + # libraries needed; is there any platform where + # libibverbs is available but where pkg-config + # isn't available or libibverbs doesn't use it? + # If not, we should only use pkg-config for it. + set(LIBIBVERBS_STATIC_LIBRARIES ibverbs) + set(LIBIBVERBS_LIBS -libverbs) + set(LIBIBVERBS_LIBS_STATIC -libverbs) + set(LIBIBVERBS_LIBS_PRIVATE -libverbs) + endif() + endif() + if(LIBIBVERBS_FOUND) + # + # For unknown reasons, check_include_file() doesn't just attempt + # to compile a test program that includes the header in + # question, it also attempts to link it. + # + # For unknown reasons, at least some of the static inline + # functions defined in infiniband/verbs.h are not inlined by the + # Sun^WOracle Studio C compiler, so the compiler generates code + # for them as part of the object code resulting from compiling + # the test program. At lest some of those functions call + # routines in -libverbs, so, in order to keep the compile and + # link from failing, even though the header file exists and is + # usable, we need to link with -libverbs. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES ${LIBIBVERBS_LIBRARIES}) + check_include_file(infiniband/verbs.h HAVE_INFINIBAND_VERBS_H) + if(HAVE_INFINIBAND_VERBS_H) + check_symbol_exists(ibv_create_flow infiniband/verbs.h PCAP_SUPPORT_RDMASNIFF) + if(PCAP_SUPPORT_RDMASNIFF) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-rdmasniff.c) + set(PCAP_LINK_LIBRARIES ${LIBIBVERBS_LIBRARIES} ${PCAP_LINK_LIBRARIES}) + set(LIBS "${LIBIBVERBS_LIBS} ${LIBS}") + set(LIBS_STATIC "${LIBIBVERBS_LIBS_STATIC} ${LIBS_STATIC}") + set(LIBS_PRIVATE "${LIBIBVERBS_LIBS_PRIVATE} ${LIBS_PRIVATE}") + set(REQUIRES_PRIVATE "${REQUIRES_PRIVATE} ${LIBIBVERBS_PACKAGE_NAME}") + endif(PCAP_SUPPORT_RDMASNIFF) + endif(HAVE_INFINIBAND_VERBS_H) + cmake_pop_check_state() + endif(LIBIBVERBS_FOUND) +endif(NOT DISABLE_RDMA) + +# +# Check for sniffing capabilities using third-party APIs. +# + +# Check for Endace DAG card support. +if(NOT DISABLE_DAG) + # + # Try to find the DAG header file and library. + # + find_package(DAG) + + # + # Did we succeed? + # + if(DAG_FOUND) + # + # Yes. + # Check for various DAG API functions. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${DAG_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${DAG_LIBRARIES}) + check_function_exists(dag_attach_stream HAVE_DAG_STREAMS_API) + if(NOT HAVE_DAG_STREAMS_API) + message(FATAL_ERROR "DAG library lacks streams support") + endif() + check_function_exists(dag_attach_stream64 HAVE_DAG_LARGE_STREAMS_API) + check_function_exists(dag_get_erf_types HAVE_DAG_GET_ERF_TYPES) + check_function_exists(dag_get_stream_erf_types HAVE_DAG_GET_STREAM_ERF_TYPES) + cmake_pop_check_state() + + include_directories(AFTER ${DAG_INCLUDE_DIRS}) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-dag.c) + set(HAVE_DAG_API TRUE) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${DAG_LIBRARIES}) + set(LIBS "${LIBS} ${DAG_LIBS}") + set(LIBS_STATIC "${LIBS_STATIC} ${DAG_LIBS_STATIC}") + set(LIBS_PRIVATE "${LIBS_PRIVATE} ${DAG_LIBS_PRIVATE}") + + if(HAVE_DAG_LARGE_STREAMS_API) + get_filename_component(DAG_LIBRARY_DIR ${DAG_LIBRARY} PATH) + check_library_exists(vdag vdag_set_device_info ${DAG_LIBRARY_DIR} HAVE_DAG_VDAG) + if(HAVE_DAG_VDAG) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + set(LIBS "${LIBS} ${CMAKE_THREAD_LIBS_INIT}") + set(LIBS_STATIC "${LIBS_STATIC} ${CMAKE_THREAD_LIBS_INIT}") + set(LIBS_PRIVATE "${LIBS_PRIVATE} ${CMAKE_THREAD_LIBS_INIT}") + endif() + endif() + endif() +endif() + +# Check for Septel card support. +set(PROJECT_EXTERNAL_OBJECT_LIST "") +if(NOT DISABLE_SEPTEL) + # + # Do we have the msg.h header? + # + set(SEPTEL_INCLUDE_DIRS "${SEPTEL_ROOT}/INC") + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${SEPTEL_INCLUDE_DIRS}) + check_include_file(msg.h HAVE_INC_MSG_H) + cmake_pop_check_state() + if(HAVE_INC_MSG_H) + # + # Yes. + # + include_directories(AFTER ${SEPTEL_INCLUDE_DIRS}) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-septel.c) + set(PROJECT_EXTERNAL_OBJECT_LIST ${PROJECT_EXTERNAL_OBJECT_LIST} "${SEPTEL_ROOT}/asciibin.o ${SEPTEL_ROOT}/bit2byte.o ${SEPTEL_ROOT}/confirm.o ${SEPTEL_ROOT}/fmtmsg.o ${SEPTEL_ROOT}/gct_unix.o ${SEPTEL_ROOT}/hqueue.o ${SEPTEL_ROOT}/ident.o ${SEPTEL_ROOT}/mem.o ${SEPTEL_ROOT}/pack.o ${SEPTEL_ROOT}/parse.o ${SEPTEL_ROOT}/pool.o ${SEPTEL_ROOT}/sdlsig.o ${SEPTEL_ROOT}/strtonum.o ${SEPTEL_ROOT}/timer.o ${SEPTEL_ROOT}/trace.o") + set(HAVE_SEPTEL_API TRUE) + endif() +endif() + +# Check for Myricom SNF support. +if(NOT DISABLE_SNF) + # + # Try to find the SNF header file and library. + # + find_package(SNF) + + # + # Did we succeed? + # + if(SNF_FOUND) + # + # Yes. + # + include_directories(AFTER ${SNF_INCLUDE_DIRS}) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-snf.c) + set(HAVE_SNF_API TRUE) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${SNF_LIBRARIES}) + set(LIBS "${LIBS_STATIC} ${SNF_LIBS}") + set(LIBS_STATIC "${LIBS_STATIC} ${SNF_LIBS_STATIC}") + set(LIBS_PRIVATE "${LIBS_PRIVATE} ${SNF_LIBS_PRIVATE}") + endif() +endif() + +# Check for Riverbed AirPcap support. +if(NOT DISABLE_AIRPCAP) + # + # Try to find the AirPcap header file and library. + # + find_package(AirPcap) + + # + # Did we succeed? + # + if(AirPcap_FOUND) + # + # Yes. + # + include_directories(AFTER ${AirPcap_INCLUDE_DIRS}) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-airpcap.c) + set(HAVE_AIRPCAP_API TRUE) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${AirPcap_LIBRARIES}) + endif() +endif() + +# Check for Riverbed TurboCap support. +if(NOT DISABLE_TC) + # + # Try to find the TurboCap header file and library. + # + find_package(TC) + + # + # Did we succeed? + # + if(TC_FOUND) + # + # Yes. + # + include_directories(AFTER ${TC_INCLUDE_DIRS}) + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} pcap-tc.c) + set(HAVE_TC_API TRUE) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} ${TC_LIBRARIES} ${CMAKE_USE_PTHREADS_INIT} stdc++) + endif() +endif() + +# +# Remote capture support. +# + +if(ENABLE_REMOTE) + # + # Check for various members of struct msghdr. + # We need to include ftmacros.h on some platforms, to make sure we + # get the POSIX/Single USER Specification version of struct msghdr, + # which has those members, rather than the backwards-compatible + # version, which doesn't. That's not a system header file, and + # at least some versions of CMake include it as , which + # won't check the current directory, so we add the top-level + # source directory to the list of include directories when we do + # the check. + # + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) + check_struct_has_member("struct msghdr" msg_control "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_CONTROL) + check_struct_has_member("struct msghdr" msg_flags "ftmacros.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_FLAGS) + cmake_pop_check_state() + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} + pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c sslutils.c) +endif(ENABLE_REMOTE) + +################################################################### +# Warning options +################################################################### + +# +# Check and add warning options if we have a .devel file. +# +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.devel OR EXISTS ${CMAKE_BINARY_DIR}/.devel) + # + # Warning options. + # + if(MSVC AND NOT ${CMAKE_C_COMPILER} MATCHES "clang*") + # + # MSVC, with Microsoft's front end and code generator. + # "MSVC" is also set for Microsoft's compiler with a Clang + # front end and their code generator ("Clang/C2"), so we + # check for clang.exe and treat that differently. + # + check_and_add_compiler_option(-Wall) + # + # Disable some pointless warnings that /Wall turns on. + # + # Unfortunately, MSVC does not appear to have an equivalent + # to "__attribute__((unused))" to mark a particular function + # parameter as being known to be unused, so that the compiler + # won't warn about it (for example, the function might have + # that parameter because a pointer to it is being used, and + # the signature of that function includes that parameter). + # C++ lets you give a parameter a type but no name, but C + # doesn't have that. + # + check_and_add_compiler_option(-wd4100) + # + # In theory, we care whether somebody uses f() rather than + # f(void) to declare a function with no arguments, but, in + # practice, there are places in the Windows header files + # that appear to do that, so we squelch that warning. + # + check_and_add_compiler_option(-wd4255) + # + # Windows FD_SET() generates this, so we suppress it. + # + check_and_add_compiler_option(-wd4548) + # + # Perhaps testing something #defined to be 0 with #ifdef is an + # error, and it should be tested with #if, but perhaps it's + # not, and Microsoft does that in its headers, so we squelch + # that warning. + # + check_and_add_compiler_option(-wd4574) + # + # The Windows headers also test not-defined values in #if, so + # we don't want warnings about that, either. + # + check_and_add_compiler_option(-wd4668) + # + # We do *not* care whether some function is, or isn't, going to be + # expanded inline. + # + check_and_add_compiler_option(-wd4710) + check_and_add_compiler_option(-wd4711) + # + # We do *not* care whether we're adding padding bytes after + # structure members. + # + check_and_add_compiler_option(-wd4820) + # + # We do *not* care about every single place the compiler would + # have inserted Spectre mitigation if only we had told it to + # do so with /Qspectre. Maybe it's worth it, as that's in + # Bison-generated code that we don't control. + # + # XXX - add /Qspectre if that is really worth doing. + # + check_and_add_compiler_option(-wd5045) + + # + # Treat all (remaining) warnings as errors. + # + check_and_add_compiler_option(-WX) + else() + # + # Other compilers, including MSVC with a Clang front end and + # Microsoft's code generator. We currently treat them as if + # they might support GCC-style -W options. + # + check_and_add_compiler_option(-W) + check_and_add_compiler_option(-Wall) + check_and_add_compiler_option(-Wcomma) + # Warns about safeguards added in case the enums are extended + # check_and_add_compiler_option(-Wcovered-switch-default) + check_and_add_compiler_option(-Wdocumentation) + check_and_add_compiler_option(-Wformat-nonliteral) + check_and_add_compiler_option(-Wmissing-noreturn) + check_and_add_compiler_option(-Wmissing-prototypes) + check_and_add_compiler_option(-Wmissing-variable-declarations) + check_and_add_compiler_option(-Wnull-pointer-subtraction) + check_and_add_compiler_option(-Wpointer-arith) + check_and_add_compiler_option(-Wpointer-sign) + check_and_add_compiler_option(-Wshadow) + check_and_add_compiler_option(-Wshorten-64-to-32) + check_and_add_compiler_option(-Wsign-compare) + check_and_add_compiler_option(-Wstrict-prototypes) + check_and_add_compiler_option(-Wundef) + check_and_add_compiler_option(-Wunreachable-code) + check_and_add_compiler_option(-Wunused-but-set-parameter) + check_and_add_compiler_option(-Wunused-but-set-variable) + check_and_add_compiler_option(-Wunused-parameter) + check_and_add_compiler_option(-Wused-but-marked-unused) + endif() +endif() + +# +# Suppress some warnings we get with MSVC even without /Wall. +# +if(MSVC AND NOT ${CMAKE_C_COMPILER} MATCHES "clang*") + # + # Yes, we have some functions that never return but that + # have a non-void return type. That's because, on some + # platforms, they *do* return values but, on other + # platforms, including Windows, they just fail and + # longjmp out by calling bpf_error(). + # + check_and_add_compiler_option(-wd4646) +endif() + +file(GLOB PROJECT_SOURCE_LIST_H + *.h + pcap/*.h +) + +# +# Try to have the compiler default to hiding symbols, so that only +# symbols explicitly exported with PCAP_API will be visible outside +# (shared) libraries. +# +# Not necessary with MSVC, as that's the default. +# +# XXX - we don't use ADD_COMPILER_EXPORT_FLAGS, because, as of CMake +# 2.8.12.2, it doesn't know about Sun C/Oracle Studio, and, as of +# CMake 2.8.6, it only sets the C++ compiler flags, rather than +# allowing an arbitrary variable to be set with the "hide symbols +# not explicitly exported" flag. +# +if(NOT MSVC) + if(CMAKE_C_COMPILER_ID MATCHES "SunPro") + # + # Sun C/Oracle Studio. + # + check_and_add_compiler_option(-xldscope=hidden) + else() + # + # Try this for all other compilers; it's what GCC uses, + # and a number of other compilers, such as Clang and Intel C, + # use it as well. + # + check_and_add_compiler_option(-fvisibility=hidden) + endif() +endif(NOT MSVC) + +# +# Extra compiler options for the build matrix scripts to request -Werror or +# its equivalent if required. The CMake variable name cannot be CFLAGS +# because that is already used for a different purpose in CMake. Example +# usage: cmake -DEXTRA_CFLAGS='-Wall -Wextra -Werror' ... +# +if(NOT "${EXTRA_CFLAGS}" STREQUAL "") + # The meaning of EXTRA_CFLAGS is "use the exact specified options, or the + # build risks failing to fail", not "try every specified option, omit those + # that do not work and use the rest". Thus use add_compile_options(), not + # foreach()/check_and_add_compiler_option(). Another reason to do that is + # that the effect lasts in testprogs/ and testprogs/fuzz/. + string(REPLACE " " ";" _extra_cflags_list ${EXTRA_CFLAGS}) + add_compile_options(${_extra_cflags_list}) + message(STATUS "Added extra compile options (${EXTRA_CFLAGS})") +endif() + +# +# Flex/Lex and YACC/Berkeley YACC/Bison. +# From a mail message to the CMake mailing list by Andy Cedilnik of +# Kitware. +# + +# +# Try to find Flex, a Windows version of Flex, or Lex. +# +find_program(LEX_EXECUTABLE NAMES flex win_flex lex) +if(LEX_EXECUTABLE STREQUAL "LEX_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Neither flex nor win_flex nor lex was found.") +endif() +message(STATUS "Lexical analyzer generator: ${LEX_EXECUTABLE}") + +# +# Make sure {f}lex supports the -P, --header-file, and --nounput flags +# and supports processing our scanner.l. +# +if(WIN32) + set(NULL_DEVICE "NUL:") +else() + set(NULL_DEVICE "/dev/null") +endif() +execute_process(COMMAND ${LEX_EXECUTABLE} -P pcap_ --header-file=${NULL_DEVICE} --nounput -t ${pcap_SOURCE_DIR}/scanner.l + OUTPUT_QUIET RESULT_VARIABLE EXIT_STATUS) +if(NOT EXIT_STATUS EQUAL 0) + message(FATAL_ERROR "${LEX_EXECUTABLE} is insufficient to compile libpcap. +libpcap requires Flex 2.5.31 or later, or a compatible version of lex. +If a suitable version of Lex/Flex is available as a non-standard command +and/or not in the PATH, you can specify it using the LEX environment +variable. That said, on some systems the error can mean that Flex/Lex is +actually acceptable, but m4 is not. Likewise, if a suitable version of +m4 (such as GNU M4) is available but has not been detected, you can +specify it using the M4 environment variable.") +endif() + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/scanner.c ${CMAKE_CURRENT_BINARY_DIR}/scanner.h + SOURCE ${pcap_SOURCE_DIR}/scanner.l + COMMAND ${LEX_EXECUTABLE} -P pcap_ --header-file=scanner.h --nounput -o${CMAKE_CURRENT_BINARY_DIR}/scanner.c ${pcap_SOURCE_DIR}/scanner.l + DEPENDS ${pcap_SOURCE_DIR}/scanner.l +) + +# +# Since scanner.c does not exist yet when cmake is run, mark +# it as generated. +# +# Since scanner.c includes grammar.h, mark that as a dependency. +# +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/scanner.c PROPERTIES + GENERATED TRUE + OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/grammar.h +) + +# +# Add scanner.c to the list of sources. +# +#set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${CMAKE_CURRENT_BINARY_DIR}/scanner.c) + +# +# Try to find YACC or Bison. +# +find_program(YACC_EXECUTABLE NAMES bison win_bison byacc yacc) +if(YACC_EXECUTABLE STREQUAL "YACC_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Neither bison nor win_bison nor byacc nor yacc was found.") +endif() + +if(YACC_EXECUTABLE MATCHES "byacc" OR YACC_EXECUTABLE MATCHES "yacc") + # + # Make sure this is Berkeley YACC, not AT&T YACC; + # the latter doesn't support reentrant parsers. + # Run it with "-V"; that succeeds and reports the + # version number with Berkeley YACC, but will + # (probably) fail with various vendor flavors + # of AT&T YACC. + # + # Hopefully this also eliminates any versions + # of Berkeley YACC that don't support reentrant + # parsers, if there are any. + # + execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_QUIET + RESULT_VARIABLE EXIT_STATUS) + if(NOT EXIT_STATUS EQUAL 0) + message(FATAL_ERROR "${YACC_EXECUTABLE} is insufficient to compile libpcap. +libpcap requires Bison, a newer version of Berkeley YACC with support +for reentrant parsers, or another YACC compatible with them.") + endif() + # + # Berkeley YACC doesn't support "%define api.pure", so use + # "%pure-parser". + # + set(REENTRANT_PARSER "%pure-parser") +else() + # + # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use + # "%pure-parser". + # + execute_process(COMMAND ${YACC_EXECUTABLE} -V OUTPUT_VARIABLE bison_full_version) + string(REGEX MATCH "[1-9][0-9]*[.][0-9]+" bison_major_minor ${bison_full_version}) + if (bison_major_minor VERSION_LESS "2.4") + set(REENTRANT_PARSER "%pure-parser") + else() + set(REENTRANT_PARSER "%define api.pure") + endif() +endif() + +message(STATUS "Parser generator: ${YACC_EXECUTABLE}") + +# +# Create custom command for the scanner. +# +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/grammar.c ${CMAKE_CURRENT_BINARY_DIR}/grammar.h + SOURCE ${pcap_BINARY_DIR}/grammar.y + COMMAND ${YACC_EXECUTABLE} -p pcap_ -o ${CMAKE_CURRENT_BINARY_DIR}/grammar.c -d ${pcap_BINARY_DIR}/grammar.y + DEPENDS ${pcap_BINARY_DIR}/grammar.y +) + +# +# Since grammar.c does not exists yet when cmake is run, mark +# it as generated. +# +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/grammar.c PROPERTIES + GENERATED TRUE + OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/scanner.h +) + +# +# Add grammar.c to the list of sources. +# +#set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${CMAKE_CURRENT_BINARY_DIR}/grammar.c) + +# +# Assume, by default, no support for shared libraries and V7/BSD +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. +# Individual cases can override this. +# +set(MAN_DEVICES 4) +set(MAN_FILE_FORMATS 5) +set(MAN_MISC_INFO 7) +set(MAN_ADMIN_COMMANDS 8) +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + # Workaround to enable certain features + set(_SUN TRUE) + if(PCAP_TYPE STREQUAL "bpf") + # + # If we're using BPF, we need libodm and libcfg, as + # we use them to load the BPF module. + # + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} odm cfg) + set(LIBS "${LIBS} -lodm -lcfg") + set(LIBS_STATIC "${LIBS_STATIC} -lodm -lcfg") + set(LIBS_PRIVATE "${LIBS_PRIVATE} -lodm -lcfg") + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + if(CMAKE_SYSTEM_VERSION MATCHES "[A-Z.]*9\.[0-9]*") + # + # HP-UX 9.x. + # + set(HAVE_HPUX9 TRUE) + elseif(CMAKE_SYSTEM_VERSION MATCHES "[A-Z.]*10\.0") + # + # HP-UX 10.0. + # + elseif(CMAKE_SYSTEM_VERSION MATCHES "[A-Z.]*10\.1") + # + # HP-UX 10.1. + # + else() + # + # HP-UX 10.20 and later. + # + set(HAVE_HPUX10_20_OR_LATER TRUE) + endif() + + # + # Use System V conventions for man pages. + # + set(MAN_ADMIN_COMMANDS 1m) + set(MAN_FILE_FORMATS 4) + set(MAN_MISC_INFO 5) +elseif(CMAKE_SYSTEM_NAME STREQUAL "IRIX" OR CMAKE_SYSTEM_NAME STREQUAL "IRIX64") + # + # Use IRIX conventions for man pages; they're the same as the + # System V conventions, except that they use section 8 for + # administrative commands and daemons. + # + set(MAN_FILE_FORMATS 4) + set(MAN_MISC_INFO 5) +elseif(CMAKE_SYSTEM_NAME STREQUAL "OSF1") + # + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. + # Use Tru64 UNIX conventions for man pages; they're the same as the + # System V conventions except that they use section 8 for + # administrative commands and daemons. + # + set(MAN_FILE_FORMATS 4) + set(MAN_MISC_INFO 5) + set(MAN_DEVICES 7) +elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") + # + # SunOS 5.x. + # + set(HAVE_SOLARIS TRUE) + # + # Make sure errno is thread-safe, in case we're called in + # a multithreaded program. We don't guarantee that two + # threads can use the *same* pcap_t safely, but the + # current version does guarantee that you can use different + # pcap_t's in different threads, and even that pcap_compile() + # is thread-safe (it wasn't thread-safe in some older versions). + # + add_definitions(-D_TS_ERRNO) + + if(CMAKE_SYSTEM_VERSION STREQUAL "5.12") + else() + # + # Use System V conventions for man pages. + # + set(MAN_ADMIN_COMMANDS 1m) + set(MAN_FILE_FORMATS 4) + set(MAN_MISC_INFO 5) + set(MAN_DEVICES 7D) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku") + # + # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't use them. + # + add_definitions(-D_BSD_SOURCE) +endif() + +source_group("Source Files" FILES ${PROJECT_SOURCE_LIST_C}) +source_group("Header Files" FILES ${PROJECT_SOURCE_LIST_H}) + +if(WIN32) + # + # Add pcap-dll.rc to the list of sources. + # + set(PROJECT_SOURCE_LIST_C ${PROJECT_SOURCE_LIST_C} ${pcap_SOURCE_DIR}/pcap-dll.rc) +endif(WIN32) + +# +# Add subdirectories after we've set various variables, so they pick up +# pick up those variables. +# +if(ENABLE_REMOTE) + add_subdirectory(rpcapd) +endif(ENABLE_REMOTE) +add_subdirectory(testprogs) + +###################################### +# Register targets +###################################### + +# +# Special target to serialize the building of the generated source. +# +# See +# +# https://public.kitware.com/pipermail/cmake/2013-August/055510.html +# +add_custom_target(SerializeTarget + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/grammar.c + ${CMAKE_CURRENT_BINARY_DIR}/scanner.c +) + +set_source_files_properties(${PROJECT_EXTERNAL_OBJECT_LIST} PROPERTIES + EXTERNAL_OBJECT TRUE) + +if(BUILD_SHARED_LIBS) + add_library(${LIBRARY_NAME} SHARED + ${PROJECT_SOURCE_LIST_C} + ${CMAKE_CURRENT_BINARY_DIR}/grammar.c + ${CMAKE_CURRENT_BINARY_DIR}/scanner.c + ${PROJECT_EXTERNAL_OBJECT_LIST} + ) + target_include_directories(${LIBRARY_NAME} PUBLIC + $ + $ + ) + add_dependencies(${LIBRARY_NAME} SerializeTarget) + set_target_properties(${LIBRARY_NAME} PROPERTIES + COMPILE_DEFINITIONS BUILDING_PCAP) + # + # No matter what the library is called - it might be called "wpcap" + # in a Windows build - the symbol to define to indicate that we're + # building the library, rather than a program using the library, + # and thus that we're exporting functions defined in our public + # header files, rather than importing those functions, is + # pcap_EXPORTS. + # + set_target_properties(${LIBRARY_NAME} PROPERTIES + DEFINE_SYMBOL pcap_EXPORTS) + if(NOT "${LINKER_FLAGS}" STREQUAL "") + set_target_properties(${LIBRARY_NAME} PROPERTIES + LINK_FLAGS "${LINKER_FLAGS}") + endif() +endif(BUILD_SHARED_LIBS) + +add_library(${LIBRARY_NAME}_static STATIC + ${PROJECT_SOURCE_LIST_C} + ${CMAKE_CURRENT_BINARY_DIR}/grammar.c + ${CMAKE_CURRENT_BINARY_DIR}/scanner.c + ${PROJECT_EXTERNAL_OBJECT_LIST} +) +target_include_directories(${LIBRARY_NAME}_static PUBLIC + $ + $ +) +add_dependencies(${LIBRARY_NAME}_static SerializeTarget) +set_target_properties(${LIBRARY_NAME}_static PROPERTIES + COMPILE_DEFINITIONS BUILDING_PCAP) + +if(WIN32) + if(BUILD_SHARED_LIBS) + set_target_properties(${LIBRARY_NAME} PROPERTIES + VERSION ${PACKAGE_VERSION_NOSUFFIX} # only MAJOR and MINOR are needed + ) + endif(BUILD_SHARED_LIBS) + if(MSVC) + # XXX For DLLs, the TARGET_PDB_FILE generator expression can be used to locate + # its PDB file's output directory for installation. + # cmake doesn't offer a generator expression for PDB files generated by the + # compiler (static libraries). + # So instead of considering any possible output there is (there are many), + # this will search for the PDB file in the compiler's initial output directory, + # which is always ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles\wpcap_static.dir + # regardless of architecture, build generator etc. + # Quite hackish indeed. + set(CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY $) + set_target_properties(${LIBRARY_NAME}_static PROPERTIES + COMPILE_PDB_NAME ${LIBRARY_NAME}_static + OUTPUT_NAME "${LIBRARY_NAME}_static" + ) + elseif(MINGW) + # + # For compatibility, build the shared library without the "lib" prefix on + # MinGW as well. + # + set_target_properties(${LIBRARY_NAME} PROPERTIES + PREFIX "" + OUTPUT_NAME "${LIBRARY_NAME}" + ) + set_target_properties(${LIBRARY_NAME}_static PROPERTIES + OUTPUT_NAME "${LIBRARY_NAME}" + ) + endif() +else(WIN32) # UN*X + if(BUILD_SHARED_LIBS) + if(APPLE) + set_target_properties(${LIBRARY_NAME} PROPERTIES + VERSION ${PACKAGE_VERSION} + SOVERSION A + ) + else(APPLE) + set_target_properties(${LIBRARY_NAME} PROPERTIES + VERSION ${PACKAGE_VERSION} + SOVERSION ${PACKAGE_VERSION_MAJOR} + ) + endif(APPLE) + endif(BUILD_SHARED_LIBS) + set_target_properties(${LIBRARY_NAME}_static PROPERTIES + OUTPUT_NAME "${LIBRARY_NAME}" + ) +endif(WIN32) + +if(BUILD_SHARED_LIBS) + if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(${LIBRARY_NAME} PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) + endif() + + # + # If this is macOS and we've picked the default architectures on + # which to build, build the library on them. + # + if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + set_target_properties(${LIBRARY_NAME} PROPERTIES + OSX_ARCHITECTURES "${OSX_LIBRARY_ARCHITECTURES}") + endif() + target_link_libraries(${LIBRARY_NAME} ${PCAP_LINK_LIBRARIES}) +endif(BUILD_SHARED_LIBS) + +if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(${LIBRARY_NAME}_static PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) +endif() + +# +# If this is macOS and we've picked the default architectures on +# which to build, build the library on them. +# +if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + set_target_properties(${LIBRARY_NAME}_static PROPERTIES + OSX_ARCHITECTURES "${OSX_LIBRARY_ARCHITECTURES}") +endif() + +###################################### +# Write out the config.h file +###################################### + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmakeconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +###################################### +# Write out the grammar.y file +###################################### + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/grammar.y.in ${CMAKE_CURRENT_BINARY_DIR}/grammar.y @ONLY) + +###################################### +# Install pcap library, include files, and man pages +###################################### + +# +# "Define GNU standard installation directories", which actually +# are also defined, to some degree, by autotools, and at least +# some of which are general UN*X conventions. +# +include(GNUInstallDirs) + +set(LIBRARY_NAME_STATIC ${LIBRARY_NAME}_static) + +function(install_manpage_symlink SOURCE TARGET MANDIR) + if(MINGW) + # + # If we haven't found an ln executable with MinGW, we don't try + # generating and installing the man pages, so if we get here, + # we've found that executable. + set(LINK_COMMAND "\"${LINK_EXECUTABLE}\" \"-s\" \"${SOURCE}\" \"${TARGET}\"") + else(MINGW) + set(LINK_COMMAND "\"${CMAKE_COMMAND}\" \"-E\" \"create_symlink\" \"${SOURCE}\" \"${TARGET}\"") + endif(MINGW) + + install(CODE " + if(NOT ${CMAKE_INSTALL_MESSAGE} STREQUAL \"NEVER\") + message(STATUS \"Symlinking: \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MANDIR}/${SOURCE} to ${TARGET}\") + endif() + execute_process( + COMMAND \"${CMAKE_COMMAND}\" \"-E\" \"remove\" \"${TARGET}\" + WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MANDIR} + ) + execute_process( + COMMAND ${LINK_COMMAND} + WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${MANDIR} + RESULT_VARIABLE EXIT_STATUS + ) + if(NOT EXIT_STATUS EQUAL 0) + message(FATAL_ERROR \"Could not create symbolic link from \${CMAKE_INSTALL_PREFIX}/${MANDIR}/${SOURCE} to ${TARGET}\") + endif() + set(CMAKE_INSTALL_MANIFEST_FILES \${CMAKE_INSTALL_MANIFEST_FILES} \${CMAKE_INSTALL_PREFIX}/${MANDIR}/${TARGET})") +endfunction(install_manpage_symlink) + +set(MAN1_NOEXPAND pcap-config.1) +set(MAN3PCAP_EXPAND + pcap.3pcap.in + pcap_compile.3pcap.in + pcap_datalink.3pcap.in + pcap_dump_open.3pcap.in + pcap_get_tstamp_precision.3pcap.in + pcap_list_datalinks.3pcap.in + pcap_list_tstamp_types.3pcap.in + pcap_open_dead.3pcap.in + pcap_open_offline.3pcap.in + pcap_set_immediate_mode.3pcap.in + pcap_set_tstamp_precision.3pcap.in + pcap_set_tstamp_type.3pcap.in +) +set(MAN3PCAP_NOEXPAND + pcap_activate.3pcap + pcap_breakloop.3pcap + pcap_can_set_rfmon.3pcap + pcap_close.3pcap + pcap_create.3pcap + pcap_datalink_name_to_val.3pcap + pcap_datalink_val_to_name.3pcap + pcap_dump.3pcap + pcap_dump_close.3pcap + pcap_dump_file.3pcap + pcap_dump_flush.3pcap + pcap_dump_ftell.3pcap + pcap_file.3pcap + pcap_fileno.3pcap + pcap_findalldevs.3pcap + pcap_freecode.3pcap + pcap_get_required_select_timeout.3pcap + pcap_get_selectable_fd.3pcap + pcap_geterr.3pcap + pcap_init.3pcap + pcap_inject.3pcap + pcap_is_swapped.3pcap + pcap_lib_version.3pcap + pcap_lookupdev.3pcap + pcap_lookupnet.3pcap + pcap_loop.3pcap + pcap_major_version.3pcap + pcap_next_ex.3pcap + pcap_offline_filter.3pcap + pcap_open_live.3pcap + pcap_set_buffer_size.3pcap + pcap_set_datalink.3pcap + pcap_set_promisc.3pcap + pcap_set_protocol_linux.3pcap + pcap_set_rfmon.3pcap + pcap_set_snaplen.3pcap + pcap_set_timeout.3pcap + pcap_setdirection.3pcap + pcap_setfilter.3pcap + pcap_setnonblock.3pcap + pcap_snapshot.3pcap + pcap_stats.3pcap + pcap_statustostr.3pcap + pcap_strerror.3pcap + pcap_tstamp_type_name_to_val.3pcap + pcap_tstamp_type_val_to_name.3pcap +) +set(MANFILE_EXPAND + pcap-savefile.manfile.in +) +set(MANMISC_EXPAND + pcap-filter.manmisc.in + pcap-linktype.manmisc.in + pcap-tstamp.manmisc.in +) + +if(BUILD_SHARED_LIBS) + set(LIBRARIES_TO_INSTALL "${LIBRARY_NAME}" "${LIBRARY_NAME_STATIC}") +else(BUILD_SHARED_LIBS) + set(LIBRARIES_TO_INSTALL "${LIBRARY_NAME_STATIC}") +endif(BUILD_SHARED_LIBS) + +if(WIN32 OR CYGWIN OR MSYS) + # + # XXX - according to the CMake documentation, WIN32 is set if + # the target is Windows; would there ever be a case where + # CYGWIN or MSYS are set but WIN32 *isn't* set? + # + if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # Install 64-bit code built with MSVC in the x64 subdirectories, + # as that's where it expects it to be. + # + install(TARGETS ${LIBRARIES_TO_INSTALL} + RUNTIME DESTINATION bin/x64 + LIBRARY DESTINATION lib/x64 + ARCHIVE DESTINATION lib/x64) + if(NOT MINGW) + install(FILES $/${LIBRARY_NAME_STATIC}.pdb + DESTINATION bin/x64 OPTIONAL) + if(BUILD_SHARED_LIBS) + install(FILES $ + DESTINATION bin/x64 OPTIONAL) + endif(BUILD_SHARED_LIBS) + endif(NOT MINGW) + else(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # Install 32-bit code, and 64-bit code not built with MSVC + # in the top-level directories, as those are where they + # expect it to be. + # + install(TARGETS ${LIBRARIES_TO_INSTALL} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + if(MSVC) + install(FILES $/${LIBRARY_NAME_STATIC}.pdb + DESTINATION bin OPTIONAL) + if(BUILD_SHARED_LIBS) + install(FILES $ + DESTINATION bin OPTIONAL) + endif(BUILD_SHARED_LIBS) + endif(MSVC) + endif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) +else(WIN32 OR CYGWIN OR MSYS) + install(TARGETS ${LIBRARIES_TO_INSTALL} DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif(WIN32 OR CYGWIN OR MSYS) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pcap/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/pcap) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap-bpf.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/pcap-namedb.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# On UN*X, and on Windows when not using MSVC, generate libpcap.pc and +# pcap-config and process man pages and arrange that they be installed. +if(NOT MSVC) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix "\${prefix}") + set(includedir "\${prefix}/include") + set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") + + # + # If this is a platform where we need to have the .pc file and + # pcap-config script supply an rpath option to specify the directory + # in which the libpcap shared library is installed, and the install + # prefix /usr (meaning we're not installing a system library), + # provide the rpath option. + # + # (We must check CMAKE_INSTALL_PREFIX, as the library directory + # isn't necessarily /usr/lib in this case - for example, Linux + # distributions for 64-bit platforms that also provide support for + # binaries for a 32-bit version of the platform may put the 64-bit + # libraries, the 32-bit libraries, or both in directories other than + # /usr/lib.) + # + # In AIX, do we have to do this? + # + # In Darwin-based OSes, the full paths of the shared libraries with + # which the program was linked are stored in the executable, so we + # don't need to provide an rpath option. + # + # With the HP-UX linker, directories specified with -L are, by + # default, added to the run-time search path, so we don't need to + # supply them. + # + # For Tru64 UNIX, "-rpath" works with DEC's^WCompaq's^WHP's C + # compiler for Alpha, but isn't documented as working with GCC, and + # no GCC-compatible option is documented as working with the DEC + # compiler. If anybody needs this on Tru64/Alpha, they're welcome + # to figure out a way to make it work. + # + # This must *not* depend on the compiler, as, on platforms where + # there's a GCC-compatible compiler and a vendor compiler, we need + # to work with both. + # + if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr") + if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "DragonFly BSD" OR + CMAKE_SYSTEM_NAME STREQUAL "Linux") + # + # Platforms where the "native" C compiler is GCC or accepts + # compatible command-line arguments, and the "native" linker + # is the GNU linker or accepts compatible command-line + # arguments. + # + set(RPATH "-Wl,-rpath,\${libdir}") + elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION MATCHES "5[.][0-9.]*") + # + # SunOS 5.x. + # + # Sun/Oracle's linker, the GNU linker, and GNU-compatible + # linkers all support -R. + # + set(RPATH "-Wl,-R,\${libdir}") + else() + # + # No option needed to set the RPATH. + # + set(RPATH "") + endif() + endif() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pcap-config.in ${CMAKE_CURRENT_BINARY_DIR}/pcap-config @ONLY) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpcap.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libpcap.pc @ONLY) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/pcap-config DESTINATION bin) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpcap.pc DESTINATION lib/pkgconfig) + + # + # Man pages. + # + # For each section of the manual for which we have man pages + # that require macro expansion, do the expansion. + # + # If this is MinGW, maybe we have a UN*X-style ln command and + # maybe we don't. (No, we do *NOT* require MSYS!) If we don't + # have it, don't do the man pages. + # + if(MINGW) + find_program(LINK_EXECUTABLE ln) + endif(MINGW) + if(UNIX OR (MINGW AND LINK_EXECUTABLE)) + set(MAN1 "") + foreach(MANPAGE ${MAN1_NOEXPAND}) + set(MAN1 ${MAN1} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE}) + endforeach(MANPAGE) + install(FILES ${MAN1} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + + set(MAN3PCAP "") + foreach(MANPAGE ${MAN3PCAP_NOEXPAND}) + set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_SOURCE_DIR}/${MANPAGE}) + endforeach(MANPAGE) + foreach(TEMPLATE_MANPAGE ${MAN3PCAP_EXPAND}) + string(REPLACE ".in" "" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MAN3PCAP ${MAN3PCAP} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MAN3PCAP} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_datalink_val_to_name.3pcap pcap_datalink_val_to_description_or_dlt.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_dump_open.3pcap pcap_dump_fopen.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_findalldevs.3pcap pcap_freealldevs.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_geterr.3pcap pcap_perror.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_inject.3pcap pcap_sendpacket.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_loop.3pcap pcap_dispatch.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_major_version.3pcap pcap_minor_version.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_next_ex.3pcap pcap_next.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_open_dead.3pcap pcap_open_dead_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + install_manpage_symlink(pcap_setnonblock.3pcap pcap_getnonblock.3pcap ${CMAKE_INSTALL_MANDIR}/man3) + + set(MANFILE "") + foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND}) + string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS}) + + set(MANMISC "") + foreach(TEMPLATE_MANPAGE ${MANMISC_EXPAND}) + string(REPLACE ".manmisc.in" ".${MAN_MISC_INFO}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANMISC ${MANMISC} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANMISC} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_MISC_INFO}) + endif(UNIX OR (MINGW AND LINK_EXECUTABLE)) +endif(NOT MSVC) + +# uninstall target +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) diff --git a/src/libpcap-1.10.5/CONTRIBUTING.md b/src/libpcap-1.10.5/CONTRIBUTING.md new file mode 100644 index 0000000000..fb22c5e381 --- /dev/null +++ b/src/libpcap-1.10.5/CONTRIBUTING.md @@ -0,0 +1,29 @@ +Guidelines for contributing +=========================== + +To report a security issue (segfault, buffer overflow, infinite loop, arbitrary +code execution etc) please send an e-mail to security@tcpdump.org, do not use +the bug tracker! + +To report a non-security problem (failure to compile, failure to capture packets +properly, missing support for a network interface type or DLT) please check +first that it reproduces with the latest stable release of libpcap. If it does, +please check that the problem reproduces with the current git master branch of +libpcap. If it does (and it is not a security-related problem, otherwise see +above), please navigate to https://github.com/the-tcpdump-group/libpcap/issues +and check if the problem has already been reported. If it has not, please open +a new issue and provide the following details: + +* libpcap version (e.g. from `tcpdump --version`) +* operating system name and version and any other details that may be relevant + (`uname -a`, compiler name and version, CPU type etc.) +* `configure` or `cmake` flags if any were used +* statement of the problem +* steps to reproduce + +Please note that if you know exactly how to solve the problem and the solution +would not be too intrusive, it would be best to contribute some development time +and open a pull request instead. + +Still not sure how to do? Feel free to [subscribe](https://www.tcpdump.org/#mailing-lists) +to the mailing list tcpdump-workers@lists.tcpdump.org and ask! diff --git a/src/libpcap-1.10.5/CREDITS b/src/libpcap-1.10.5/CREDITS new file mode 100644 index 0000000000..78ce6a102c --- /dev/null +++ b/src/libpcap-1.10.5/CREDITS @@ -0,0 +1,280 @@ +This file lists people who have contributed to libpcap. + +The current maintainers (in alphabetical order): + Denis Ovsienko + Francois-Xavier Le Bail + Guy Harris + Michael Richardson + +Additional people who have contributed patches (in alphabetical order): + Adrian Budau + Akos Vandra + Alan Bawden + Albert Chin + Alexander Galanin + Alexander 'Leo' Bergolth + Alexey Kuznetsov + Alex Smith <44322503+MadAlexUK at users dot noreply dot github dot com> + Alfredo Alvarez Fernandez + Ali Abdulkadir + Alois Klink + Alon Bar-Lev + Anders Broman + Andres Perera + Andrew Brown + + Ani Sinha + Anthony Kirby + Antonio Vázquez Blanco + Antti Kantee + Archit Shah + Arien Vijn + Arkadiusz Miskiewicz + Armando L. Caro Jr. + Assar Westerlund + Atzm Watanabe + Baptiste Peugnez + Baruch Siach + Bill Parker + Biswapriyo Nath + blazeable + bleader + Brent Cook + Brian Ginsbach + B. Scott Michel + Cedric Cellier + Charles M. Hannum + Chris G. Demetriou + Chris Lightfoot + Chris Maynard + Chris Pepper + Christian Bell + Christian Peron + Christian Svensson + Christopher K Lee + Clément Péron + Daniel Borkmann + Daniele Orlandi + Daniel Lublin + Daniel Miller + Dario Lombardo + Darren Lim + Darren Reed + Dave Barach + David Clark + David Kaelbling + David Karoly + David Ward + David Young + Dean Gaudet + dhruv + Dmytro Ovdiienko + Don Ebright + Dug Song + Dustin Spicuzza + dzejarczech + Ed Maste + Edward Sheldrake + Eli Schwartz + Eric Anderson + Erik de Castro Lopo + Fedor Sakharov + Felix Janda + Felix Obenhuber + fghzxm + Florent Drouin + Florian Fainelli + François Revol + Franz Schaefer + frederich + Fulko Hew + Fumiyuki Shimizu + Gabor Tatarka + Gabriel Ganne + Garrett Cooper + George Neville-Neil + Gerald Combs + Gerard Garcia + Gianluca Varenni + Gilbert Hoyek + Gisle Vanem + Graeme Hewson + Gregor Maier + Greg Stark + Greg Troxel + Guillaume Pelat + Gustavo Zacarias + Hagen Paul Pfeifer + headshog + Henri Doreau + Hiroaki KAWAI + hopper-vul + Hyung Sik Yoon + Igor Khristophorov + Jakub Sitnicki + Jakub Zawadzki + James Ko + Jan-Philip Velders + Jason R. Thorpe + Javier Achirica + Jean-Louis Charton + Jean Tourrilhes + Jefferson Ogata + Jerome Duval + Jesper Dangaard Brouer + Jesper Peterson + Jesse Gross + JHA + jingyu yang + Jiri Slaby + João Valverde + Joel <82591719+joelg989 at users dot noreply dot github dot com> + Joerg Mayer + John Bankier + Jon Lindgren + Jon Smirl + Jorge Boncompte [DTI2] + Josh Soref <2119212+jsoref at users dot noreply dot github dot com> + jromanr + Juergen Schoenwaelder + Julien Moutinho + Jung-uk Kim + Kazushi Sugyo + Kenny Luong + Kevin Boulain + Klaus Klein + Koryn Grant + Kris Katterjohn + Krzysztof Halasa + Lennert Buytenhek + Li kunyu + lixiaoyan + Lorenzo Cavallaro + Loris Degioanni + Love Hörnquist-Åstrand + Lubomir Varga + Luis MartinGarcia + lxy <391861737 at qq dot com> + Maciej W. Rozycki + Mansour Behabadi + Marcus Felipe Pereira + Mario J. Rugiero + Mark C. Brown + Mark Johnston + Mark Marshall + Mark Pizzolato + Markus Mayer + Martin Husemann + Márton Németh + Matias Karhumaa + Matt Eaton + Matthew Luckie + Matthias Hannig + Matwey V. Kornilov + maxice8 + Max Laier + Michal Kubecek + Michal Labedzki + Michal Ruprich + Michal Sekletar + Mike Frysinger + Mike Kershaw + Mike Wiacek + Milosz Kaniewski + Miroslav Lichvar + Monroe Williams + Myricom Help + Nan Xiao + nic-kaczinsky <68271784+nic-kaczinsky at users dot noreply dot github dot com> + Nick Kelsey + Nicolas Badoux + Nicolas Dade + Niko Delarich + Nikolay Edigaryev + N. Leiten + nnposter + + Octavian Cerna + Olaf Kirch + Ollie Wild + Ondřej Hošek + Onno van der Linden + Orgad Shaneh + Ørjan Malde + Paolo Abeni + Patrick Marie + Patrick McHardy + Paul Mundt + Pavel Kankovsky + Pawel Brzezinski + Pawel Pokrywka + Peter Fales + Peter Jeremy + Peter Volkov + Petr Vorel + Philippe Antoine + Phil Wood + Rafal Maszkowski + ramin + + Richard Stearn + Rick Jones + Robert Edmonds + Roberto Mariani + Roland Dreier + Romain Francoise + Rongxi Li + Rose <83477269+AtariDreams at users dot noreply dot github dot com> + Sagun Shakya + Scott Barron + Scott Gifford + Scott Mcmillan + Sebastian Krahmer + Sebastien Roy + Sepherosa Ziehau + Shane Kerr + Shaun Clowes + Shunyang Zhang + solofox + Solomon Peachy + Stefan Hudson + Stephen Donnelly + Steve Karg + stubbfel + Takashi Yamamoto + Tanaka Shin-ya + Thomas Habets + Thomas Petazzoni + Tobias Poschwatta + Tomasz Moń + Tommy Beadle + Tony Li + Torsten Landschoff + Tymoteusz Blazejczyk + Uns Lider + Uwe Girlich + Vitaly Lavrov + Vivien Didelot + Vladimir Gladkov + Vladimir Marek + Walter Schell + Wesley Shields + Xianjie Zhang + Xin Li + Xue Jiang Qing + Yang Luo + Yen Yen Lim + Yoann Vandoorselaere + Yogesh Prasad + Yvan Vanhullebus + +The original LBL crew: + Steve McCanne + Craig Leres + Van Jacobson + +Past maintainers (in alphabetical order): + Bill Fenner + Fulvio Risso + Hannes Gredler + Jun-ichiro itojun Hagino Also see: http://www.wide.ad.jp/itojun-award/ diff --git a/src/libpcap-1.10.5/ChmodBPF/ChmodBPF b/src/libpcap-1.10.5/ChmodBPF/ChmodBPF new file mode 100755 index 0000000000..ee37121845 --- /dev/null +++ b/src/libpcap-1.10.5/ChmodBPF/ChmodBPF @@ -0,0 +1,33 @@ +#! /bin/sh + +. /etc/rc.common + +StartService () +{ + # + # Unfortunately, Mac OS X's devfs is based on the old FreeBSD + # one, not the current one, so there's no way to configure it + # to create BPF devices with particular owners or groups. + # This startup item will make it owned by the admin group, + # with permissions rw-rw----, so that anybody in the admin + # group can use programs that capture or send raw packets. + # + # Change this as appropriate for your site, e.g. to make + # it owned by a particular user without changing the permissions, + # so only that user and the super-user can capture or send raw + # packets, or give it the permissions rw-r-----, so that + # only the super-user can send raw packets but anybody in the + # admin group can capture packets. + # + chgrp admin /dev/bpf* + chmod g+rw /dev/bpf* +} + +StopService () +{ + return 0; +} + +RestartService () { StartService; } + +RunService "$1" diff --git a/src/libpcap-1.10.5/ChmodBPF/StartupParameters.plist b/src/libpcap-1.10.5/ChmodBPF/StartupParameters.plist new file mode 100644 index 0000000000..cba21664fe --- /dev/null +++ b/src/libpcap-1.10.5/ChmodBPF/StartupParameters.plist @@ -0,0 +1,4 @@ +{ + Description = "Change BPF permissions"; + Provides = ("ChmodBPF"); +} diff --git a/src/libpcap-1.10.5/INSTALL.md b/src/libpcap-1.10.5/INSTALL.md new file mode 100644 index 0000000000..2787580767 --- /dev/null +++ b/src/libpcap-1.10.5/INSTALL.md @@ -0,0 +1,349 @@ +# libpcap installation notes +Libpcap can be built either with the configure script and `make`, or +with CMake and any build system supported by CMake. + +To build libpcap with the configure script and `make`: + +* If you build from a git clone rather than from a release archive, +run `./autogen.sh` (a shell script). The autogen.sh script will +build the `configure` and `config.h.in` files. + +On some system, you may need to set the `AUTORECONF` variable, like: +`AUTORECONF=autoreconf-2.69 ./autogen.sh` +to select the `autoreconf` version you want to use. + +* Run `./configure` (a shell script). The configure script will +determine your system attributes and generate an appropriate `Makefile` +from `Makefile.in`. The configure script has a number of options to +control the configuration of libpcap; `./configure --help` will show +them. + +* Next, run `make`. If everything goes well, you can +`su` to root and run `make install`. However, you need not install +libpcap if you just want to build tcpdump; just make sure the tcpdump +and libpcap directory trees have the same parent directory. + +On OpenBSD, you may need to set, before the `make`, the `AUTOCONF_VERSION` +variable like: +`AUTOCONF_VERSION=2.69 make` + +To build libpcap with CMake and the build system of your choice, from +the command line: + +* Create a build directory into which CMake will put the build files it +generates; CMake does not work as well with builds done in the source +code directory as does the configure script. The build directory may be +created as a subdirectory of the source directory or as a directory +outside the source directory. + +* Change to the build directory and run CMake with the path from the +build directory to the source directory as an argument. The `-G` flag +can be used to select the CMake "generator" appropriate for the build +system you're using; various `-D` flags can be used to control the +configuration of libpcap. + +* Run the build tool. If everything goes well, you can `su` to root and +run the build tool with the `install` target. Building tcpdump from a +libpcap in a build directory is not supported. + +An `uninstall` target is supported with both `./configure` and CMake. + +***DO NOT*** run the build as root; there is no need to do so, running +anything as root that doesn't need to be run as root increases the risk +of damaging your system, and running the build as root will put files in +the build directory that are owned by root and that probably cannot be +overwritten, removed, or replaced except by root, which could cause +permission errors in subsequent builds. + +If configure says: + + configure: warning: cannot determine packet capture interface + configure: warning: (see INSTALL.md file for more info) + +or CMake says: + + cannot determine packet capture interface + + (see the INSTALL.md file for more info) + +then your system either does not support packet capture or your system +does support packet capture but libpcap does not support that +particular type. (If you have HP-UX, see below.) If your system uses a +packet capture not supported by libpcap, please send us patches; don't +forget to include an autoconf fragment suitable for use in +`configure.ac`. + +It is possible to override the default packet capture type with the +`--with-pcap` option to `./configure` or the `-DPCAP_TYPE` option to +CMake, although the circumstances where this works are limited. One +possible reason to do that would be to force a supported packet capture +type in the case where the configure or CMake scripts fails to detect +it. + +You will need a C99 compiler to build libpcap. The configure script +will abort if your compiler is not C99 compliant. If this happens, use +the generally available GNU C compiler (GCC) or Clang. + +You will need either Flex 2.5.31 or later, or a version of Lex +compatible with it (if any exist), to build libpcap. The configure +script will abort if there isn't any such program; CMake fails if Flex +or Lex cannot be found, but doesn't ensure that it's compatible with +Flex 2.5.31 or later. If you have an older version of Flex, or don't +have a compatible version of Lex, the current version of Flex is +available [here](https://github.com/westes/flex). + +You will need either Bison, Berkeley YACC, or a version of YACC +compatible with them (if any exist), to build libpcap. The configure +script will abort if there isn't any such program; CMake fails if Bison +or some form of YACC cannot be found, but doesn't ensure that it's +compatible with Bison or Berkeley YACC. If you don't have any such +program, the current version of Bison can be found +[here](https://ftp.gnu.org/gnu/bison/) and the current version of +Berkeley YACC can be found [here](https://invisible-island.net/byacc/). + +Sometimes the stock C compiler does not interact well with Flex and +Bison. The list of problems includes undefined references for alloca(3). +You can get around this by installing GCC. + +## Linux specifics +On Linux, libpcap will not work if the kernel does not have the packet +socket option enabled; see [this file](doc/README.linux) for more +information. + +## Solaris specifics +If you use the SPARCompiler, you must be careful to not use the +`/usr/ucb/cc` interface. If you do, you will get bogus warnings and +perhaps errors. Either make sure your path has `/opt/SUNWspro/bin` +before `/usr/ucb` or else: + + setenv CC /opt/SUNWspro/bin/cc + +before running configure. (You might have to do a `make distclean` +if you already ran `configure` once). + +See [this file](doc/README.solaris.md) for more up to date +Solaris-related information. + +## HP-UX specifics +If you use HP-UX, you must have at least version 9 and either the +version of `cc` that supports C99 (`cc -AC99`) or else use the GNU C +compiler. You must also buy the optional streams package. If you don't +have: + + /usr/include/sys/dlpi.h + /usr/include/sys/dlpi_ext.h + +then you don't have the streams package. In addition, we believe you +need to install the "9.X LAN and DLPI drivers cumulative" patch +(PHNE_6855) to make the version 9 DLPI work with libpcap. + +The DLPI streams package is standard starting with HP-UX 10. + +The HP implementation of DLPI is a little bit eccentric. Unlike +Solaris, you must attach `/dev/dlpi` instead of the specific `/dev/*` +network pseudo device entry in order to capture packets. The PPA is +based on the ifnet "index" number. Under HP-UX 9, it is necessary to +read `/dev/kmem` and the kernel symbol file (`/hp-ux`). Under HP-UX 10, +DLPI can provide information for determining the PPA. It does not seem +to be possible to trace the loopback interface. Unlike other DLPI +implementations, PHYS implies MULTI and SAP and you get an error if you +try to enable more than one promiscuous mode at a time. + +It is impossible to capture outbound packets on HP-UX 9. To do so on +HP-UX 10, you will, apparently, need a late "LAN products cumulative +patch" (at one point, it was claimed that this would be PHNE_18173 for +s700/10.20; at another point, it was claimed that the required patches +were PHNE_20892, PHNE_20725 and PHCO_10947, or newer patches), and to do +so on HP-UX 11 you will, apparently, need the latest lancommon/DLPI +patches and the latest driver patch for the interface(s) in use on HP-UX +11 (at one point, it was claimed that patches PHNE_19766, PHNE_19826, +PHNE_20008, and PHNE_20735 did the trick). + +Furthermore, on HP-UX 10, you will need to turn on a kernel switch by +doing + + echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem + +You would have to arrange that this happens on reboots; the right way to +do that would probably be to put it into an executable script file +`/sbin/init.d/outbound_promisc` and making +`/sbin/rc2.d/S350outbound_promisc` a symbolic link to that script. + +Finally, testing shows that there can't be more than one simultaneous +DLPI user per network interface. + +See [this file](doc/README.hpux) for more information specific to HP-UX. + +## AIX specifics +See [this file](doc/README.aix) for information on installing libpcap and +configuring your system to be able to support libpcap. + +## other specifics +If you are trying to do packet capture with a FORE ATM card, you may or +may not be able to. They usually only release their driver in object +code so unless their driver supports packet capture, there's not much +libpcap can do. + +If you get an error like: + + tcpdump: recv_ack: bind error 0x??? + +when using DLPI, look for the DL_ERROR_ACK error return values, usually +in `/usr/include/sys/dlpi.h`, and find the corresponding value. + +## Description of files + CHANGES - description of differences between releases + ChmodBPF/* - macOS startup item to set ownership and permissions on /dev/bpf* + CMakeLists.txt - CMake file + CONTRIBUTING.md - guidelines for contributing + CREDITS - people that have helped libpcap along + INSTALL.md - this file + LICENSE - the license under which libpcap is distributed + Makefile.in - compilation rules (input to the configure script) + README.md - description of distribution + doc/README.aix - notes on using libpcap on AIX + doc/README.dag - notes on using libpcap to capture on Endace DAG devices + doc/README.haiku.md - notes on using libpcap on Haiku + doc/README.hpux - notes on using libpcap on HP-UX + doc/README.linux - notes on using libpcap on Linux + doc/README.macos - notes on using libpcap on macOS + doc/README.septel - notes on using libpcap to capture on Intel/Septel devices + doc/README.sita - notes on using libpcap to capture on SITA devices + doc/README.solaris.md - notes on using libpcap on Solaris + doc/README.windows.md - notes on using libpcap on Windows systems (with Npcap) + VERSION - version of this release + aclocal.m4 - autoconf macros + arcnet.h - ARCNET definitions + atmuni31.h - ATM Q.2931 definitions + autogen.sh - build configure and config.h.in (run this first) + bpf_dump.c - BPF program printing routines + bpf_filter.c - BPF filtering routines + bpf_image.c - BPF disassembly routine + charconv.c - Windows Unicode routines + charconv.h - Windows Unicode prototypes + config.guess - autoconf support + config.sub - autoconf support + configure.ac - configure script source + diag-control.h - compiler diagnostics control macros + dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c + dlpisubs.h - DLPI-related function declarations + etherent.c - /etc/ethers support routines + extract.h - Alignment definitions + ethertype.h - Ethernet protocol types and names definitions + fad-getad.c - pcap_findalldevs() for systems with getifaddrs() + fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST + fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF + fmtutils.c - error message formatting routines + fmtutils.h - error message formatting prototypes + ftmacros.h - feature test macros + testprogs/filtertest.c - test program for BPF compiler + testprogs/findalldevstest.c - test program for pcap_findalldevs() + gencode.c - BPF code generation routines + gencode.h - BPF code generation definitions + grammar.y - filter string grammar + ieee80211.h - 802.11 definitions + install-sh - BSD style install script + instrument-functions.c - functions instrumentation calls for entry/exit + lbl/os-*.h - OS-dependent defines and prototypes + llc.h - 802.2 LLC SAP definitions + missing/* - replacements for missing library functions + mkdep - construct Makefile dependency list + msdos/* - drivers for MS-DOS capture support + nametoaddr.c - hostname to address routines + nametoaddr.h - hostname to address prototypes + nlpid.h - OSI network layer protocol identifier definitions + optimize.c - BPF optimization routines + optimize.h - BPF optimization prototypes + pcap/bluetooth.h - public definition of DLT_BLUETOOTH_HCI_H4_WITH_PHDR header + pcap/bpf.h - BPF definitions + pcap/can_socketcan.h - SocketCAN header + pcap/compiler-tests.h - compiler version comparison and other macros + pcap/dlt.h - Link-layer header type codes. + pcap/funcattrs.h - function attribute macros + pcap/ipnet.h - Solaris IPnet definitions + pcap/namedb.h - public libpcap name database definitions + pcap/nflog.h - NFLOG-related definitions + pcap/pcap.h - public libpcap definitions + pcap/pcap-inttypes.h - header for OS-specific integer type includes + pcap/sll.h - public definitions of DLT_LINUX_SLL and DLT_LINUX_SLL2 headers + pcap/socket.h - IP sockets support for various OSes + pcap/usb.h - public definition of DLT_USB header + pcap/vlan.h - VLAN-specific definitions + pcap-airpcap.c - AirPcap device capture support + pcap-airpcap.h - AirPcap device capture support + pcap-bpf.c - BSD Packet Filter support + pcap-bpf.h - header for backwards compatibility + pcap-bt-linux.c - Bluetooth capture support for Linux + pcap-bt-linux.h - Bluetooth capture support for Linux + pcap-bt-monitor-linux.c - Bluetooth monitor capture support for Linux + pcap-bt-monitor-linux.h - Bluetooth monitor capture support for Linux + pcap-common.c - common code for pcap and pcapng files + pcap-common.h - common code for pcap and pcapng files + pcap-dag.c - Endace DAG device capture support + pcap-dag.h - Endace DAG device capture support + pcap-dbus.c - D-Bus capture support + pcap-dbus.h - D-Bus capture support + pcap-dlpi.c - Data Link Provider Interface support + pcap-dos.c - MS-DOS capture support + pcap-dos.h - headers for MS-DOS capture support + pcap-dpdk.c - DPDK device support + pcap-dpdk.h - DPDK device support + pcap-enet.c - enet support + pcap-haiku.c - Haiku capture support + pcap-int.h - internal libpcap definitions + pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi + pcap-linux.c - Linux packet socket support + pcap-namedb.h - header for backwards compatibility + pcap-netfilter-linux.c - Linux netfilter support + pcap-netfilter-linux.h - Linux netfilter support + pcap-netmap.c - netmap support + pcap-netmap.h - netmap support + pcap-nit.c - SunOS Network Interface Tap support + pcap-npf.c - Npcap capture support + pcap-null.c - dummy monitor support (allows offline use of libpcap) + pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support + pcap-rdmasniff.c - RDMA/InfiniBand capture support + pcap-rdmasniff.h - RDMA/InfiniBand capture support + pcap-rpcap.c - RPCAP protocol capture support + pcap-rpcap.h - RPCAP protocol capture support + pcap-septel.c - Intel/Septel device capture support + pcap-septel.h - Intel/Septel device capture support + pcap-sita.c - SITA device capture support + pcap-sita.h - SITA device capture support + pcap-sita.html - SITA device capture documentation + pcap-snf.c - Myricom SNF device capture support + pcap-snf.h - Myricom SNF device capture support + pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support + pcap-snoop.c - IRIX Snoop network monitoring support + pcap-tc.c - TurboCap device capture support + pcap-tc.h - TurboCap device capture support + pcap-types.h - header for OS-specific type includes + pcap-usb-linux.c - USB capture support for Linux + pcap-usb-linux.h - USB capture support for Linux + pcap-usb-linux-common.c - Linux USB common routines + pcap-usb-linux-common.h - Linux USB common prototypes + pcap-util.c - common code for various files + pcap-util.h - common code for various files + pcap.3pcap - manual entry for the library + pcap.c - pcap utility routines + pcap.h - header for backwards compatibility + pcap_*.3pcap - manual entries for library functions + pcap-filter.manmisc.in - manual entry for filter syntax + pcap-linktype.manmisc.in - manual entry for link-layer header types + pflog.h - header for DLT_PFLOG handling in filter code + portability.h - Portability declarations/definitions + ppp.h - Point to Point Protocol definitions + rpcap-protocol.c - RPCAP client/server common routines + rpcap-protocol.h - RPCAP client/server common prototypes + savefile.c - offline support + scanner.l - filter string scanner + sf-pcap.c - routines for .pcap savefiles + sf-pcap.h - prototypes for .pcap savefiles + sf-pcapng.c - routines for .pcapng savefiles + sf-pcapng.h - prototypes for .pcapng savefiles + sockutils.c - socket and name lookup API routines + sockutils.h - socket and name lookup API prototypes + sslutils.c - OpenSSL interface routines + sslutils.h - OpenSSL interface prototypes + sunatmpos.h - definitions for SunATM capturing + varattrs.h - variable attribute macros diff --git a/src/libpcap-1.10.5/LICENSE b/src/libpcap-1.10.5/LICENSE new file mode 100644 index 0000000000..a10474d54a --- /dev/null +++ b/src/libpcap-1.10.5/LICENSE @@ -0,0 +1,19 @@ +License: BSD + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/src/libpcap-1.10.5/Makefile-devel-adds b/src/libpcap-1.10.5/Makefile-devel-adds new file mode 100644 index 0000000000..7cfd6c91d8 --- /dev/null +++ b/src/libpcap-1.10.5/Makefile-devel-adds @@ -0,0 +1,22 @@ +# +# Auto-regenerate configure script or Makefile when things change. +# From autoconf.info . Works best with GNU Make. +# +${srcdir}/configure: configure.ac aclocal.m4 + (cd ${srcdir} && autoconf) + +# autoheader might not change config.h.in, so touch a stamp file. +${srcdir}/config.h.in: ${srcdir}/stamp-h.in +${srcdir}/stamp-h.in: configure.ac aclocal.m4 + (cd ${srcdir} && autoheader) + echo timestamp > ${srcdir}/stamp-h.in + +config.h: stamp-h +stamp-h: ${srcdir}/config.h.in config.status + ./config.status + +Makefile: Makefile.in config.status + ./config.status + +config.status: ${srcdir}/configure + ./config.status --recheck diff --git a/src/libpcap-1.10.5/Makefile.in b/src/libpcap-1.10.5/Makefile.in new file mode 100644 index 0000000000..207ad8c0db --- /dev/null +++ b/src/libpcap-1.10.5/Makefile.in @@ -0,0 +1,933 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +SHLIB_CCOPT = @V_SHLIB_CCOPT@ +INCLS = -I. @V_INCLS@ +DEFS = -DBUILDING_PCAP -Dpcap_EXPORTS @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +RPATH = @RPATH@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +PROG=libpcap +PTHREAD_LIBS=@PTHREAD_LIBS@ +BUILD_RPCAPD=@BUILD_RPCAPD@ +INSTALL_RPCAPD=@INSTALL_RPCAPD@ + +# Standard CFLAGS for building members of a shared library +FULL_CFLAGS = $(CCOPT) @V_LIB_CCOPT_FAT@ $(SHLIB_CCOPT) $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +RANLIB = @RANLIB@ + +LEX = @LEX@ +BISON_BYACC = @BISON_BYACC@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +PLATFORM_C_SRC = @PLATFORM_C_SRC@ +MODULE_C_SRC = @MODULE_C_SRC@ +REMOTE_C_SRC = @REMOTE_C_SRC@ +COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \ + fmtutils.c pcap-util.c \ + savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \ + bpf_image.c bpf_filter.c bpf_dump.c +GENERATED_C_SRC = scanner.c grammar.c +LIBOBJS = @LIBOBJS@ + +SRC = $(PLATFORM_C_SRC) \ + $(MODULE_C_SRC) $(REMOTE_C_SRC) $(COMMON_C_SRC) \ + $(GENERATED_C_SRC) + +# We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot +# hack the extra indirection +OBJ = $(PLATFORM_C_SRC:.c=.o) \ + $(MODULE_C_SRC:.c=.o) $(REMOTE_C_SRC:.c=.o) $(COMMON_C_SRC:.c=.o) \ + $(GENERATED_C_SRC:.c=.o) \ + $(LIBOBJS) + +PUBHDR = \ + pcap.h \ + pcap-bpf.h \ + pcap-namedb.h \ + pcap/bluetooth.h \ + pcap/bpf.h \ + pcap/can_socketcan.h \ + pcap/compiler-tests.h \ + pcap/dlt.h \ + pcap/funcattrs.h \ + pcap/ipnet.h \ + pcap/namedb.h \ + pcap/nflog.h \ + pcap/pcap-inttypes.h \ + pcap/pcap.h \ + pcap/sll.h \ + pcap/socket.h \ + pcap/usb.h \ + pcap/vlan.h + +HDR = $(PUBHDR) \ + arcnet.h \ + atmuni31.h \ + diag-control.h \ + ethertype.h \ + extract.h \ + fmtutils.h \ + ftmacros.h \ + gencode.h \ + ieee80211.h \ + llc.h \ + nametoaddr.h \ + nlpid.h \ + optimize.h \ + pcap-common.h \ + pcap-int.h \ + pcap-rpcap.h \ + pcap-types.h \ + pcap-usb-linux-common.h \ + pcap-util.h \ + pflog.h \ + portability.h \ + ppp.h \ + rpcap-protocol.h \ + sf-pcap.h \ + sf-pcapng.h \ + sunatmpos.h \ + thread-local.h \ + varattrs.h + +GENHDR = \ + scanner.h grammar.h + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) libpcap.a libpcap.so.`cat $(srcdir)/VERSION` \ + $(PROG)-`cat $(srcdir)/VERSION`.tar.gz $(GENERATED_C_SRC) $(GENHDR) \ + lex.yy.c pcap-config libpcap.pc libpcap.$(DYEXT) + +MAN1 = pcap-config.1 + +MAN3PCAP_EXPAND = \ + pcap.3pcap.in \ + pcap_compile.3pcap.in \ + pcap_datalink.3pcap.in \ + pcap_dump_open.3pcap.in \ + pcap_get_tstamp_precision.3pcap.in \ + pcap_list_datalinks.3pcap.in \ + pcap_list_tstamp_types.3pcap.in \ + pcap_open_dead.3pcap.in \ + pcap_open_offline.3pcap.in \ + pcap_set_immediate_mode.3pcap.in \ + pcap_set_tstamp_precision.3pcap.in \ + pcap_set_tstamp_type.3pcap.in + +MAN3PCAP_NOEXPAND = \ + pcap_activate.3pcap \ + pcap_breakloop.3pcap \ + pcap_can_set_rfmon.3pcap \ + pcap_close.3pcap \ + pcap_create.3pcap \ + pcap_datalink_name_to_val.3pcap \ + pcap_datalink_val_to_name.3pcap \ + pcap_dump.3pcap \ + pcap_dump_close.3pcap \ + pcap_dump_file.3pcap \ + pcap_dump_flush.3pcap \ + pcap_dump_ftell.3pcap \ + pcap_file.3pcap \ + pcap_fileno.3pcap \ + pcap_findalldevs.3pcap \ + pcap_freecode.3pcap \ + pcap_get_required_select_timeout.3pcap \ + pcap_get_selectable_fd.3pcap \ + pcap_geterr.3pcap \ + pcap_init.3pcap \ + pcap_inject.3pcap \ + pcap_is_swapped.3pcap \ + pcap_lib_version.3pcap \ + pcap_lookupdev.3pcap \ + pcap_lookupnet.3pcap \ + pcap_loop.3pcap \ + pcap_major_version.3pcap \ + pcap_next_ex.3pcap \ + pcap_offline_filter.3pcap \ + pcap_open_live.3pcap \ + pcap_set_buffer_size.3pcap \ + pcap_set_datalink.3pcap \ + pcap_set_promisc.3pcap \ + pcap_set_protocol_linux.3pcap \ + pcap_set_rfmon.3pcap \ + pcap_set_snaplen.3pcap \ + pcap_set_timeout.3pcap \ + pcap_setdirection.3pcap \ + pcap_setfilter.3pcap \ + pcap_setnonblock.3pcap \ + pcap_snapshot.3pcap \ + pcap_stats.3pcap \ + pcap_statustostr.3pcap \ + pcap_strerror.3pcap \ + pcap_tstamp_type_name_to_val.3pcap \ + pcap_tstamp_type_val_to_name.3pcap + +MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=) + +MANFILE = \ + pcap-savefile.manfile.in + +MANMISC = \ + pcap-filter.manmisc.in \ + pcap-linktype.manmisc.in \ + pcap-tstamp.manmisc.in + +EXTRA_DIST = \ + CHANGES \ + ChmodBPF/ChmodBPF \ + ChmodBPF/StartupParameters.plist \ + CREDITS \ + CMakeLists.txt \ + INSTALL.md \ + LICENSE \ + Makefile.in \ + Makefile-devel-adds \ + README.md \ + doc/README.aix \ + doc/README.dag \ + doc/README.haiku.md \ + doc/README.hpux \ + doc/README.linux \ + doc/README.macos \ + doc/README.septel \ + doc/README.sita \ + doc/README.solaris.md \ + doc/README.windows.md \ + CONTRIBUTING.md \ + TODO \ + VERSION \ + aclocal.m4 \ + autogen.sh \ + charconv.c \ + charconv.h \ + chmod_bpf \ + cmake_uninstall.cmake.in \ + cmakeconfig.h.in \ + cmake/Modules/FindAirPcap.cmake \ + cmake/Modules/FindDAG.cmake \ + cmake/Modules/Finddpdk.cmake \ + cmake/Modules/FindFseeko.cmake \ + cmake/Modules/FindLFS.cmake \ + cmake/Modules/FindPacket.cmake \ + cmake/Modules/FindSNF.cmake \ + cmake/Modules/FindTC.cmake \ + cmake/have_siocglifconf.c \ + config.guess \ + config.sub \ + configure.ac \ + dlpisubs.c \ + dlpisubs.h \ + fad-getad.c \ + fad-gifc.c \ + fad-glifc.c \ + grammar.y.in \ + install-sh \ + lbl/os-aix4.h \ + lbl/os-aix7.h \ + lbl/os-hpux11.h \ + lbl/os-osf4.h \ + lbl/os-osf5.h \ + lbl/os-solaris2.h \ + lbl/os-sunos4.h \ + lbl/os-ultrix4.h \ + libpcap.pc.in \ + missing/asprintf.c \ + missing/getopt.c \ + missing/getopt.h \ + missing/strlcat.c \ + missing/strlcpy.c \ + missing/strtok_r.c \ + missing/win_asprintf.c \ + mkdep \ + msdos/bin2c.c \ + msdos/makefile \ + msdos/makefile.dj \ + msdos/makefile.wc \ + msdos/pkt_rx0.asm \ + msdos/pkt_rx1.s \ + msdos/pktdrvr.c \ + msdos/pktdrvr.h \ + msdos/readme.dos \ + nomkdep \ + org.tcpdump.chmod_bpf.plist \ + pcap-airpcap.c \ + pcap-airpcap.h \ + pcap-bpf.c \ + pcap-bt-linux.c \ + pcap-bt-linux.h \ + pcap-bt-monitor-linux.c \ + pcap-bt-monitor-linux.h \ + pcap-config.in \ + pcap-dag.c \ + pcap-dag.h \ + pcap-dbus.c \ + pcap-dbus.h \ + pcap-dll.rc \ + pcap-dlpi.c \ + pcap-dos.c \ + pcap-dos.h \ + pcap-dpdk.c \ + pcap-dpdk.h \ + pcap-enet.c \ + pcap-haiku.c \ + pcap-int.h \ + pcap-libdlpi.c \ + pcap-linux.c \ + pcap-namedb.h \ + pcap-new.c \ + pcap-netfilter-linux.c \ + pcap-netfilter-linux.h \ + pcap-netmap.c \ + pcap-netmap.h \ + pcap-nit.c \ + pcap-npf.c \ + pcap-null.c \ + pcap-pf.c \ + pcap-rdmasniff.c \ + pcap-rdmasniff.h \ + pcap-rpcap.c \ + pcap-septel.c \ + pcap-septel.h \ + pcap-sita.h \ + pcap-sita.c \ + pcap-sita.html \ + pcap-snf.c \ + pcap-snf.h \ + pcap-snit.c \ + pcap-snoop.c \ + pcap-tc.c \ + pcap-tc.h \ + pcap-usb-linux.c \ + pcap-usb-linux.h \ + rpcap-protocol.c \ + rpcapd/CMakeLists.txt \ + rpcapd/Makefile.in \ + rpcapd/config_params.h \ + rpcapd/daemon.h \ + rpcapd/daemon.c \ + rpcapd/fileconf.c \ + rpcapd/fileconf.h \ + rpcapd/log.h \ + rpcapd/log.c \ + rpcapd/org.tcpdump.rpcapd.plist \ + rpcapd/rpcapd.c \ + rpcapd/rpcapd.h \ + rpcapd/rpcapd.inetd.conf \ + rpcapd/rpcapd.manadmin.in \ + rpcapd/rpcapd-config.manfile.in \ + rpcapd/rpcapd.rc \ + rpcapd/rpcapd.socket \ + rpcapd/rpcapd.xinetd.conf \ + rpcapd/rpcapd@.service \ + rpcapd/win32-svc.c \ + rpcapd/win32-svc.h \ + sockutils.c \ + sockutils.h \ + sslutils.c \ + sslutils.h \ + scanner.l \ + testprogs/CMakeLists.txt \ + testprogs/Makefile.in \ + testprogs/can_set_rfmon_test.c \ + testprogs/capturetest.c \ + testprogs/filtertest.c \ + testprogs/findalldevstest.c \ + testprogs/findalldevstest-perf.c \ + testprogs/fuzz/CMakeLists.txt \ + testprogs/fuzz/fuzz_both.c \ + testprogs/fuzz/fuzz_both.options \ + testprogs/fuzz/fuzz_filter.c \ + testprogs/fuzz/fuzz_filter.options \ + testprogs/fuzz/fuzz_pcap.c \ + testprogs/fuzz/fuzz_pcap.options \ + testprogs/fuzz/onefile.c \ + testprogs/nonblocktest.c \ + testprogs/opentest.c \ + testprogs/reactivatetest.c \ + testprogs/selpolltest.c \ + testprogs/threadsignaltest.c \ + testprogs/unix.h \ + testprogs/valgrindtest.c \ + testprogs/visopts.py \ + testprogs/writecaptest.c + +TEST_DIST = `git -C "$$DIR" ls-files tests | grep -v 'tests/\..*'` + +RELEASE_FILES = $(COMMON_C_SRC) $(HDR) $(MAN1) $(MAN3PCAP_EXPAND) \ + $(MAN3PCAP_NOEXPAND) $(MANFILE) $(MANMISC) $(EXTRA_DIST) \ + $(TEST_DIST) + +all: libpcap.a shared $(BUILD_RPCAPD) libpcap.pc pcap-config + +libpcap.a: $(OBJ) + @rm -f $@ + $(AR) rc $@ $(OBJ) $(ADDLARCHIVEOBJS) + $(RANLIB) $@ + +shared: libpcap.$(DYEXT) + +libpcap.so: $(OBJ) + @rm -f $@ + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + @V_SHLIB_CMD@ $(LDFLAGS) @V_SHLIB_OPT@ @V_SONAME_OPT@$@.$$MAJOR_VER \ + -o $@.$$VER $(OBJ) $(ADDLOBJS) $(LIBS) + +# +# The following rule succeeds, but the result is untested. +# +# In macOS, the libpcap dylib has the name "libpcap.A.dylib", with its +# full path as the install_name, and with the compatibility and current +# version both set to 1. The compatibility version is set to 1 so that +# programs built with a newer version of the library will run against +# older versions if they don't use APIs available in the newer version +# but not in the older version. +# +# We also use "A" as the major version, and 1 as the compatibility version, +# but set the current version to the value in VERSION, with any non-numeric +# stuff stripped off (the compatibility and current version must be of the +# form X[.Y[.Z]], with Y and Z possibly absent, and with all components +# numeric). +# +libpcap.dylib: $(OBJ) + rm -f libpcap*.dylib + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + COMPAT_VER=1; \ + CURRENT_VER=`sed 's/[^0-9.].*$$//' $(srcdir)/VERSION`; \ + $(CC) -dynamiclib -undefined error $(LDFLAGS) @V_LIB_LDFLAGS_FAT@ \ + -o libpcap.$$VER.dylib $(OBJ) $(ADDLOBJS) $(LIBS) \ + -install_name $(libdir)/libpcap.$$MAJOR_VER.dylib \ + -compatibility_version $$COMPAT_VER \ + -current_version $$CURRENT_VER + +# +# The HP-UX linker manual says that the convention for a versioned library +# is libXXX.{number}, not libXXX.sl.{number}. That appears to be the case +# on at least one HP-UX 11.00 system; libXXX.sl is a symlink to +# libXXX.{number}. +# +# The manual also says "library-level versioning" (think "sonames") was +# added in HP-UX 10.0. +# +# XXX - this assumes we're using the HP linker, rather than the GNU +# linker, even with GCC. +# +libpcap.sl: $(OBJ) + @MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f libpcap.$$MAJOR_VER + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + ld -b $(LDFLAGS) -o libpcap.$$MAJOR_VER +h libpcap.$$MAJOR_VER \ + $(OBJ) $(ADDLOBJS) $(LIBS) + +# +# AIX is different from everybody else. A shared library is an archive +# library with one or more shared-object components. We still build a +# normal static archive library on AIX, for the benefit of the traditional +# scheme of building libpcap and tcpdump in subdirectories of the +# same directory, with tcpdump statically linked with the libpcap +# in question, but we also build a shared library as "libpcap.shareda" +# and install *it*, rather than the static library, as "libpcap.a". +# +libpcap.shareda: $(OBJ) + @rm -f $@ shr.o + $(CC) $(LDFLAGS) @V_SHLIB_OPT@ -o shr.o $(OBJ) $(ADDLOBJS) $(LIBS) + $(AR) rc $@ shr.o + +# +# For platforms that don't support shared libraries (or on which we +# don't support shared libraries). +# +libpcap.none: + +scanner.c: $(srcdir)/scanner.l + $(LEX) -P pcap_ --header-file=scanner.h --nounput -o scanner.c $< +scanner.h: scanner.c +## Recover from the removal of $@ + @if test -f $@; then :; else \ + rm -f scanner.c; \ + $(MAKE) $(MAKEFLAGS) scanner.c; \ + fi + +scanner.o: scanner.c grammar.h + $(CC) $(FULL_CFLAGS) -c scanner.c + +# +# Generate the grammar.y file. +# +# Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; +# for example, the Solaris 9 make man page says +# +# Because make assigns $< and $* as it would for implicit rules +# (according to the suffixes list and the directory contents), +# they may be unreliable when used within explicit target entries. +# +# and this is an explicit target entry. +# +# Therefore, instead of using $<, we explicitly put in $(srcdir)/grammar.y.in. +# +grammar.y: $(srcdir)/grammar.y.in ./config.status + @rm -f $@ $@.tmp + ./config.status --file=$@.tmp:$(srcdir)/grammar.y.in + mv $@.tmp $@ + +grammar.c: grammar.y + $(BISON_BYACC) -p pcap_ -o grammar.c -d $< +grammar.h: grammar.c +## Recover from the removal of $@ + @if test -f $@; then :; else \ + rm -f grammar.c; \ + $(MAKE) $(MAKEFLAGS) grammar.c; \ + fi + +grammar.o: grammar.c scanner.h + $(CC) $(FULL_CFLAGS) -c grammar.c + +gencode.o: $(srcdir)/gencode.c grammar.h scanner.h + $(CC) $(FULL_CFLAGS) -c $(srcdir)/gencode.c + +asprintf.o: $(srcdir)/missing/asprintf.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/asprintf.c + +snprintf.o: $(srcdir)/missing/snprintf.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/snprintf.c + +strlcat.o: $(srcdir)/missing/strlcat.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcat.c + +strlcpy.o: $(srcdir)/missing/strlcpy.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strlcpy.c + +strtok_r.o: $(srcdir)/missing/strtok_r.c + $(CC) $(FULL_CFLAGS) -o $@ -c $(srcdir)/missing/strtok_r.c + +# +# Generate the libpcap.pc file. +# +# Some Makes, e.g. AIX Make and Solaris Make, can't handle "--file=$@.tmp:$<"; +# for example, the Solaris 9 make man page says +# +# Because make assigns $< and $* as it would for implicit rules +# (according to the suffixes list and the directory contents), +# they may be unreliable when used within explicit target entries. +# +# and this is an explicit target entry. +# +# Therefore, instead of using $<, we explicitly put in $(srcdir)/libpcap.pc.in. +# +libpcap.pc: $(srcdir)/libpcap.pc.in ./config.status + @rm -f $@ $@.tmp + ./config.status --file=$@.tmp:$(srcdir)/libpcap.pc.in + mv $@.tmp $@ + +# +# Generate the pcap-config script. See above. +# +pcap-config: $(srcdir)/pcap-config.in ./config.status + @rm -f $@ $@.tmp + ./config.status --file=$@.tmp:$(srcdir)/pcap-config.in + mv $@.tmp $@ + chmod a+x $@ + +# +# Remote pcap daemon. +# +build-rpcapd: libpcap.a + (cd rpcapd; $(MAKE)) + +# +# Test programs - not built by default, and not installed. +# +testprogs: FORCE libpcap.a + (cd testprogs; $(MAKE) CFLAGS="$(CFLAGS)") + +FORCE: + +install: install-shared install-archive libpcap.pc pcap-config @INSTALL_RPCAPD@ + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + [ -d $(DESTDIR)$(includedir) ] || \ + (mkdir -p $(DESTDIR)$(includedir); chmod 755 $(DESTDIR)$(includedir)) + [ -d $(DESTDIR)$(includedir)/pcap ] || \ + (mkdir -p $(DESTDIR)$(includedir)/pcap; chmod 755 $(DESTDIR)$(includedir)/pcap) + [ -d $(DESTDIR)$(mandir)/man1 ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man1; chmod 755 $(DESTDIR)$(mandir)/man1) + [ -d $(DESTDIR)$(mandir)/man3 ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man3; chmod 755 $(DESTDIR)$(mandir)/man3) + [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) + [ -d $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@) + for i in $(PUBHDR); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(includedir)/$$i; done + [ -d $(DESTDIR)$(bindir) ] || \ + (mkdir -p $(DESTDIR)$(bindir); chmod 755 $(DESTDIR)$(bindir)) + $(INSTALL_PROGRAM) pcap-config $(DESTDIR)$(bindir)/pcap-config + [ -d $(DESTDIR)$(libdir)/pkgconfig ] || \ + (mkdir -p $(DESTDIR)$(libdir)/pkgconfig; chmod 755 $(DESTDIR)$(libdir)/pkgconfig) + $(INSTALL_DATA) libpcap.pc $(DESTDIR)$(libdir)/pkgconfig/libpcap.pc + for i in $(MAN1); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(mandir)/man1/$$i; done + for i in $(MAN3PCAP_NOEXPAND); do \ + $(INSTALL_DATA) $(srcdir)/$$i \ + $(DESTDIR)$(mandir)/man3/$$i; done + for i in $(MAN3PCAP_EXPAND:.in=); do \ + $(INSTALL_DATA) $$i \ + $(DESTDIR)$(mandir)/man3/$$i; done + (cd $(DESTDIR)$(mandir)/man3 && \ + rm -f pcap_datalink_val_to_description.3pcap && \ + $(LN_S) pcap_datalink_val_to_name.3pcap \ + pcap_datalink_val_to_description.3pcap && \ + rm -f pcap_datalink_val_to_description_or_dlt.3pcap && \ + $(LN_S) pcap_datalink_val_to_name.3pcap \ + pcap_datalink_val_to_description_or_dlt.3pcap && \ + rm -f pcap_dump_fopen.3pcap && \ + $(LN_S) pcap_dump_open.3pcap pcap_dump_fopen.3pcap && \ + rm -f pcap_freealldevs.3pcap && \ + $(LN_S) pcap_findalldevs.3pcap pcap_freealldevs.3pcap && \ + rm -f pcap_perror.3pcap && \ + $(LN_S) pcap_geterr.3pcap pcap_perror.3pcap && \ + rm -f pcap_sendpacket.3pcap && \ + $(LN_S) pcap_inject.3pcap pcap_sendpacket.3pcap && \ + rm -f pcap_free_datalinks.3pcap && \ + $(LN_S) pcap_list_datalinks.3pcap pcap_free_datalinks.3pcap && \ + rm -f pcap_free_tstamp_types.3pcap && \ + $(LN_S) pcap_list_tstamp_types.3pcap pcap_free_tstamp_types.3pcap && \ + rm -f pcap_dispatch.3pcap && \ + $(LN_S) pcap_loop.3pcap pcap_dispatch.3pcap && \ + rm -f pcap_minor_version.3pcap && \ + $(LN_S) pcap_major_version.3pcap pcap_minor_version.3pcap && \ + rm -f pcap_next.3pcap && \ + $(LN_S) pcap_next_ex.3pcap pcap_next.3pcap && \ + rm -f pcap_open_dead_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_dead.3pcap \ + pcap_open_dead_with_tstamp_precision.3pcap && \ + rm -f pcap_open_offline_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_open_offline_with_tstamp_precision.3pcap && \ + rm -f pcap_fopen_offline.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline.3pcap && \ + rm -f pcap_fopen_offline_with_tstamp_precision.3pcap && \ + $(LN_S) pcap_open_offline.3pcap pcap_fopen_offline_with_tstamp_precision.3pcap && \ + rm -f pcap_tstamp_type_val_to_description.3pcap && \ + $(LN_S) pcap_tstamp_type_val_to_name.3pcap pcap_tstamp_type_val_to_description.3pcap && \ + rm -f pcap_getnonblock.3pcap && \ + $(LN_S) pcap_setnonblock.3pcap pcap_getnonblock.3pcap) + for i in $(MANFILE); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ + $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + for i in $(MANMISC); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manmisc.in/.manmisc/'` \ + $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done + +install-shared: install-shared-$(DYEXT) +install-shared-so: libpcap.so + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + $(INSTALL_PROGRAM) libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ + ln -sf libpcap.so.$$VER $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ + ln -sf libpcap.so.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.so +install-shared-dylib: libpcap.dylib + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + $(INSTALL_PROGRAM) libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ + ln -sf libpcap.$$VER.dylib $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ + ln -sf libpcap.$$MAJOR_VER.dylib $(DESTDIR)$(libdir)/libpcap.dylib +install-shared-sl: libpcap.sl + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + $(INSTALL_PROGRAM) libpcap.$$MAJOR_VER $(DESTDIR)$(libdir) + ln -sf libpcap.$$MAJOR_VER $(DESTDIR)$(libdir)/libpcap.sl +# +# AIX shared libraries are weird. They're archive libraries +# with one or more shared object components. +# +install-shared-shareda: libpcap.shareda + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + $(INSTALL_PROGRAM) libpcap.shareda $(DESTDIR)$(libdir)/libpcap.a +install-shared-none: + +install-archive: install-archive-$(DYEXT) +# +# Most platforms have separate suffixes for shared and +# archive libraries, so we install both. +# +install-archive-so install-archive-dylib install-archive-sl install-archive-none: libpcap.a + [ -d $(DESTDIR)$(libdir) ] || \ + (mkdir -p $(DESTDIR)$(libdir); chmod 755 $(DESTDIR)$(libdir)) + $(INSTALL_DATA) libpcap.a $(DESTDIR)$(libdir)/libpcap.a + $(RANLIB) $(DESTDIR)$(libdir)/libpcap.a +# +# AIX, however, doesn't, so we don't install the archive +# library on AIX. +# +install-archive-shareda: + +install-rpcapd: + (cd rpcapd; $(MAKE) DESTDIR=$(DESTDIR) install) + +uninstall: uninstall-shared uninstall-rpcapd + rm -f $(DESTDIR)$(libdir)/libpcap.a + for i in $(PUBHDR); do \ + rm -f $(DESTDIR)$(includedir)/$$i; done + -rmdir $(DESTDIR)$(includedir)/pcap + rm -f $(DESTDIR)/$(libdir)/pkgconfig/libpcap.pc + rm -f $(DESTDIR)/$(bindir)/pcap-config + for i in $(MAN1); do \ + rm -f $(DESTDIR)$(mandir)/man1/$$i; done + for i in $(MAN3PCAP); do \ + rm -f $(DESTDIR)$(mandir)/man3/$$i; done + rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_datalink_val_to_description_or_dlt.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_dump_fopen.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_freealldevs.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_sendpacket.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_minor_version.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_next.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_open_dead_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_open_offline_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_fopen_offline_with_tstamp_precision.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_getnonblock.3pcap + rm -f $(DESTDIR)$(mandir)/man3/pcap_tstamp_type_val_to_description.3pcap + for i in $(MANFILE); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + for i in $(MANMISC); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_MISC_INFO@/`echo $$i | sed 's/.manmisc.in/.@MAN_MISC_INFO@/'`; done + +uninstall-shared: uninstall-shared-$(DYEXT) +uninstall-shared-so: + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so.$$VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so.$$MAJOR_VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.so +uninstall-shared-dylib: + VER=`cat $(srcdir)/VERSION`; \ + MAJOR_VER=A; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$VER.dylib; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER.dylib; \ + rm -f $(DESTDIR)$(libdir)/libpcap.dylib +uninstall-shared-sl: + MAJOR_VER=`sed 's/\([0-9][0-9]*\)\..*/\1/' $(srcdir)/VERSION`; \ + rm -f $(DESTDIR)$(libdir)/libpcap.$$MAJOR_VER; \ + rm -f $(DESTDIR)$(libdir)/libpcap.sl +uninstall-shared-shareda: + rm -f $(DESTDIR)$(libdir)/libpcap.a +uninstall-shared-none: + +uninstall-rpcapd: + (cd rpcapd; $(MAKE) DESTDIR=$(DESTDIR) uninstall) + +clean: + rm -f $(CLEANFILES) config.h.in~ configure~ configure.ac~ + (cd rpcapd; $(MAKE) clean) + (cd testprogs; $(MAKE) clean) + +distclean: clean + rm -f Makefile grammar.y config.cache config.log config.status \ + config.h os-proto.h libpcap.pc pcap-config stamp-h stamp-h.in + rm -f $(MAN3PCAP_EXPAND:.in=) $(MANFILE:.in=) $(MANMISC:.in=) + rm -rf autom4te.cache + (cd rpcapd; $(MAKE) distclean) + (cd testprogs; $(MAKE) distclean) + +extags: $(TAGFILES) + ctags $(TAGFILES) + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +# +# Use git archive piped to tar to construct a subdirectory whose name +# is libpcap-{release}, containing all the checked-in source files, +# and then run autoreconf in that directory to generate the configure +# script and other files from that source. Then remove autom4te.cache, +# construct the release tarball from that subdirectory, and remove +# the subdirectory. +# +# The --format=tar is to force git archive to write a non-compressed +# archive, in case the platform's tar command doesn't have built-in +# decompression. +# +# The ^{tree} is there to force git archive not to write out the +# "helpful" global extended pax header with a commit ID, as not all +# versions of tar can handle that (Solaris tar can't, for example). +# (It turns HEAD, or a tag, both of which are apparently "tree-ish"es, +# into a tree; apparently, unlike HEAD, or a tag, which have a commit +# ID associated with them, the tree associated with them doesn't have +# a commit ID, so no commit ID is available to write, and thus +# git archive doesn't write one.) +# +releasetar: + @TAG=$(PROG)-`cat VERSION` && \ + if [ ! -d .git ]; then echo 'Not in a git clone, stop.'; exit 1; fi && \ + TMPTESTFILE=`mktemp -t tmptestfile_XXXXXXXX` && \ + rm -f "$$TMPTESTFILE" && \ + AUTORECONF_DIR=`dirname "$$TMPTESTFILE"`/"$(PROG)"_build_autoreconf_$$$$ && \ + DIR=`pwd` && \ + rm -rf "$$AUTORECONF_DIR" && \ + mkdir "$$AUTORECONF_DIR" && \ + cd "$$AUTORECONF_DIR" && \ + if git -C "$$DIR" show-ref --tags --quiet --verify -- "refs/tags/$$TAG"; then \ + (git -C "$$DIR" archive --format=tar --prefix="$$TAG"/ "$$TAG^{tree}" $(RELEASE_FILES) | \ + tar xf -) && \ + echo "Archive build from tag $$TAG."; \ + else \ + (git -C "$$DIR" archive --format=tar --prefix="$$TAG"/ "HEAD^{tree}" $(RELEASE_FILES) | \ + tar xf -) && \ + echo "No $$TAG tag. Archive build from HEAD."; \ + fi && \ + (cd "$$TAG" && "$${AUTORECONF:-autoreconf}" && rm -rf autom4te.cache) && \ + tar cf "$$DIR/$$TAG".tar "$$TAG" && \ + rm -f "$$DIR/$$TAG".tar.gz && \ + gzip --best "$$DIR/$$TAG".tar && \ + cd "$$DIR" && \ + rm -rf "$$AUTORECONF_DIR" + +releasecheck: releasetar + @TAG=$(PROG)-`cat VERSION` && \ + INSTALL_DIR=/tmp/install_"$$TAG"_$$$$ && \ + DIR=`pwd` && \ + cd /tmp && \ + rm -rf "$$TAG" && \ + rm -rf "$$INSTALL_DIR" && \ + tar xf "$$DIR"/"$$TAG".tar.gz && \ + cd "$$TAG" && \ + echo "[$@] $$ touch .devel" && \ + touch .devel && \ + echo "[$@] $$ ./configure --enable-remote --quiet --prefix=$$INSTALL_DIR" && \ + ./configure --enable-remote --quiet --prefix="$$INSTALL_DIR" && \ + echo '[$@] $$ $(MAKE) -s all testprogs' && \ + $(MAKE) -s all testprogs && \ + echo '[$@] $$ $(MAKE) -s install' && \ + $(MAKE) -s install && \ + cd .. && \ + rm -rf "$$TAG" && \ + rm -rf "$$INSTALL_DIR" && \ + tar xf "$$DIR"/"$$TAG".tar.gz && \ + cd "$$TAG" && \ + echo "[$@] $$ touch .devel" && \ + touch .devel && \ + mkdir build && \ + cd build && \ + echo '[$@] $$ cmake -DENABLE_REMOTE=yes [...] ..' && \ + cmake -DENABLE_REMOTE=yes \ + -DCMAKE_INSTALL_PREFIX="$$INSTALL_DIR" \ + -DCMAKE_MESSAGE_LOG_LEVEL=NOTICE \ + -DCMAKE_RULE_MESSAGES=OFF \ + -DCMAKE_INSTALL_MESSAGE=NEVER \ + .. && \ + echo '[$@] $$ $(MAKE) -s all testprogs' && \ + $(MAKE) -s all testprogs && \ + echo '[$@] $$ $(MAKE) -s install' && \ + $(MAKE) -s install && \ + cd ../.. && \ + rm -rf "$$TAG" && \ + rm -rf "$$INSTALL_DIR" && \ + echo '[$@] Done.' + +whitespacecheck: + @# trailing space(s)? + @if git grep -I -n ' $$' $$(git ls-files|grep -v '^tests/'); then \ + echo 'Error: Trailing space(s).'; \ + exit 1; \ + fi + @# trailing tab(s)? + @if git grep -I -n ' $$' $$(git ls-files|grep -v '^tests/'); then \ + echo 'Error: Trailing tabs(s).'; \ + exit 1; \ + fi + @# space(s) before tab(s)? + @if git grep -I -n '[ ][ ]' $$(git ls-files|grep -v '^tests/'); then \ + echo 'Error: space(s) before tab(s).'; \ + exit 1; \ + fi + +depend: $(GENERATED_C_SRC) $(GENHDR) + $(MKDEP) -c $(CC) -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) + (cd rpcapd; $(MAKE) depend) + (cd testprogs; $(MAKE) depend) + +shellcheck: + shellcheck -f gcc -e SC2006 autogen.sh build.sh build_matrix.sh build_common.sh mkdep .ci-coverity-scan-build.sh diff --git a/src/libpcap-1.10.5/README.md b/src/libpcap-1.10.5/README.md new file mode 100644 index 0000000000..e38b9a15d6 --- /dev/null +++ b/src/libpcap-1.10.5/README.md @@ -0,0 +1,76 @@ +# LIBPCAP 1.x.y by [The Tcpdump Group](https://www.tcpdump.org) + +**To report a security issue please send an e-mail to security@tcpdump.org.** + +To report bugs and other problems, contribute patches, request a +feature, provide generic feedback etc please see the +[guidelines for contributing](CONTRIBUTING.md). + +The [documentation directory](doc/) has README files about specific +operating systems and options. + +Anonymous Git is available via: + + https://github.com/the-tcpdump-group/libpcap.git + +This directory contains source code for libpcap, a system-independent +interface for user-level packet capture. libpcap provides a portable +framework for low-level network monitoring. Applications include +network statistics collection, security monitoring, network debugging, +etc. Since almost every system vendor provides a different interface +for packet capture, and since we've developed several tools that +require this functionality, we've created this system-independent API +to ease in porting and to alleviate the need for several +system-dependent packet capture modules in each application. + +```text +formerly from Lawrence Berkeley National Laboratory + Network Research Group + ftp://ftp.ee.lbl.gov/old/libpcap-0.4a7.tar.Z +``` + +### Support for particular platforms and BPF +For some platforms there are `README.{system}` files that discuss issues +with the OS's interface for packet capture on those platforms, such as +how to enable support for that interface in the OS, if it's not built in +by default. + +The libpcap interface supports a filtering mechanism based on the +architecture in the BSD packet filter. BPF is described in the 1993 +Winter Usenix paper ``The BSD Packet Filter: A New Architecture for +User-level Packet Capture'' +([compressed PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.Z), +[gzipped PostScript](https://www.tcpdump.org/papers/bpf-usenix93.ps.gz), +[PDF](https://www.tcpdump.org/papers/bpf-usenix93.pdf)). + +Although most packet capture interfaces support in-kernel filtering, +libpcap utilizes in-kernel filtering only for the BPF interface. +On systems that don't have BPF, all packets are read into user-space +and the BPF filters are evaluated in the libpcap library, incurring +added overhead (especially, for selective filters). Ideally, libpcap +would translate BPF filters into a filter program that is compatible +with the underlying kernel subsystem, but this is not yet implemented. + +BPF is standard in 4.4BSD, BSD/OS, NetBSD, FreeBSD, OpenBSD, DragonFly +BSD, macOS, and Solaris 11; an older, modified and undocumented version +is standard in AIX. {DEC OSF/1, Digital UNIX, Tru64 UNIX} uses the +packetfilter interface but has been extended to accept BPF filters +(which libpcap utilizes). + +Linux has a number of BPF based systems, and libpcap does not support +any of the eBPF mechanisms as yet, although it supports many of the +memory mapped receive mechanisms. +See the [Linux-specific README](doc/README.linux) for more information. + +### Note to Linux distributions and *BSD systems that include libpcap: + +There's now a rule to make a shared library, which should work on Linux +and *BSD, among other platforms. + +It sets the soname of the library to `libpcap.so.1`; this is what it +should be, **NOT** `libpcap.so.1.x` or `libpcap.so.1.x.y` or something such as +that. + +We've been maintaining binary compatibility between libpcap releases for +quite a while; there's no reason to tie a binary linked with libpcap to +a particular release of libpcap. diff --git a/src/libpcap-1.10.5/TODO b/src/libpcap-1.10.5/TODO new file mode 100644 index 0000000000..8fdd1c42ef --- /dev/null +++ b/src/libpcap-1.10.5/TODO @@ -0,0 +1,28 @@ + TODO list for libpcap +======================= + +Important stuff (to be done before the next release) +--------------- + +General + +- The source files should be better documented. There is no official + design guideline for what is done where. There should be a common coding + style (okay, you can guess that by looking at the code) and a guide for + what needs to be documented. + +Less urgent items +----------------- + +- Better documentation and cleanup of the interface. I am seeing a few + problems at the first glance which needs fixing: + + not very well suited for interactive programs (think ethereal). There + should be a way for the application to get a file descriptor which it + has to monitor and a callback in pcap which has to be called on + activity (XXX - "pcap_fileno()" handles the first part, although + "select()" and "poll()" don't work on BPF devices on most BSDs, and + you can call "pcap_dispatch()" as the dispatch routine after putting + the descriptor into non-blocking mode) + + too many functions. There are a lot of functions for everything which + violates the KISS principle. Why do we need pcap_strerror, pcap_perror + and pcap_geterr? diff --git a/src/libpcap-1.10.5/VERSION b/src/libpcap-1.10.5/VERSION new file mode 100644 index 0000000000..db77e0ee97 --- /dev/null +++ b/src/libpcap-1.10.5/VERSION @@ -0,0 +1 @@ +1.10.5 diff --git a/src/libpcap-1.10.5/aclocal.m4 b/src/libpcap-1.10.5/aclocal.m4 new file mode 100644 index 0000000000..374a68db2e --- /dev/null +++ b/src/libpcap-1.10.5/aclocal.m4 @@ -0,0 +1,1346 @@ +dnl Copyright (c) 1995, 1996, 1997, 1998 +dnl The Regents of the University of California. All rights reserved. +dnl +dnl Redistribution and use in source and binary forms, with or without +dnl modification, are permitted provided that: (1) source code distributions +dnl retain the above copyright notice and this paragraph in its entirety, (2) +dnl distributions including binary code include the above copyright notice and +dnl this paragraph in its entirety in the documentation or other materials +dnl provided with the distribution, and (3) all advertising materials mentioning +dnl features or use of this software display the following acknowledgement: +dnl ``This product includes software developed by the University of California, +dnl Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +dnl the University nor the names of its contributors may be used to endorse +dnl or promote products derived from this software without specific prior +dnl written permission. +dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +dnl WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +dnl +dnl LBL autoconf macros +dnl + +dnl +dnl Do whatever AC_LBL_C_INIT work is necessary before using AC_PROG_CC. +dnl +dnl It appears that newer versions of autoconf (2.64 and later) will, +dnl if you use AC_TRY_COMPILE in a macro, stick AC_PROG_CC at the +dnl beginning of the macro, even if the macro itself calls AC_PROG_CC. +dnl See the "Prerequisite Macros" and "Expanded Before Required" sections +dnl in the Autoconf documentation. +dnl +dnl This causes a steaming heap of fail in our case, as we were, in +dnl AC_LBL_C_INIT, doing the tests we now do in AC_LBL_C_INIT_BEFORE_CC, +dnl calling AC_PROG_CC, and then doing the tests we now do in +dnl AC_LBL_C_INIT. Now, we run AC_LBL_C_INIT_BEFORE_CC, AC_PROG_CC, +dnl and AC_LBL_C_INIT at the top level. +dnl +AC_DEFUN(AC_LBL_C_INIT_BEFORE_CC, +[ + AC_BEFORE([$0], [AC_LBL_C_INIT]) + AC_BEFORE([$0], [AC_PROG_CC]) + AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) + AC_BEFORE([$0], [AC_LBL_DEVEL]) + AC_ARG_WITH(gcc, [ --without-gcc don't use gcc]) + $1="" + if test "${srcdir}" != "." ; then + $1="-I\$(srcdir)" + fi + if test "${CFLAGS+set}" = set; then + LBL_CFLAGS="$CFLAGS" + fi + if test -z "$CC" ; then + case "$host_os" in + + bsdi*) + AC_CHECK_PROG(SHLICC2, shlicc2, yes, no) + if test $SHLICC2 = yes ; then + CC=shlicc2 + export CC + fi + ;; + esac + fi + if test -z "$CC" -a "$with_gcc" = no ; then + CC=cc + export CC + fi +]) + +dnl +dnl Determine which compiler we're using (cc or gcc) +dnl If using gcc, determine the version number +dnl If using cc: +dnl require that it support ansi prototypes +dnl use -O (AC_PROG_CC will use -g -O2 on gcc, so we don't need to +dnl do that ourselves for gcc) +dnl add -g flags, as appropriate +dnl explicitly specify /usr/local/include +dnl +dnl NOTE WELL: with newer versions of autoconf, "gcc" means any compiler +dnl that defines __GNUC__, which means clang, for example, counts as "gcc". +dnl +dnl usage: +dnl +dnl AC_LBL_C_INIT(copt, incls) +dnl +dnl results: +dnl +dnl $1 (copt set) +dnl $2 (incls set) +dnl CC +dnl LDFLAGS +dnl LBL_CFLAGS +dnl +AC_DEFUN(AC_LBL_C_INIT, +[ + AC_BEFORE([$0], [AC_LBL_FIXINCLUDES]) + AC_BEFORE([$0], [AC_LBL_DEVEL]) + AC_BEFORE([$0], [AC_LBL_SHLIBS_INIT]) + if test "$GCC" = yes ; then + # + # -Werror forces warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) + else + $2="$$2 -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + + case "$host_os" in + + darwin*) + # + # This is assumed either to be GCC or clang, both + # of which use -Werror to force warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + AC_LBL_CHECK_COMPILER_OPT($1, -fvisibility=hidden) + ;; + + hpux*) + # + # HP C, which is what we presume we're using, doesn't + # exit with a non-zero exit status if we hand it an + # invalid -W flag, can't be forced to do so even with + # +We, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + ;; + + irix*) + # + # MIPS C, which is what we presume we're using, doesn't + # necessarily exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # It also, apparently, defaults to "char" being + # unsigned, unlike most other C implementations; + # I suppose we could say "signed char" whenever + # we want to guarantee a signed "char", but let's + # just force signed chars. + # + # -xansi is normally the default, but the + # configure script was setting it; perhaps -cckr + # was the default in the Old Days. (Then again, + # that would probably be for backwards compatibility + # in the days when ANSI C was Shiny and New, i.e. + # 1989 and the early '90's, so maybe we can just + # drop support for those compilers.) + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + $1="$$1 -xansi -signed -g3" + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + # The DEC C compiler, which is what we presume we're + # using, doesn't exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + $1="$$1 -g3" + ;; + + solaris*) + # + # Assumed to be Sun C, which requires -errwarn to force + # warnings to be treated as errors. + # + ac_lbl_cc_force_warning_errors=-errwarn + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + AC_LBL_CHECK_COMPILER_OPT($1, -xldscope=hidden) + ;; + + ultrix*) + AC_MSG_CHECKING(that Ultrix $CC hacks const in prototypes) + AC_CACHE_VAL(ac_cv_lbl_cc_const_proto, + AC_TRY_COMPILE( + [#include ], + [struct a { int b; }; + void c(const struct a *)], + ac_cv_lbl_cc_const_proto=yes, + ac_cv_lbl_cc_const_proto=no)) + AC_MSG_RESULT($ac_cv_lbl_cc_const_proto) + if test $ac_cv_lbl_cc_const_proto = no ; then + AC_DEFINE(const,[], + [to handle Ultrix compilers that don't support const in prototypes]) + fi + ;; + esac + $1="$$1 -O" + fi +]) + +dnl +dnl Save the values of various variables that affect compilation and +dnl linking, and that we don't ourselves modify persistently; done +dnl before a test involving compiling or linking is done, so that we +dnl can restore those variables after the test is done. +dnl +AC_DEFUN(AC_LBL_SAVE_CHECK_STATE, +[ + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" +]) + +dnl +dnl Restore the values of variables saved by AC_LBL_SAVE_CHECK_STATE. +dnl +AC_DEFUN(AC_LBL_RESTORE_CHECK_STATE, +[ + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" +]) + +dnl +dnl Check whether the compiler option specified as the second argument +dnl is supported by the compiler and, if so, add it to the macro +dnl specified as the first argument +dnl +dnl If a third argument is supplied, treat it as C code to be compiled +dnl with the flag in question, and the "treat warnings as errors" flag +dnl set, and don't add the flag to the first argument if the compile +dnl fails; this is for warning options cause problems that can't be +dnl worked around. If a third argument is supplied, a fourth argument +dnl should also be supplied; it's a message describing what the test +dnl program is checking. +dnl +AC_DEFUN(AC_LBL_CHECK_COMPILER_OPT, + [ + AC_MSG_CHECKING([whether the compiler supports the $2 option]) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $2" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([[int main(void) { return 0; }]])], + [ + AC_MSG_RESULT([yes]) + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x$4" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + AC_MSG_CHECKING(whether $2 $4) + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE($3)], + [ + # + # Not a problem. + # + AC_MSG_RESULT(no) + ], + [ + # + # A problem. + # + AC_MSG_RESULT(yes) + can_add_to_cflags=no + ]) + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + $1="$$1 $2" + fi + ], + [ + AC_MSG_RESULT([no]) + CFLAGS="$save_CFLAGS" + ]) + ac_c_werror_flag="$save_ac_c_werror_flag" + ]) + +dnl +dnl Check whether the compiler supports an option to generate +dnl Makefile-style dependency lines +dnl +dnl GCC uses -M for this. Non-GCC compilers that support this +dnl use a variety of flags, including but not limited to -M. +dnl +dnl We test whether the flag in question is supported, as older +dnl versions of compilers might not support it. +dnl +dnl We don't try all the possible flags, just in case some flag means +dnl "generate dependencies" on one compiler but means something else +dnl on another compiler. +dnl +dnl Most compilers that support this send the output to the standard +dnl output by default. IBM's XLC, however, supports -M but sends +dnl the output to {sourcefile-basename}.u, and AIX has no /dev/stdout +dnl to work around that, so we don't bother with XLC. +dnl +AC_DEFUN(AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT, + [ + AC_MSG_CHECKING([whether the compiler supports generating dependencies]) + if test "$GCC" = yes ; then + # + # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even + # though it's not); we assume that, in this case, the flag + # would be -M. + # + ac_lbl_dependency_flag="-M" + else + # + # Not GCC or a compiler deemed to be GCC; what platform is + # this? (We're assuming that if the compiler isn't GCC + # it's the compiler from the vendor of the OS; that won't + # necessarily be true for x86 platforms, where it might be + # the Intel C compiler.) + # + case "$host_os" in + + irix*|osf*|darwin*) + # + # MIPS C for IRIX, DEC C, and clang all use -M. + # + ac_lbl_dependency_flag="-M" + ;; + + solaris*) + # + # Sun C uses -xM. + # + ac_lbl_dependency_flag="-xM" + ;; + + hpux*) + # + # HP's older C compilers don't support this. + # HP's newer C compilers support this with + # either +M or +Make; the older compilers + # interpret +M as something completely + # different, so we use +Make so we don't + # think it works with the older compilers. + # + ac_lbl_dependency_flag="+Make" + ;; + + *) + # + # Not one of the above; assume no support for + # generating dependencies. + # + ac_lbl_dependency_flag="" + ;; + esac + fi + + # + # Is ac_lbl_dependency_flag defined and, if so, does the compiler + # complain about it? + # + # Note: clang doesn't seem to exit with an error status when handed + # an unknown non-warning error, even if you pass it + # -Werror=unknown-warning-option. However, it always supports + # -M, so the fact that this test always succeeds with clang + # isn't an issue. + # + if test ! -z "$ac_lbl_dependency_flag"; then + AC_LANG_CONFTEST( + [AC_LANG_SOURCE([[int main(void) { return 0; }]])]) + if AC_RUN_LOG([eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1"]); then + AC_MSG_RESULT([yes, with $ac_lbl_dependency_flag]) + DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" + MKDEP='${top_srcdir}/mkdep' + else + AC_MSG_RESULT([no]) + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP='${top_srcdir}/nomkdep' + fi + rm -rf conftest* + else + AC_MSG_RESULT([no]) + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP='${top_srcdir}/nomkdep' + fi + AC_SUBST(DEPENDENCY_CFLAG) + AC_SUBST(MKDEP) + ]) + +dnl +dnl Determine what options are needed to build a shared library +dnl +dnl usage: +dnl +dnl AC_LBL_SHLIBS_INIT +dnl +dnl results: +dnl +dnl V_SHLIB_CCOPT (modified to build position-independent code) +dnl V_SHLIB_CMD +dnl V_SHLIB_OPT +dnl V_SONAME_OPT +dnl +AC_DEFUN(AC_LBL_SHLIBS_INIT, + [AC_PREREQ(2.50) + if test "$GCC" = yes ; then + # + # On platforms where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in AIX and Darwin/macOS); + # + # define option to set the soname of the shared library, + # if the OS supports that; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + case "$host_os" in + + aix*) + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*) + # + # Platforms where the C compiler is GCC or accepts + # compatible command-line arguments, and the linker + # is the GNU linker or accepts compatible command-line + # arguments. + # + # Some instruction sets require -fPIC on some + # operating systems. Check for them. If you + # have a combination that requires it, add it + # here. + # + PIC_OPT=-fpic + case "$host_cpu" in + + sparc64*) + case "$host_os" in + + freebsd*|openbsd*|linux*) + PIC_OPT=-fPIC + ;; + esac + ;; + esac + V_SHLIB_CCOPT="$V_SHLIB_CCOPT $PIC_OPT" + V_SONAME_OPT="-Wl,-soname," + ;; + + hpux*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + # + # XXX - this assumes GCC is using the HP linker, + # rather than the GNU linker, and that the "+h" + # option is used on all HP-UX platforms, both .sl + # and .so. + # + V_SONAME_OPT="-Wl,+h," + # + # By default, directories specified with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + solaris*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + # + # Sun/Oracle's C compiler, GCC, and GCC-compatible + # compilers support -Wl,{comma-separated list of options}, + # and we use the C compiler, not ld, for all linking, + # including linking to produce a shared library. + # + V_SONAME_OPT="-Wl,-h," + ;; + esac + else + # + # Set the appropriate compiler flags and, on platforms + # where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in Darwin/macOS); + # + # if we generate ".so" shared libraries, define the + # appropriate options for building the shared library; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + # Note: spaces after V_SONAME_OPT are significant; on + # some platforms the soname is passed with a GCC-like + # "-Wl,-soname,{soname}" option, with the soname part + # of the option, while on other platforms the C compiler + # driver takes it as a regular option with the soname + # following the option. + # + case "$host_os" in + + aix*) + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G -bnoentry -bexpall" + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*) + # + # Platforms where the C compiler is GCC or accepts + # compatible command-line arguments, and the linker + # is the GNU linker or accepts compatible command-line + # arguments. + # + # XXX - does 64-bit SPARC require -fPIC? + # + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-Wl,-soname," + ;; + + hpux*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT +z" + V_SHLIB_CMD="\$(LD)" + V_SHLIB_OPT="-b" + V_SONAME_OPT="+h " + # + # By default, directories specified with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-soname " + ;; + + solaris*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -Kpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G" + # + # Sun/Oracle's C compiler, GCC, and GCC-compatible + # compilers support -Wl,{comma-separated list of options}, + # and we use the C compiler, not ld, for all linking, + # including linking to produce a shared library. + # + V_SONAME_OPT="-Wl,-h," + ;; + esac + fi +]) + +# +# Try compiling a sample of the type of code that appears in +# gencode.c with "inline", "__inline__", and "__inline". +# +# Autoconf's AC_C_INLINE, at least in autoconf 2.13, isn't good enough, +# as it just tests whether a function returning "int" can be inlined; +# at least some versions of HP's C compiler can inline that, but can't +# inline a function that returns a struct pointer. +# +# Make sure we use the V_CCOPT flags, because some of those might +# disable inlining. +# +AC_DEFUN(AC_LBL_C_INLINE, + [AC_MSG_CHECKING(for inline) + save_CFLAGS="$CFLAGS" + CFLAGS="$V_CCOPT" + AC_CACHE_VAL(ac_cv_lbl_inline, [ + ac_cv_lbl_inline="" + ac_lbl_cc_inline=no + for ac_lbl_inline in inline __inline__ __inline + do + AC_TRY_COMPILE( + [#define inline $ac_lbl_inline + static inline struct iltest *foo(void); + struct iltest { + int iltest1; + int iltest2; + }; + + static inline struct iltest * + foo() + { + static struct iltest xxx; + + return &xxx; + }],,ac_lbl_cc_inline=yes,) + if test "$ac_lbl_cc_inline" = yes ; then + break; + fi + done + if test "$ac_lbl_cc_inline" = yes ; then + ac_cv_lbl_inline=$ac_lbl_inline + fi]) + CFLAGS="$save_CFLAGS" + if test ! -z "$ac_cv_lbl_inline" ; then + AC_MSG_RESULT($ac_cv_lbl_inline) + else + AC_MSG_RESULT(no) + fi + AC_DEFINE_UNQUOTED(inline, $ac_cv_lbl_inline, [Define as token for inline if inlining supported])]) + +# +# Test whether we have __atomic_load_n() and __atomic_store_n(). +# +# We use AC_TRY_LINK because AC_TRY_COMPILE will succeed, as the +# compiler will just think that those functions are undefined, +# and perhaps warn about that, but not fail to compile. +# +AC_DEFUN(AC_PCAP_C___ATOMICS, + [ + AC_MSG_CHECKING(for __atomic_load_n) + AC_CACHE_VAL(ac_cv_have___atomic_load_n, + AC_TRY_LINK([], + [ + int i = 17; + int j; + j = __atomic_load_n(&i, __ATOMIC_RELAXED); + ], + ac_have___atomic_load_n=yes, + ac_have___atomic_load_n=no)) + AC_MSG_RESULT($ac_have___atomic_load_n) + if test $ac_have___atomic_load_n = yes ; then + AC_DEFINE(HAVE___ATOMIC_LOAD_N, 1, + [define if __atomic_load_n is supported by the compiler]) + fi + + AC_MSG_CHECKING(for __atomic_store_n) + AC_CACHE_VAL(ac_cv_have___atomic_store_n, + AC_TRY_LINK([], + [ + int i; + __atomic_store_n(&i, 17, __ATOMIC_RELAXED); + ], + ac_have___atomic_store_n=yes, + ac_have___atomic_store_n=no)) + AC_MSG_RESULT($ac_have___atomic_store_n) + if test $ac_have___atomic_store_n = yes ; then + AC_DEFINE(HAVE___ATOMIC_STORE_N, 1, + [define if __atomic_store_n is supported by the compiler]) + fi]) + +dnl +dnl If using gcc, make sure we have ANSI ioctl definitions +dnl +dnl usage: +dnl +dnl AC_LBL_FIXINCLUDES +dnl +AC_DEFUN(AC_LBL_FIXINCLUDES, + [if test "$GCC" = yes ; then + AC_MSG_CHECKING(for ANSI ioctl definitions) + AC_CACHE_VAL(ac_cv_lbl_gcc_fixincludes, + AC_TRY_COMPILE( + [/* + * This generates a "duplicate case value" when fixincludes + * has not be run. + */ +# include +# include +# include +# ifdef HAVE_SYS_IOCCOM_H +# include +# endif], + [switch (0) { + case _IO('A', 1):; + case _IO('B', 1):; + }], + ac_cv_lbl_gcc_fixincludes=yes, + ac_cv_lbl_gcc_fixincludes=no)) + AC_MSG_RESULT($ac_cv_lbl_gcc_fixincludes) + if test $ac_cv_lbl_gcc_fixincludes = no ; then + # Don't cache failure + unset ac_cv_lbl_gcc_fixincludes + AC_MSG_ERROR(see the INSTALL for more info) + fi + fi]) + +dnl +dnl Checks to see if union wait is used with WEXITSTATUS() +dnl +dnl usage: +dnl +dnl AC_LBL_UNION_WAIT +dnl +dnl results: +dnl +dnl DECLWAITSTATUS (defined) +dnl +AC_DEFUN(AC_LBL_UNION_WAIT, + [AC_MSG_CHECKING(if union wait is used) + AC_CACHE_VAL(ac_cv_lbl_union_wait, + AC_TRY_COMPILE([ +# include +# include ], + [int status; + u_int i = WEXITSTATUS(status); + u_int j = waitpid(0, &status, 0);], + ac_cv_lbl_union_wait=no, + ac_cv_lbl_union_wait=yes)) + AC_MSG_RESULT($ac_cv_lbl_union_wait) + if test $ac_cv_lbl_union_wait = yes ; then + AC_DEFINE(DECLWAITSTATUS,union wait,[type for wait]) + else + AC_DEFINE(DECLWAITSTATUS,int,[type for wait]) + fi]) + +dnl +dnl Checks to see if -R is used +dnl +dnl usage: +dnl +dnl AC_LBL_HAVE_RUN_PATH +dnl +dnl results: +dnl +dnl ac_cv_lbl_have_run_path (yes or no) +dnl +AC_DEFUN(AC_LBL_HAVE_RUN_PATH, + [AC_MSG_CHECKING(for ${CC-cc} -R) + AC_CACHE_VAL(ac_cv_lbl_have_run_path, + [echo 'main(){}' > conftest.c + ${CC-cc} -o conftest conftest.c -R/a1/b2/c3 >conftest.out 2>&1 + if test ! -s conftest.out ; then + ac_cv_lbl_have_run_path=yes + else + ac_cv_lbl_have_run_path=no + fi + rm -f -r conftest*]) + AC_MSG_RESULT($ac_cv_lbl_have_run_path) + ]) + +dnl +dnl If the file .devel exists: +dnl Add some warning flags if the compiler supports them +dnl If an os prototype include exists, symlink os-proto.h to it +dnl +dnl usage: +dnl +dnl AC_LBL_DEVEL(copt) +dnl +dnl results: +dnl +dnl $1 (copt appended) +dnl HAVE_OS_PROTO_H (defined) +dnl os-proto.h (symlinked) +dnl +AC_DEFUN(AC_LBL_DEVEL, + [rm -f os-proto.h + if test "${LBL_CFLAGS+set}" = set; then + $1="$$1 ${LBL_CFLAGS}" + fi + if test -f .devel ; then + # + # Skip all the warning option stuff on some compilers. + # + if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then + AC_LBL_CHECK_COMPILER_OPT($1, -W) + AC_LBL_CHECK_COMPILER_OPT($1, -Wall) + AC_LBL_CHECK_COMPILER_OPT($1, -Wcomma) + # Warns about safeguards added in case the enums are + # extended + # AC_LBL_CHECK_COMPILER_OPT($1, -Wcovered-switch-default) + AC_LBL_CHECK_COMPILER_OPT($1, -Wdocumentation) + AC_LBL_CHECK_COMPILER_OPT($1, -Wformat-nonliteral) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-noreturn) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-prototypes) + AC_LBL_CHECK_COMPILER_OPT($1, -Wmissing-variable-declarations) + AC_LBL_CHECK_COMPILER_OPT($1, -Wnull-pointer-subtraction) + AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-arith) + AC_LBL_CHECK_COMPILER_OPT($1, -Wpointer-sign) + AC_LBL_CHECK_COMPILER_OPT($1, -Wshadow) + AC_LBL_CHECK_COMPILER_OPT($1, -Wshorten-64-to-32) + AC_LBL_CHECK_COMPILER_OPT($1, -Wsign-compare) + AC_LBL_CHECK_COMPILER_OPT($1, -Wstrict-prototypes) + AC_LBL_CHECK_COMPILER_OPT($1, -Wundef) + # + # This can cause problems with ntohs(), ntohl(), + # htons(), and htonl() on some platforms, such + # as OpenBSD 6.3 with Clang 5.0.1. I guess the + # problem is that the macro that ultimately does + # the byte-swapping involves a conditional + # expression that tests whether the value being + # swapped is a compile-time constant or not, + # using __builtin_constant_p(), and, depending + # on whether it is, does a compile-time swap or + # a run-time swap; perhaps the compiler always + # considers one of the two results of the + # conditional expression is never evaluated, + # because the conditional check is done at + # compile time, and thus always says "that + # expression is never executed". + # + # (Perhaps there should be a way of flagging + # an expression that you *want* evaluated at + # compile time, so that the compiler 1) warns + # if it *can't* be evaluated at compile time + # and 2) *doesn't* warn that the true or false + # branch will never be reached.) + # + AC_LBL_CHECK_COMPILER_OPT($1, -Wunreachable-code, + [ +#include + +unsigned short +testme(unsigned short a) +{ + return ntohs(a); +} + ], + [generates warnings from ntohs()]) + AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-but-set-parameter) + AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-but-set-variable) + AC_LBL_CHECK_COMPILER_OPT($1, -Wunused-parameter) + AC_LBL_CHECK_COMPILER_OPT($1, -Wused-but-marked-unused) + fi + AC_LBL_CHECK_DEPENDENCY_GENERATION_OPT() + # + # We used to set -n32 for IRIX 6 when not using GCC (presumed + # to mean that we're using MIPS C or MIPSpro C); it specified + # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm + # not sure why that would be something to do *only* with a + # .devel file; why should the ABI for which we produce code + # depend on .devel? + # + os=`echo $host_os | sed -e 's/\([[0-9]][[0-9]]*\)[[^0-9]].*$/\1/'` + name="lbl/os-$os.h" + if test -f $name ; then + ln -s $name os-proto.h + AC_DEFINE(HAVE_OS_PROTO_H, 1, + [if there's an os_proto.h for this platform, to use additional prototypes]) + else + AC_MSG_WARN(can't find $name) + fi + fi]) + +dnl +dnl Improved version of AC_CHECK_LIB +dnl +dnl Thanks to John Hawkinson (jhawk@mit.edu) +dnl +dnl usage: +dnl +dnl AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [, +dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]]) +dnl +dnl results: +dnl +dnl LIBS +dnl +dnl XXX - "AC_LBL_LIBRARY_NET" was redone to use "AC_SEARCH_LIBS" +dnl rather than "AC_LBL_CHECK_LIB", so this isn't used any more. +dnl We keep it around for reference purposes in case it's ever +dnl useful in the future. +dnl + +define(AC_LBL_CHECK_LIB, +[AC_MSG_CHECKING([for $2 in -l$1]) +dnl Use a cache variable name containing the library, function +dnl name, and extra libraries to link with, because the test really is +dnl for library $1 defining function $2, when linked with potinal +dnl library $5, not just for library $1. Separate tests with the same +dnl $1 and different $2's or $5's may have different results. +ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'` +AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var, +[ac_save_LIBS="$LIBS" +LIBS="-l$1 $5 $LIBS" +AC_TRY_LINK(dnl +ifelse([$2], [main], , dnl Avoid conflicting decl of main. +[/* Override any gcc2 internal prototype to avoid an error. */ +]ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus +extern "C" +#endif +])dnl +[/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $2(); +]), + [$2()], + eval "ac_cv_lbl_lib_$ac_lib_var=yes", + eval "ac_cv_lbl_lib_$ac_lib_var=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$3], , +[changequote(, )dnl + ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` +changequote([, ])dnl + AC_DEFINE_UNQUOTED($ac_tr_lib) + LIBS="-l$1 $LIBS" +], [$3]) +else + AC_MSG_RESULT(no) +ifelse([$4], , , [$4 +])dnl +fi +]) + +dnl +dnl AC_LBL_LIBRARY_NET +dnl +dnl Look for various networking-related libraries that we may need. +dnl +dnl We need getaddrinfo() to translate host names in filters to IP +dnl addresses. We use getaddrinfo() because we want a portable +dnl thread-safe way of getting information for a host name or port; +dnl there exist _r versions of gethostbyname() and getservbyname() on +dnl some platforms, but not on all platforms. +dnl +dnl We may also need socket() and other socket functions to support: +dnl +dnl Local packet capture with capture mechanisms that use sockets. +dnl +dnl Local capture device enumeration if a socket call is needed to +dnl enumerate devices or get device attributes. +dnl +dnl Packet capture from services that put captured packets on the +dnl network, such as rpcap servers. +dnl +dnl We may also need getnameinfo() for packet capture from services +dnl that put packets on the network. +dnl +AC_DEFUN(AC_LBL_LIBRARY_NET, [ + # + # Most operating systems have getaddrinfo(), and the other routines + # we may need, in the default searched libraries (e.g., libc). + # Check there first. + # + AC_CHECK_FUNC(getaddrinfo,, + [ + # + # Not found in the standard system libraries. + # + # In some versions of Solaris, we need to link with libsocket + # and libnsl, so check in libsocket and also link with liblnsl + # when doing this test. + # + # Linking with libsocket and libnsl will find all the routines + # we need. + # + AC_CHECK_LIB(socket, getaddrinfo, + [ + # + # OK, we found it in libsocket. + # + LIBS="-lsocket -lnsl $LIBS" + ], + [ + # + # Not found in libsocket; test for it in libnetwork, which + # is where it is in Haiku. + # + # Linking with libnetwork will find all the routines we + # need. + # + AC_CHECK_LIB(network, getaddrinfo, + [ + # + # OK, we found it in libnetwork. + # + LIBS="-lnetwork $LIBS" + ], + [ + # + # We didn't find it. + # + AC_MSG_ERROR([getaddrinfo is required, but wasn't found]) + ]) + ], -lnsl) + + # + # We require a version of recvmsg() that conforms to the Single + # UNIX Specification, so that we can check whether a datagram + # received with recvmsg() was truncated when received due to the + # buffer being too small. + # + # On most systems, the version of recvmsg() in the libraries + # found above conforms to the SUS. + # + # On at least some versions of Solaris, it does not conform to + # the SUS, and we need the version in libxnet, which does + # conform. + # + # Check whether libxnet exists and has a version of recvmsg(); + # if it does, link with libxnet before we link with libsocket, + # to get that version. + # + # This test also links with libsocket and libnsl. + # + AC_CHECK_LIB(xnet, recvmsg, + [ + # + # libxnet has recvmsg(); link with it as well. + # + LIBS="-lxnet $LIBS" + ], , -lsocket -lnsl) + ]) + + # + # DLPI needs putmsg under HP-UX, so test for -lstr while we're at it. + # + AC_SEARCH_LIBS(putmsg, str) +]) + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +dnl serial 11 (pkg-config-0.29) +dnl +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.17.0 is +dnl used since that's the first version where --static was supported. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.17.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULE, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular module exists. Similar to +dnl PKG_CHECK_MODULE(), but does not set variables or print errors. +AC_DEFUN([PKG_CHECK_EXISTS], +[ +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG_WITH_FLAGS([VARIABLE], [FLAGS], [MODULE]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and, if +dnl pkg-config fails, reporting the error and quitting. +m4_define([_PKG_CONFIG_WITH_FLAGS], +[if test ! -n "$$1"; then + $1=`$PKG_CONFIG $2 "$3" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors $2 "$3" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors $2 "$3" 2>&1` + fi + AC_MSG_ERROR([$PKG_CONFIG $2 "$3" failed: $_pkg_error_string]) + fi + fi[]dnl +])dnl _PKG_CONFIG_WITH_FLAGS + + +dnl _PKG_CONFIG([VARIABLE], [FLAGS], [MODULE]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG $2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[ +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULE(VARIABLE-PREFIX, MODULE, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +AC_DEFUN([PKG_CHECK_MODULE], +[ +AC_MSG_CHECKING([for $2 with pkg-config]) +if test -n "$PKG_CONFIG"; then + AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $2, overriding pkg-config])dnl + AC_ARG_VAR([$1][_LIBS], [linker flags for $2, overriding pkg-config])dnl + AC_ARG_VAR([$1][_LIBS_STATIC], [static-link linker flags for $2, overriding pkg-config])dnl + + if AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$2"]); then + # + # The package was found, so try to get its C flags and + # libraries. + # + AC_MSG_RESULT([found]) + _PKG_CONFIG_WITH_FLAGS([$1][_CFLAGS], [--cflags], [$2]) + _PKG_CONFIG_WITH_FLAGS([$1][_LIBS], [--libs], [$2]) + _PKG_CONFIG_WITH_FLAGS([$1][_LIBS_STATIC], [--libs --static], [$2]) + m4_default([$3], [:]) + else + AC_MSG_RESULT([not found]) + m4_default([$4], [:]) + fi +else + # No pkg-config, so obviously not found with pkg-config. + AC_MSG_RESULT([pkg-config not found]) + m4_default([$4], [:]) +fi +])dnl PKG_CHECK_MODULE + + +dnl PKG_CHECK_MODULE_STATIC(VARIABLE-PREFIX, MODULE, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULE and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +AC_DEFUN([PKG_CHECK_MODULE_STATIC], +[ +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULE($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULE_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[ +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [--variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR diff --git a/src/libpcap-1.10.5/arcnet.h b/src/libpcap-1.10.5/arcnet.h new file mode 100644 index 0000000000..58690985cb --- /dev/null +++ b/src/libpcap-1.10.5/arcnet.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp + */ + +/* RFC 1051 */ +#define ARCTYPE_IP_OLD 240 /* IP protocol */ +#define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ + +/* RFC 1201 */ +#define ARCTYPE_IP 212 /* IP protocol */ +#define ARCTYPE_ARP 213 /* address resolution protocol */ +#define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ + +#define ARCTYPE_ATALK 221 /* Appletalk */ +#define ARCTYPE_BANIAN 247 /* Banyan Vines */ +#define ARCTYPE_IPX 250 /* Novell IPX */ + +#define ARCTYPE_INET6 0xc4 /* IPng */ +#define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ diff --git a/src/libpcap-1.10.5/atmuni31.h b/src/libpcap-1.10.5/atmuni31.h new file mode 100644 index 0000000000..83208d1f15 --- /dev/null +++ b/src/libpcap-1.10.5/atmuni31.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Based on UNI3.1 standard by ATM Forum */ + +/* ATM traffic types based on VPI=0 and (the following VCI */ +#define VCI_PPC 0x05 /* Point-to-point signal msg */ +#define VCI_BCC 0x02 /* Broadcast signal msg */ +#define VCI_OAMF4SC 0x03 /* Segment OAM F4 flow cell */ +#define VCI_OAMF4EC 0x04 /* End-to-end OAM F4 flow cell */ +#define VCI_METAC 0x01 /* Meta signal msg */ +#define VCI_ILMIC 0x10 /* ILMI msg */ + +/* Q.2931 signalling messages */ +#define CALL_PROCEED 0x02 /* call proceeding */ +#define CONNECT 0x07 /* connect */ +#define CONNECT_ACK 0x0f /* connect_ack */ +#define SETUP 0x05 /* setup */ +#define RELEASE 0x4d /* release */ +#define RELEASE_DONE 0x5a /* release_done */ +#define RESTART 0x46 /* restart */ +#define RESTART_ACK 0x4e /* restart ack */ +#define STATUS 0x7d /* status */ +#define STATUS_ENQ 0x75 /* status ack */ +#define ADD_PARTY 0x80 /* add party */ +#define ADD_PARTY_ACK 0x81 /* add party ack */ +#define ADD_PARTY_REJ 0x82 /* add party rej */ +#define DROP_PARTY 0x83 /* drop party */ +#define DROP_PARTY_ACK 0x84 /* drop party ack */ + +/* Information Element Parameters in the signalling messages */ +#define CAUSE 0x08 /* cause */ +#define ENDPT_REF 0x54 /* endpoint reference */ +#define AAL_PARA 0x58 /* ATM adaptation layer parameters */ +#define TRAFF_DESCRIP 0x59 /* atm traffic descriptors */ +#define CONNECT_ID 0x5a /* connection identifier */ +#define QOS_PARA 0x5c /* quality of service parameters */ +#define B_HIGHER 0x5d /* broadband higher layer information */ +#define B_BEARER 0x5e /* broadband bearer capability */ +#define B_LOWER 0x5f /* broadband lower information */ +#define CALLING_PARTY 0x6c /* calling party number */ +#define CALLED_PARTY 0x70 /* called party number */ + +#define Q2931 0x09 + +/* Q.2931 signalling general messages format */ +#define PROTO_POS 0 /* offset of protocol discriminator */ +#define CALL_REF_POS 2 /* offset of call reference value */ +#define MSG_TYPE_POS 5 /* offset of message type */ +#define MSG_LEN_POS 7 /* offset of message length */ +#define IE_BEGIN_POS 9 /* offset of first information element */ + +/* format of signalling messages */ +#define TYPE_POS 0 +#define LEN_POS 2 +#define FIELD_BEGIN_POS 4 diff --git a/src/libpcap-1.10.5/autogen.sh b/src/libpcap-1.10.5/autogen.sh new file mode 100755 index 0000000000..c84a6b5c5d --- /dev/null +++ b/src/libpcap-1.10.5/autogen.sh @@ -0,0 +1,25 @@ +#!/bin/sh -e + +: "${AUTORECONF:=autoreconf}" + +AUTORECONFVERSION=`$AUTORECONF --version 2>&1 | grep "^autoreconf" | sed 's/.*) *//'` + +maj=`echo "$AUTORECONFVERSION" | cut -d. -f1` +min=`echo "$AUTORECONFVERSION" | cut -d. -f2` +# The minimum required version of autoconf is currently 2.69. +if [ "$maj" = "" ] || [ "$min" = "" ] || \ + [ "$maj" -lt 2 ] || { [ "$maj" -eq 2 ] && [ "$min" -lt 69 ]; }; then + cat >&2 <<-EOF + Please install the 'autoconf' package version 2.69 or later. + If version 2.69 or later is already installed and there is no + autoconf default, it may be necessary to set the AUTORECONF + environment variable to enable the one to use, like: + AUTORECONF=autoreconf-2.69 ./autogen.sh + or + AUTORECONF=autoreconf-2.71 ./autogen.sh + EOF + exit 1 +fi + +echo "$AUTORECONF identification: $AUTORECONFVERSION" +"$AUTORECONF" -f diff --git a/src/libpcap-1.10.5/bpf_dump.c b/src/libpcap-1.10.5/bpf_dump.c new file mode 100644 index 0000000000..79a5a34236 --- /dev/null +++ b/src/libpcap-1.10.5/bpf_dump.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include +#include + +#include "optimize.h" + +void +bpf_dump(const struct bpf_program *p, int option) +{ + const struct bpf_insn *insn; + int i; + int n = p->bf_len; + + insn = p->bf_insns; + if (option > 2) { + printf("%d\n", n); + for (i = 0; i < n; ++insn, ++i) { + printf("%u %u %u %u\n", insn->code, + insn->jt, insn->jf, insn->k); + } + return ; + } + if (option > 1) { + for (i = 0; i < n; ++insn, ++i) + printf("{ 0x%x, %d, %d, 0x%08x },\n", + insn->code, insn->jt, insn->jf, insn->k); + return; + } + for (i = 0; i < n; ++insn, ++i) { +#ifdef BDEBUG + if (i < NBIDS && bids[i] > 0) + printf("[%02d]", bids[i] - 1); + else + printf(" -- "); +#endif + puts(bpf_image(insn, i)); + } +} diff --git a/src/libpcap-1.10.5/bpf_filter.c b/src/libpcap-1.10.5/bpf_filter.c new file mode 100644 index 0000000000..9b899bbb36 --- /dev/null +++ b/src/libpcap-1.10.5/bpf_filter.c @@ -0,0 +1,544 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.c 7.5 (Berkeley) 7/15/91 + */ + +#include + +#include +#include "pcap-types.h" +#include "extract.h" +#include "diag-control.h" + +#define EXTRACT_SHORT EXTRACT_BE_U_2 +#define EXTRACT_LONG EXTRACT_BE_U_4 + +#ifndef _WIN32 +#include +#include +#include +#endif /* _WIN32 */ + +#include + +#include + +#ifdef __linux__ +#include +#include +#include +#endif + +enum { + BPF_S_ANC_NONE, + BPF_S_ANC_VLAN_TAG, + BPF_S_ANC_VLAN_TAG_PRESENT, +}; + +/* + * Execute the filter program starting at pc on the packet p + * wirelen is the length of the original packet + * buflen is the amount of data present + * aux_data is auxiliary data, currently used only when interpreting + * filters intended for the Linux kernel in cases where the kernel + * rejects the filter; it contains VLAN tag information + * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, + * in all other cases, p is a pointer to a buffer and buflen is its size. + * + * Thanks to Ani Sinha for providing initial implementation + */ +#if defined(SKF_AD_VLAN_TAG_PRESENT) +u_int +pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, + u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data) +#else +u_int +pcapint_filter_with_aux_data(const struct bpf_insn *pc, const u_char *p, + u_int wirelen, u_int buflen, const struct pcap_bpf_aux_data *aux_data _U_) +#endif +{ + register uint32_t A, X; + register bpf_u_int32 k; + uint32_t mem[BPF_MEMWORDS]; + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + for (;;) { + ++pc; + switch (pc->code) { + + default: + abort(); + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k > buflen || sizeof(int32_t) > buflen - k) { + return 0; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k > buflen || sizeof(int16_t) > buflen - k) { + return 0; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_ABS: + /* + * Yes, we know, this switch doesn't do + * anything unless we're building for + * a Linux kernel with removed VLAN + * tags available as meta-data. + */ +DIAG_OFF_DEFAULT_ONLY_SWITCH + switch (pc->k) { + +#if defined(SKF_AD_VLAN_TAG_PRESENT) + case SKF_AD_OFF + SKF_AD_VLAN_TAG: + if (!aux_data) + return 0; + A = aux_data->vlan_tag; + break; + + case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT: + if (!aux_data) + return 0; + A = aux_data->vlan_tag_present; + break; +#endif + default: + k = pc->k; + if (k >= buflen) { + return 0; + } + A = p[k]; + break; + } +DIAG_ON_DEFAULT_ONLY_SWITCH + continue; + + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (pc->k > buflen || X > buflen - pc->k || + sizeof(int32_t) > buflen - k) { + return 0; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (X > buflen || pc->k > buflen - X || + sizeof(int16_t) > buflen - k) { + return 0; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if (pc->k >= buflen || X >= buflen - pc->k) { + return 0; + } + A = p[k]; + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if (k >= buflen) { + return 0; + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_JMP|BPF_JA: + /* + * XXX - we currently implement "ip6 protochain" + * with backward jumps, so sign-extend pc->k. + */ + pc += (bpf_int32)pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_MOD|BPF_X: + if (X == 0) + return 0; + A %= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_XOR|BPF_X: + A ^= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + if (X < 32) + A <<= X; + else + A = 0; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + if (X < 32) + A >>= X; + else + A = 0; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_MOD|BPF_K: + A %= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_XOR|BPF_K: + A ^= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + /* + * Most BPF arithmetic is unsigned, but negation + * can't be unsigned; respecify it as subtracting + * the accumulator from 0U, so that 1) we don't + * get compiler warnings about negating an unsigned + * value and 2) don't get UBSan warnings about + * the result of negating 0x80000000 being undefined. + */ + A = (0U - A); + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + } + } +} + +u_int +pcapint_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, + u_int buflen) +{ + return pcapint_filter_with_aux_data(pc, p, wirelen, buflen, NULL); +} + +/* + * Return true if the 'fcode' is a valid filter program. + * The constraints are that each jump be forward and to a valid + * code, that memory accesses are within valid ranges (to the + * extent that this can be checked statically; loads of packet + * data have to be, and are, also checked at run time), and that + * the code terminates with either an accept or reject. + * + * The kernel needs to be able to verify an application's filter code. + * Otherwise, a bogus program could easily crash the system. + */ +int +pcapint_validate_filter(const struct bpf_insn *f, int len) +{ + u_int i, from; + const struct bpf_insn *p; + + if (len < 1) + return 0; + + for (i = 0; i < (u_int)len; ++i) { + p = &f[i]; + switch (BPF_CLASS(p->code)) { + /* + * Check that memory operations use valid addresses. + */ + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(p->code)) { + case BPF_IMM: + break; + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + /* + * There's no maximum packet data size + * in userland. The runtime packet length + * check suffices. + */ + break; + case BPF_MEM: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_LEN: + break; + default: + return 0; + } + break; + case BPF_ST: + case BPF_STX: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_ALU: + switch (BPF_OP(p->code)) { + case BPF_ADD: + case BPF_SUB: + case BPF_MUL: + case BPF_OR: + case BPF_AND: + case BPF_XOR: + case BPF_LSH: + case BPF_RSH: + case BPF_NEG: + break; + case BPF_DIV: + case BPF_MOD: + /* + * Check for constant division or modulus + * by 0. + */ + if (BPF_SRC(p->code) == BPF_K && p->k == 0) + return 0; + break; + default: + return 0; + } + break; + case BPF_JMP: + /* + * Check that jumps are within the code block, + * and that unconditional branches don't go + * backwards as a result of an overflow. + * Unconditional branches have a 32-bit offset, + * so they could overflow; we check to make + * sure they don't. Conditional branches have + * an 8-bit offset, and the from address is <= + * BPF_MAXINSNS, and we assume that BPF_MAXINSNS + * is sufficiently small that adding 255 to it + * won't overflow. + * + * We know that len is <= BPF_MAXINSNS, and we + * assume that BPF_MAXINSNS is < the maximum size + * of a u_int, so that i + 1 doesn't overflow. + * + * For userland, we don't know that the from + * or len are <= BPF_MAXINSNS, but we know that + * from <= len, and, except on a 64-bit system, + * it's unlikely that len, if it truly reflects + * the size of the program we've been handed, + * will be anywhere near the maximum size of + * a u_int. We also don't check for backward + * branches, as we currently support them in + * userland for the protochain operation. + */ + from = i + 1; + switch (BPF_OP(p->code)) { + case BPF_JA: + if (from + p->k >= (u_int)len) + return 0; + break; + case BPF_JEQ: + case BPF_JGT: + case BPF_JGE: + case BPF_JSET: + if (from + p->jt >= (u_int)len || from + p->jf >= (u_int)len) + return 0; + break; + default: + return 0; + } + break; + case BPF_RET: + break; + case BPF_MISC: + break; + default: + return 0; + } + } + return BPF_CLASS(f[len - 1].code) == BPF_RET; +} + +/* + * Exported because older versions of libpcap exported them. + */ +u_int +bpf_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, + u_int buflen) +{ + return pcapint_filter(pc, p, wirelen, buflen); +} + +int +bpf_validate(const struct bpf_insn *f, int len) +{ + return pcapint_validate_filter(f, len); +} diff --git a/src/libpcap-1.10.5/bpf_image.c b/src/libpcap-1.10.5/bpf_image.c new file mode 100644 index 0000000000..38eb857b9e --- /dev/null +++ b/src/libpcap-1.10.5/bpf_image.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include + +#include +#include + +#ifdef __linux__ +#include +#include +#include + +/* + * We want our versions of these #defines, not Linux's version. + * (The two should be the same; if not, we have a problem; all BPF + * implementations *should* be source-compatible supersets of ours.) + */ +#undef BPF_STMT +#undef BPF_JUMP +#endif + +#include "pcap-int.h" + +#include "thread-local.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifdef SKF_AD_OFF +/* + * Symbolic names for offsets that refer to the special Linux BPF locations. + */ +static const char *offsets[SKF_AD_MAX] = { +#ifdef SKF_AD_PROTOCOL + [SKF_AD_PROTOCOL] = "proto", +#endif +#ifdef SKF_AD_PKTTYPE + [SKF_AD_PKTTYPE] = "type", +#endif +#ifdef SKF_AD_IFINDEX + [SKF_AD_IFINDEX] = "ifidx", +#endif +#ifdef SKF_AD_NLATTR + [SKF_AD_NLATTR] = "nla", +#endif +#ifdef SKF_AD_NLATTR_NEST + [SKF_AD_NLATTR_NEST] = "nlan", +#endif +#ifdef SKF_AD_MARK + [SKF_AD_MARK] = "mark", +#endif +#ifdef SKF_AD_QUEUE + [SKF_AD_QUEUE] = "queue", +#endif +#ifdef SKF_AD_HATYPE + [SKF_AD_HATYPE] = "hatype", +#endif +#ifdef SKF_AD_RXHASH + [SKF_AD_RXHASH] = "rxhash", +#endif +#ifdef SKF_AD_CPU + [SKF_AD_CPU] = "cpu", +#endif +#ifdef SKF_AD_ALU_XOR_X + [SKF_AD_ALU_XOR_X] = "xor_x", +#endif +#ifdef SKF_AD_VLAN_TAG + [SKF_AD_VLAN_TAG] = "vlan_tci", +#endif +#ifdef SKF_AD_VLAN_TAG_PRESENT + [SKF_AD_VLAN_TAG_PRESENT] = "vlanp", +#endif +#ifdef SKF_AD_PAY_OFFSET + [SKF_AD_PAY_OFFSET] = "poff", +#endif +#ifdef SKF_AD_RANDOM + [SKF_AD_RANDOM] = "random", +#endif +#ifdef SKF_AD_VLAN_TPID + [SKF_AD_VLAN_TPID] = "vlan_tpid" +#endif +}; +#endif + +static void +bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p) +{ +#ifdef SKF_AD_OFF + const char *sym; + + /* + * It's an absolute load. + * Is the offset a special Linux offset that we know about? + */ + if (p->k >= (bpf_u_int32)SKF_AD_OFF && + p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) && + (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) { + /* + * Yes. Print the offset symbolically. + */ + (void)snprintf(buf, bufsize, "[%s]", sym); + } else +#endif + (void)snprintf(buf, bufsize, "[%d]", p->k); +} + +char * +bpf_image(const struct bpf_insn *p, int n) +{ + const char *op; + static thread_local char image[256]; + char operand_buf[64]; + const char *operand; + + switch (p->code) { + + default: + op = "unimp"; + (void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code); + operand = operand_buf; + break; + + case BPF_RET|BPF_K: + op = "ret"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_RET|BPF_A: + op = "ret"; + operand = ""; + break; + + case BPF_LD|BPF_W|BPF_ABS: + op = "ld"; + bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); + operand = operand_buf; + break; + + case BPF_LD|BPF_H|BPF_ABS: + op = "ldh"; + bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); + operand = operand_buf; + break; + + case BPF_LD|BPF_B|BPF_ABS: + op = "ldb"; + bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p); + operand = operand_buf; + break; + + case BPF_LD|BPF_W|BPF_LEN: + op = "ld"; + operand = "#pktlen"; + break; + + case BPF_LD|BPF_W|BPF_IND: + op = "ld"; + (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); + operand = operand_buf; + break; + + case BPF_LD|BPF_H|BPF_IND: + op = "ldh"; + (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); + operand = operand_buf; + break; + + case BPF_LD|BPF_B|BPF_IND: + op = "ldb"; + (void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k); + operand = operand_buf; + break; + + case BPF_LD|BPF_IMM: + op = "ld"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_LDX|BPF_IMM: + op = "ldx"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_LDX|BPF_MSH|BPF_B: + op = "ldxb"; + (void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k); + operand = operand_buf; + break; + + case BPF_LD|BPF_MEM: + op = "ld"; + (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); + operand = operand_buf; + break; + + case BPF_LDX|BPF_MEM: + op = "ldx"; + (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); + operand = operand_buf; + break; + + case BPF_ST: + op = "st"; + (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); + operand = operand_buf; + break; + + case BPF_STX: + op = "stx"; + (void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JA: + op = "ja"; + (void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JGT|BPF_K: + op = "jgt"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JGE|BPF_K: + op = "jge"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + op = "jeq"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JSET|BPF_K: + op = "jset"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_JMP|BPF_JGT|BPF_X: + op = "jgt"; + operand = "x"; + break; + + case BPF_JMP|BPF_JGE|BPF_X: + op = "jge"; + operand = "x"; + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + op = "jeq"; + operand = "x"; + break; + + case BPF_JMP|BPF_JSET|BPF_X: + op = "jset"; + operand = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_X: + op = "add"; + operand = "x"; + break; + + case BPF_ALU|BPF_SUB|BPF_X: + op = "sub"; + operand = "x"; + break; + + case BPF_ALU|BPF_MUL|BPF_X: + op = "mul"; + operand = "x"; + break; + + case BPF_ALU|BPF_DIV|BPF_X: + op = "div"; + operand = "x"; + break; + + case BPF_ALU|BPF_MOD|BPF_X: + op = "mod"; + operand = "x"; + break; + + case BPF_ALU|BPF_AND|BPF_X: + op = "and"; + operand = "x"; + break; + + case BPF_ALU|BPF_OR|BPF_X: + op = "or"; + operand = "x"; + break; + + case BPF_ALU|BPF_XOR|BPF_X: + op = "xor"; + operand = "x"; + break; + + case BPF_ALU|BPF_LSH|BPF_X: + op = "lsh"; + operand = "x"; + break; + + case BPF_ALU|BPF_RSH|BPF_X: + op = "rsh"; + operand = "x"; + break; + + case BPF_ALU|BPF_ADD|BPF_K: + op = "add"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_SUB|BPF_K: + op = "sub"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_MUL|BPF_K: + op = "mul"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_DIV|BPF_K: + op = "div"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_MOD|BPF_K: + op = "mod"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_AND|BPF_K: + op = "and"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_OR|BPF_K: + op = "or"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_XOR|BPF_K: + op = "xor"; + (void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_LSH|BPF_K: + op = "lsh"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_RSH|BPF_K: + op = "rsh"; + (void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k); + operand = operand_buf; + break; + + case BPF_ALU|BPF_NEG: + op = "neg"; + operand = ""; + break; + + case BPF_MISC|BPF_TAX: + op = "tax"; + operand = ""; + break; + + case BPF_MISC|BPF_TXA: + op = "txa"; + operand = ""; + break; + } + if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) { + (void)snprintf(image, sizeof image, + "(%03d) %-8s %-16s jt %d\tjf %d", + n, op, operand, n + 1 + p->jt, n + 1 + p->jf); + } else { + (void)snprintf(image, sizeof image, + "(%03d) %-8s %s", + n, op, operand); + } + return image; +} diff --git a/src/libpcap-1.10.5/charconv.c b/src/libpcap-1.10.5/charconv.c new file mode 100644 index 0000000000..98f9023251 --- /dev/null +++ b/src/libpcap-1.10.5/charconv.c @@ -0,0 +1,217 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#include + +#include /* Needed for PCAP_ERRBUF_SIZE */ + +#include "charconv.h" + +wchar_t * +cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags) +{ + int utf16le_len; + wchar_t *utf16le_string; + + /* + * Map from the specified code page to UTF-16LE. + * First, find out how big a buffer we'll need. + */ + utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1, + NULL, 0); + if (utf16le_len == 0) { + /* + * Error. Fail with EINVAL. + */ + errno = EINVAL; + return (NULL); + } + + /* + * Now attempt to allocate a buffer for that. + */ + utf16le_string = malloc(utf16le_len * sizeof (wchar_t)); + if (utf16le_string == NULL) { + /* + * Not enough memory; assume errno has been + * set, and fail. + */ + return (NULL); + } + + /* + * Now convert. + */ + utf16le_len = MultiByteToWideChar(codepage, flags, cp_string, -1, + utf16le_string, utf16le_len); + if (utf16le_len == 0) { + /* + * Error. Fail with EINVAL. + * XXX - should this ever happen, given that + * we already ran the string through + * MultiByteToWideChar() to find out how big + * a buffer we needed? + */ + free(utf16le_string); + errno = EINVAL; + return (NULL); + } + return (utf16le_string); +} + +char * +utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string) +{ + int cp_len; + char *cp_string; + + /* + * Map from UTF-16LE to the specified code page. + * First, find out how big a buffer we'll need. + * We convert composite characters to precomposed characters, + * as that's what Windows expects. + */ + cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK, + utf16le_string, -1, NULL, 0, NULL, NULL); + if (cp_len == 0) { + /* + * Error. Fail with EINVAL. + */ + errno = EINVAL; + return (NULL); + } + + /* + * Now attempt to allocate a buffer for that. + */ + cp_string = malloc(cp_len * sizeof (char)); + if (cp_string == NULL) { + /* + * Not enough memory; assume errno has been + * set, and fail. + */ + return (NULL); + } + + /* + * Now convert. + */ + cp_len = WideCharToMultiByte(codepage, WC_COMPOSITECHECK, + utf16le_string, -1, cp_string, cp_len, NULL, NULL); + if (cp_len == 0) { + /* + * Error. Fail with EINVAL. + * XXX - should this ever happen, given that + * we already ran the string through + * WideCharToMultiByte() to find out how big + * a buffer we needed? + */ + free(cp_string); + errno = EINVAL; + return (NULL); + } + return (cp_string); +} + +/* + * Convert an error message string from UTF-8 to the local code page, as + * best we can. + * + * The buffer is assumed to be PCAP_ERRBUF_SIZE bytes long; we truncate + * if it doesn't fit. + */ +void +utf_8_to_acp_truncated(char *errbuf) +{ + wchar_t *utf_16_errbuf; + int retval; + DWORD err; + + /* + * Do this by converting to UTF-16LE and then to the local + * code page. That means we get to use Microsoft's + * conversion routines, rather than having to understand + * all the code pages ourselves, *and* that this routine + * can convert in place. + */ + + /* + * Map from UTF-8 to UTF-16LE. + * First, find out how big a buffer we'll need. + * Convert any invalid characters to REPLACEMENT CHARACTER. + */ + utf_16_errbuf = cp_to_utf_16le(CP_UTF8, errbuf, 0); + if (utf_16_errbuf == NULL) { + /* + * Error. Give up. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Can't convert error string to the local code page"); + return; + } + + /* + * Now, convert that to the local code page. + * Use the current thread's code page. For unconvertible + * characters, let it pick the "best fit" character. + * + * XXX - we'd like some way to do what utf_16le_to_utf_8_truncated() + * does if the buffer isn't big enough, but we don't want to have + * to handle all local code pages ourselves; doing so requires + * knowledge of all those code pages, including knowledge of how + * characters are formed in those code pages so that we can avoid + * cutting a multi-byte character into pieces. + * + * Converting to an un-truncated string using Windows APIs, and + * then copying to the buffer, still requires knowledge of how + * characters are formed in the target code page. + */ + retval = WideCharToMultiByte(CP_THREAD_ACP, 0, utf_16_errbuf, -1, + errbuf, PCAP_ERRBUF_SIZE, NULL, NULL); + if (retval == 0) { + err = GetLastError(); + free(utf_16_errbuf); + if (err == ERROR_INSUFFICIENT_BUFFER) + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The error string, in the local code page, didn't fit in the buffer"); + else + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Can't convert error string to the local code page"); + return; + } + free(utf_16_errbuf); +} +#endif diff --git a/src/libpcap-1.10.5/charconv.h b/src/libpcap-1.10.5/charconv.h new file mode 100644 index 0000000000..93103d461e --- /dev/null +++ b/src/libpcap-1.10.5/charconv.h @@ -0,0 +1,44 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef charconv_h +#define charconv_h + +#ifdef _WIN32 +extern wchar_t *cp_to_utf_16le(UINT codepage, const char *cp_string, DWORD flags); +extern char *utf_16le_to_cp(UINT codepage, const wchar_t *utf16le_string); +extern void utf_8_to_acp_truncated(char *); +#endif + +#endif /* charconv_h */ diff --git a/src/libpcap-1.10.5/chmod_bpf b/src/libpcap-1.10.5/chmod_bpf new file mode 100755 index 0000000000..946fec37f2 --- /dev/null +++ b/src/libpcap-1.10.5/chmod_bpf @@ -0,0 +1,19 @@ +#! /bin/sh + +# +# Unfortunately, macOS's devfs is based on the old FreeBSD +# one, not the current one, so there's no way to configure it +# to create BPF devices with particular owners or groups. +# This startup item will make it owned by the admin group, +# with permissions rw-rw----, so that anybody in the admin +# group can use programs that capture or send raw packets. +# +# Change this as appropriate for your site, e.g. to make +# it owned by a particular user without changing the permissions, +# so only that user and the super-user can capture or send raw +# packets, or give it the permissions rw-r-----, so that +# only the super-user can send raw packets but anybody in the +# admin group can capture packets. +# +chgrp admin /dev/bpf* +chmod g+rw /dev/bpf* diff --git a/src/libpcap-1.10.5/cmake/Modules/FindAirPcap.cmake b/src/libpcap-1.10.5/cmake/Modules/FindAirPcap.cmake new file mode 100644 index 0000000000..56c71b7bf1 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindAirPcap.cmake @@ -0,0 +1,69 @@ +# +# FindAirPcap +# ========== +# +# Find the AirPcap library and include files. +# +# This module defines the following variables: +# +# AirPcap_INCLUDE_DIR - absolute path to the directory containing airpcap.h. +# +# AirPcap_LIBRARY - relative or absolute path to the AirPcap library to +# link with. An absolute path is will be used if the +# AirPcap library is not located in the compiler's +# default search path. + +# AirPcap_FOUND - TRUE if the AirPcap library *and* header are found. +# +# Hints and Backward Compatibility +# ================================ +# +# To tell this module where to look, a user may set the environment variable +# AirPcap_ROOT to point cmake to the *root* of a directory with include and +# lib subdirectories for airpcap.dll (e.g Airpcap_Devpack). +# Alternatively, AirPcap_ROOT may also be set from the CMake command +# line or GUI (e.g cmake -DAirPcap_ROOT=C:\path\to\airpcap_sdk [...]) +# + +# The 64-bit airpcap.lib is located under /x64 +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level + # directory contains 32-bit libraries; the 64-bit libraries are in the + # Lib/x64 directory. + # + # The only way to *FORCE* CMake to look in the Lib/x64 directory + # without searching in the Lib directory first appears to be to set + # CMAKE_LIBRARY_ARCHITECTURE to "x64". + # + # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to + # the language, e.g., CMAKE__LIBRARY_ARCHITECTURE. So, set the new + # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE + # inherits the correct value. + # + set(CMAKE_C_LIBRARY_ARCHITECTURE "x64") + set(CMAKE_LIBRARY_ARCHITECTURE "x64") +endif() + +# Find the header +find_path(AirPcap_INCLUDE_DIR airpcap.h + PATH_SUFFIXES include +) + +# Find the library +find_library(AirPcap_LIBRARY + NAMES airpcap +) + +# Set AirPcap_FOUND to TRUE if AirPcap_INCLUDE_DIR and AirPcap_LIBRARY are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(AirPcap + DEFAULT_MSG + AirPcap_INCLUDE_DIR + AirPcap_LIBRARY +) + +mark_as_advanced(AirPcap_INCLUDE_DIR AirPcap_LIBRARY) + +set(AirPcap_INCLUDE_DIRS ${AirPcap_INCLUDE_DIR}) +set(AirPcap_LIBRARIES ${AirPcap_LIBRARY}) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindDAG.cmake b/src/libpcap-1.10.5/cmake/Modules/FindDAG.cmake new file mode 100644 index 0000000000..f41b90a249 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindDAG.cmake @@ -0,0 +1,39 @@ +# +# Try to find the Endace DAG library. +# + +# Try to find the header +find_path(DAG_INCLUDE_DIR dagapi.h) + +# +# Try to find the libraries +# +# We assume that if we have libdag we have libdagconf, as they're +# installed at the same time from the same package. +# +find_library(DAG_LIBRARY dag) +find_library(DAGCONF_LIBRARY dagconf) + +# +# Get link information from the _LIBRARY paths. +# +get_link_info_from_library_path(DAG dag) +get_link_info_from_library_path(DAGCONF dagconf) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(DAG + DEFAULT_MSG + DAG_INCLUDE_DIR + DAG_LIBRARY + DAGCONF_LIBRARY +) + +mark_as_advanced( + DAG_INCLUDE_DIR + DAG_LIBRARY + DAGCONF_LIBRARY +) + +set(DAG_INCLUDE_DIRS ${DAG_INCLUDE_DIR}) +set(DAG_LIBRARIES ${DAG_LIBRARY} ${DAGCONF_LIBRARY}) +set(DAG_STATIC_LIBRARIES ${DAG_LIBRARY} ${DAGCONF_LIBRARY}) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindFseeko.cmake b/src/libpcap-1.10.5/cmake/Modules/FindFseeko.cmake new file mode 100644 index 0000000000..ca53a5a614 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindFseeko.cmake @@ -0,0 +1,85 @@ +# CMake support for fseeko +# +# Based on FindLFS.cmake by +# Copyright (C) 2016 Julian Andres Klode . +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# This defines the following variables +# +# FSEEKO_DEFINITIONS - List of definitions to pass to add_definitions() +# FSEEKO_COMPILE_OPTIONS - List of definitions to pass to add_compile_options() +# FSEEKO_LIBRARIES - List of libraries and linker flags +# FSEEKO_FOUND - If there is Large files support +# + +include(CheckCSourceCompiles) +include(FindPackageHandleStandardArgs) +include(CMakePushCheckState) + +# Check for the availability of fseeko() +# The cases handled are: +# +# * Native fseeko() +# * Preprocessor flag -D_LARGEFILE_SOURCE +# +function(_fseeko_check) + set(_fseeko_cppflags) + cmake_push_check_state() + set(CMAKE_REQUIRED_QUIET 1) + set(CMAKE_REQUIRED_DEFINITIONS ${LFS_DEFINITIONS}) + message(STATUS "Looking for native fseeko support") + check_symbol_exists(fseeko stdio.h fseeko_native) + cmake_pop_check_state() + if (fseeko_native) + message(STATUS "Looking for native fseeko support - found") + set(FSEEKO_FOUND TRUE) + else() + message(STATUS "Looking for native fseeko support - not found") + endif() + + if (NOT FSEEKO_FOUND) + # See if it's available with _LARGEFILE_SOURCE. + cmake_push_check_state() + set(CMAKE_REQUIRED_QUIET 1) + set(CMAKE_REQUIRED_DEFINITIONS ${LFS_DEFINITIONS} "-D_LARGEFILE_SOURCE") + check_symbol_exists(fseeko stdio.h fseeko_need_largefile_source) + cmake_pop_check_state() + if (fseeko_need_largefile_source) + message(STATUS "Looking for fseeko support with _LARGEFILE_SOURCE - found") + set(FSEEKO_FOUND TRUE) + set(_fseeko_cppflags "-D_LARGEFILE_SOURCE") + else() + message(STATUS "Looking for fseeko support with _LARGEFILE_SOURCE - not found") + endif() + endif() + + set(FSEEKO_DEFINITIONS ${_fseeko_cppflags} CACHE STRING "Extra definitions for fseeko support") + set(FSEEKO_COMPILE_OPTIONS "" CACHE STRING "Extra compiler options for fseeko support") + set(FSEEKO_LIBRARIES "" CACHE STRING "Extra definitions for fseeko support") + set(FSEEKO_FOUND ${FSEEKO_FOUND} CACHE INTERNAL "Found fseeko") +endfunction() + +if (NOT FSEEKO_FOUND) + _fseeko_check() +endif() + +find_package_handle_standard_args(FSEEKO "Could not find fseeko. Set FSEEKO_DEFINITIONS, FSEEKO_COMPILE_OPTIONS, FSEEKO_LIBRARIES." FSEEKO_FOUND) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindLFS.cmake b/src/libpcap-1.10.5/cmake/Modules/FindLFS.cmake new file mode 100644 index 0000000000..be5f0d4875 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindLFS.cmake @@ -0,0 +1,153 @@ +# CMake support for large files +# +# Copyright (C) 2016 Julian Andres Klode . +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# This defines the following variables +# +# LFS_DEFINITIONS - List of definitions to pass to add_definitions() +# LFS_COMPILE_OPTIONS - List of definitions to pass to add_compile_options() +# LFS_LIBRARIES - List of libraries and linker flags +# LFS_FOUND - If there is Large files support +# + +include(CheckCSourceCompiles) +include(FindPackageHandleStandardArgs) +include(CMakePushCheckState) + +# Test program to check for LFS. Requires that off_t has at least 8 byte large +set(_lfs_test_source + " + #include + typedef char my_static_assert[sizeof(off_t) >= 8 ? 1 : -1]; + int main(void) { return 0; } + " +) + +# Check if the given options are needed +# +# This appends to the variables _lfs_cppflags, _lfs_cflags, and _lfs_ldflags, +# it also sets LFS_FOUND to 1 if it works. +function(_lfs_check_compiler_option var options definitions libraries) + cmake_push_check_state() + set(CMAKE_REQUIRED_QUIET 1) + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${options}) + set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${definitions}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_DEFINITIONS} ${libraries}) + + message(STATUS "Looking for LFS support using ${options} ${definitions} ${libraries}") + check_c_source_compiles("${_lfs_test_source}" ${var}) + cmake_pop_check_state() + + if(${var}) + message(STATUS "Looking for LFS support using ${options} ${definitions} ${libraries} - found") + set(_lfs_cppflags ${_lfs_cppflags} ${definitions} PARENT_SCOPE) + set(_lfs_cflags ${_lfs_cflags} ${options} PARENT_SCOPE) + set(_lfs_ldflags ${_lfs_ldflags} ${libraries} PARENT_SCOPE) + set(LFS_FOUND TRUE PARENT_SCOPE) + else() + message(STATUS "Looking for LFS support using ${options} ${definitions} ${libraries} - not found") + endif() +endfunction() + +# Check for the availability of LFS. +# The cases handled are: +# +# * Native LFS +# * Output of getconf LFS_CFLAGS; getconf LFS_LIBS; getconf LFS_LDFLAGS +# * Preprocessor flag -D_FILE_OFFSET_BITS=64 +# * Preprocessor flag -D_LARGE_FILES +# +function(_lfs_check) + set(_lfs_cflags) + set(_lfs_cppflags) + set(_lfs_ldflags) + set(_lfs_libs) + cmake_push_check_state() + set(CMAKE_REQUIRED_QUIET 1) + message(STATUS "Looking for native LFS support") + check_c_source_compiles("${_lfs_test_source}" lfs_native) + cmake_pop_check_state() + if (lfs_native) + message(STATUS "Looking for native LFS support - found") + set(LFS_FOUND TRUE) + else() + message(STATUS "Looking for native LFS support - not found") + endif() + + if (NOT LFS_FOUND) + # Check using getconf. If getconf fails, don't worry, the check in + # _lfs_check_compiler_option will fail as well. + execute_process(COMMAND getconf LFS_CFLAGS + OUTPUT_VARIABLE _lfs_cflags_raw + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + execute_process(COMMAND getconf LFS_LIBS + OUTPUT_VARIABLE _lfs_libs_tmp + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + execute_process(COMMAND getconf LFS_LDFLAGS + OUTPUT_VARIABLE _lfs_ldflags_tmp + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + + separate_arguments(_lfs_cflags_raw) + separate_arguments(_lfs_ldflags_tmp) + separate_arguments(_lfs_libs_tmp) + + # Move -D flags to the place they are supposed to be + foreach(flag ${_lfs_cflags_raw}) + if (flag MATCHES "-D.*") + list(APPEND _lfs_cppflags_tmp ${flag}) + else() + list(APPEND _lfs_cflags_tmp ${flag}) + endif() + endforeach() + + # Check if the flags we received (if any) produce working LFS support + _lfs_check_compiler_option(lfs_getconf_works + "${_lfs_cflags_tmp}" + "${_lfs_cppflags_tmp}" + "${_lfs_libs_tmp};${_lfs_ldflags_tmp}") + endif() + + if(NOT LFS_FOUND) # IRIX stuff + _lfs_check_compiler_option(lfs_need_n32 "-n32" "" "") + endif() + if(NOT LFS_FOUND) # Linux and friends + _lfs_check_compiler_option(lfs_need_file_offset_bits "" "-D_FILE_OFFSET_BITS=64" "") + endif() + if(NOT LFS_FOUND) # AIX + _lfs_check_compiler_option(lfs_need_large_files "" "-D_LARGE_FILES=1" "") + endif() + + set(LFS_DEFINITIONS ${_lfs_cppflags} CACHE STRING "Extra definitions for large file support") + set(LFS_COMPILE_OPTIONS ${_lfs_cflags} CACHE STRING "Extra definitions for large file support") + set(LFS_LIBRARIES ${_lfs_libs} ${_lfs_ldflags} CACHE STRING "Extra definitions for large file support") + set(LFS_FOUND ${LFS_FOUND} CACHE INTERNAL "Found LFS") +endfunction() + +if (NOT LFS_FOUND) + _lfs_check() +endif() + +find_package_handle_standard_args(LFS "Could not find LFS. Set LFS_DEFINITIONS, LFS_COMPILE_OPTIONS, LFS_LIBRARIES." LFS_FOUND) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindPacket.cmake b/src/libpcap-1.10.5/cmake/Modules/FindPacket.cmake new file mode 100644 index 0000000000..8224cd3f3e --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindPacket.cmake @@ -0,0 +1,109 @@ +# +# Copyright (C) 2017 Ali Abdulkadir . +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sub-license, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# FindPacket +# ========== +# +# Find the Packet library and include files. +# +# This module defines the following variables: +# +# Packet_INCLUDE_DIR - absolute path to the directory containing Packet32.h. +# +# Packet_LIBRARY - relative or absolute path to the Packet library to +# link with. An absolute path is will be used if the +# Packet library is not located in the compiler's +# default search path. + +# Packet_FOUND - TRUE if the Packet library *and* header are found. +# +# Hints and Backward Compatibility +# ================================ +# +# To tell this module where to look, a user may set the environment variable +# Packet_ROOT to point cmake to the *root* of a directory with include and +# lib subdirectories for packet.dll (e.g WpdPack or npcap-sdk). +# Alternatively, Packet_ROOT may also be set from cmake command line or GUI +# (e.g cmake -DPacket_ROOT=C:\path\to\packet [...]) +# + +# The 64-bit Packet.lib is located under /x64 +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # + # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level + # directory contains 32-bit libraries; the 64-bit libraries are in the + # Lib/x64 directory. + # + # The only way to *FORCE* CMake to look in the Lib/x64 directory + # without searching in the Lib directory first appears to be to set + # CMAKE_LIBRARY_ARCHITECTURE to "x64". + # + # In newer versions of CMake, CMAKE_LIBRARY_ARCHITECTURE is set according to + # the language, e.g., CMAKE__LIBRARY_ARCHITECTURE. So, set the new + # variable, CMAKE_C_LIBRARY_ARCHITECTURE, so that CMAKE_LIBRARY_ARCHITECTURE + # inherits the correct value. + # + set(archdetect_c_code " + #ifndef _M_ARM64 + #error Not ARM64 + #endif + int main() { return 0; } + ") + + file(WRITE "${CMAKE_BINARY_DIR}/archdetect.c" "${archdetect_c_code}") + try_compile( + IsArm64 + "${CMAKE_BINARY_DIR}/archdetect" + "${CMAKE_BINARY_DIR}/archdetect.c" + ) + if(IsArm64) + set(CMAKE_C_LIBRARY_ARCHITECTURE "ARM64") + set(CMAKE_LIBRARY_ARCHITECTURE "ARM64") + else() + set(CMAKE_C_LIBRARY_ARCHITECTURE "x64") + set(CMAKE_LIBRARY_ARCHITECTURE "x64") + endif() +endif() + +# Find the header +find_path(Packet_INCLUDE_DIR Packet32.h + PATH_SUFFIXES include Include +) + +# Find the library +find_library(Packet_LIBRARY + NAMES Packet packet +) + +# Set Packet_FOUND to TRUE if Packet_INCLUDE_DIR and Packet_LIBRARY are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Packet + DEFAULT_MSG + Packet_INCLUDE_DIR + Packet_LIBRARY +) + +mark_as_advanced(Packet_INCLUDE_DIR Packet_LIBRARY) + +set(Packet_INCLUDE_DIRS ${Packet_INCLUDE_DIR}) +set(Packet_LIBRARIES ${Packet_LIBRARY}) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindSNF.cmake b/src/libpcap-1.10.5/cmake/Modules/FindSNF.cmake new file mode 100644 index 0000000000..d873b5aa74 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindSNF.cmake @@ -0,0 +1,30 @@ +# +# Try to find the Myricom SNF library. +# + +# Try to find the header +find_path(SNF_INCLUDE_DIR snf.h /opt/snf) + +# Try to find the library +find_library(SNF_LIBRARY snf /opt/snf) + +# +# Get link information from the _LIBRARY paths. +# +get_link_info_from_library_path(SNF snf) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SNF + DEFAULT_MSG + SNF_INCLUDE_DIR + SNF_LIBRARY +) + +mark_as_advanced( + SNF_INCLUDE_DIR + SNF_LIBRARY +) + +set(SNF_INCLUDE_DIRS ${SNF_INCLUDE_DIR}) +set(SNF_LIBRARIES ${SNF_LIBRARY}) +set(SNF_STATIC_LIBRARIES ${SNF_LIBRARY}) diff --git a/src/libpcap-1.10.5/cmake/Modules/FindTC.cmake b/src/libpcap-1.10.5/cmake/Modules/FindTC.cmake new file mode 100644 index 0000000000..bb24c6671a --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/FindTC.cmake @@ -0,0 +1,24 @@ +# +# Try to find the Riverbed TurboCap library. +# + +# Try to find the header +find_path(TC_INCLUDE_DIR TcApi.h) + +# Try to find the library +find_library(TC_LIBRARY TcApi) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TC + DEFAULT_MSG + TC_INCLUDE_DIR + TC_LIBRARY +) + +mark_as_advanced( + TC_INCLUDE_DIR + TC_LIBRARY +) + +set(TC_INCLUDE_DIRS ${TC_INCLUDE_DIR}) +set(TC_LIBRARIES ${TC_LIBRARY}) diff --git a/src/libpcap-1.10.5/cmake/Modules/Finddpdk.cmake b/src/libpcap-1.10.5/cmake/Modules/Finddpdk.cmake new file mode 100644 index 0000000000..13ae0e4a0c --- /dev/null +++ b/src/libpcap-1.10.5/cmake/Modules/Finddpdk.cmake @@ -0,0 +1,118 @@ +# Try to find dpdk +# +# Once done, this will define +# +# dpdk_FOUND +# dpdk_INCLUDE_DIRS +# dpdk_LIBRARIES +# dpdk_STATIC_LIBRARIES +# dpdk_LIBS_STATIC +# dpdk_REQUIRES_PRIVATE +# dpdk_PACKAGE_NAME + +# +# We only try to find DPDK using pkg-config; DPDK is *SO* +# complicated - DPDK 19.02, for example, has about 117(!) +# libraries, and the precise set of libraries required has +# changed over time - so attempting to guess which libraries +# you need, and hardcoding that in an attempt to find the +# libraries without DPDK, rather than relying on DPDK to +# tell you, with a .pc file, what libraries are needed, +# is *EXTREMELY* fragile and has caused some bug reports, +# so we're just not going to do it. +# +# If that causes a problem, the only thing we will do is +# accept an alternative way of finding the appropriate +# library set for the installed version of DPDK that is +# as robust as pkg-config (i.e., it had better work as well +# as pkg-config with *ALL* versions of DPDK that provide a +# libdpdk.pc file). +# +# If dpdk_ROOT is set, add ${dpdk_ROOT}/pkgconfig +# to PKG_CONFIG_PATH, so we look for the .pc file there, +# first. +# +if(PKG_CONFIG_FOUND) + set(save_PKG_CONFIG_PATH $ENV{PKG_CONFIG_PATH}) + if(dpdk_ROOT) + set(ENV{PKG_CONFIG_PATH} "${dpdk_ROOT}/pkgconfig:$ENV{PKG_CONFIG_PATH}") + endif() + pkg_check_modules(dpdk QUIET libdpdk) + if(dpdk_FOUND) + # + # Get link information for DPDK. + # + pkg_get_link_info(dpdk libdpdk) + endif() + set(ENV{PKG_CONFIG_PATH} "${save_PKG_CONFIG_PATH}") +endif() + +mark_as_advanced(dpdk_INCLUDE_DIRS dpdk_LIBRARIES dpdk_STATIC_LIBRARIES dpdk_REQUIRES_PRIVATE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(dpdk DEFAULT_MSG + dpdk_INCLUDE_DIRS + dpdk_LIBRARIES) + +if(dpdk_FOUND) + # + # This depends on CMake support for "imported targets", + # which are not supported until CMake 3.19. + # + # Ubuntu 20.04 provides CMake 3.16.3, so we are *NOT* + # going to require CMake 3.19. If you want to use + # Shiny New Features(TM), wait until all the OSes on + # which a build might conceivably be done, and that + # provide CMake, provide 3.19 or later. + # + # Just don't do this stuff on earlier versions. If that + # breaks something, figure out a way to do it *without* + # "imported targets", and either do this that way, or, + # at least, do it that way on older versions of CMake. + # + # (One good thing about autotools is that only the builders + # of a package, and people doing configure-script development, + # have to care about the autoconf etc. version; you don't + # even need to have autotools installed in order to be able + # to run an autotools-generated configure script, you just + # need an environment UN*Xy enough, and modern enough, to + # run the stuff in the script. + # + # This is *NOT* the case for CMake; not only do you need + # CMake in order to build a package using CMake, you need + # a version recent enough to run the stuff the package's + # CMake files use. + # + # Please keep this in mind when changing any CMake files, + # and keep in mind what versions of CMake come with, for + # example, commonly-used versions of commonly-used + # Linux distributions.) + # + if(NOT CMAKE_VERSION VERSION_LESS 3.19) + if(NOT TARGET dpdk::cflags) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") + set(rte_cflags "-march=core2") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM") + set(rte_cflags "-march=armv7-a") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") + set(rte_cflags "-march=armv8-a+crc") + endif() + add_library(dpdk::cflags INTERFACE IMPORTED) + if (rte_cflags) + set_target_properties(dpdk::cflags PROPERTIES + INTERFACE_COMPILE_OPTIONS "${rte_cflags}") + endif() + endif() + + if(NOT TARGET dpdk::dpdk) + add_library(dpdk::dpdk INTERFACE IMPORTED) + find_package(Threads QUIET) + list(APPEND dpdk_LIBRARIES + Threads::Threads + dpdk::cflags) + set_target_properties(dpdk::dpdk PROPERTIES + INTERFACE_LINK_LIBRARIES "${dpdk_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${dpdk_INCLUDE_DIRS}") + endif() + endif() +endif() diff --git a/src/libpcap-1.10.5/cmake/have_siocglifconf.c b/src/libpcap-1.10.5/cmake/have_siocglifconf.c new file mode 100644 index 0000000000..5a67abc192 --- /dev/null +++ b/src/libpcap-1.10.5/cmake/have_siocglifconf.c @@ -0,0 +1,6 @@ +#include +#include +#include +int main() { + ioctl(0, SIOCGLIFCONF, (char *)0); +} diff --git a/src/libpcap-1.10.5/cmake_uninstall.cmake.in b/src/libpcap-1.10.5/cmake_uninstall.cmake.in new file mode 100644 index 0000000000..2037e36539 --- /dev/null +++ b/src/libpcap-1.10.5/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/src/libpcap-1.10.5/cmakeconfig.h.in b/src/libpcap-1.10.5/cmakeconfig.h.in new file mode 100644 index 0000000000..ae7cf5252d --- /dev/null +++ b/src/libpcap-1.10.5/cmakeconfig.h.in @@ -0,0 +1,360 @@ +/* cmakeconfig.h.in */ + +/* Define to 1 if arpa/inet.h declares `ether_hostton' */ +#cmakedefine ARPA_INET_H_DECLARES_ETHER_HOSTTON 1 + +/* Enable optimizer debugging */ +#cmakedefine BDEBUG 1 + +/* Define to 1 if remote packet capture is to be supported */ +#cmakedefine ENABLE_REMOTE 1 + +/* define if we have the AIX getnetbyname_r() */ +#cmakedefine HAVE_AIX_GETNETBYNAME_R 1 + +/* define if we have the AIX getprotobyname_r() */ +#cmakedefine HAVE_AIX_GETPROTOBYNAME_R 1 + +/* define if you have the AirPcap API */ +#cmakedefine HAVE_AIRPCAP_API 1 + +/* Define to 1 if you have the `asprintf' function. */ +#cmakedefine HAVE_ASPRINTF 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_CONFIG_HAIKUCONFIG_H 1 + +/* define if you have the DAG API */ +#cmakedefine HAVE_DAG_API 1 + +/* define if you have dag_get_erf_types() */ +#cmakedefine HAVE_DAG_GET_ERF_TYPES 1 + +/* define if you have dag_get_stream_erf_types() */ +#cmakedefine HAVE_DAG_GET_STREAM_ERF_TYPES 1 + +/* define if you have large streams capable DAG API */ +#cmakedefine HAVE_DAG_LARGE_STREAMS_API 1 + +/* define if you have vdag_set_device_info() */ +#cmakedefine HAVE_DAG_VDAG 1 + +/* Define to 1 if you have the declaration of `ether_hostton' */ +#cmakedefine HAVE_DECL_ETHER_HOSTTON 1 + +/* Define to 1 if `dl_module_id_1' is a member of `dl_hp_ppa_info_t'. */ +#cmakedefine HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1 1 + +/* Define to 1 if the system has the type `dl_passive_req_t'. */ +#cmakedefine HAVE_DL_PASSIVE_REQ_T 1 + +/* Define to 1 if you have the `ether_hostton' function. */ +#cmakedefine HAVE_ETHER_HOSTTON 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#cmakedefine HAVE_FSEEKO 1 + +/* Define to 1 if you have the `getspnam' function. */ +#cmakedefine HAVE_GETSPNAM 1 + +/* Define to 1 if you have a GNU-style `strerror_r' function. */ +#cmakedefine HAVE_GNU_STRERROR_R 1 + +/* on HP-UX 10.20 or later */ +#cmakedefine HAVE_HPUX10_20_OR_LATER 1 + +/* on HP-UX 9.x */ +#cmakedefine HAVE_HPUX9 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* if libdlpi exists */ +#cmakedefine HAVE_LIBDLPI 1 + +/* if libnl exists */ +#cmakedefine HAVE_LIBNL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_COMPILER_H 1 + +/* define if we have the Linux getnetbyname_r() */ +#cmakedefine HAVE_LINUX_GETNETBYNAME_R 1 + +/* define if we have the Linux getprotobyname_r() */ +#cmakedefine HAVE_LINUX_GETPROTOBYNAME_R 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_NET_TSTAMP_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_USBDEVICE_FS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LINUX_WIRELESS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETPACKET_PACKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_BPF_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_ENET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_IF_MEDIA_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_NIT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_PFILT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NET_RAW_H 1 + +/* Use OpenSSL */ +#cmakedefine HAVE_OPENSSL 1 + +/* if there's an os_proto.h for this platform, to use additional prototypes */ +#cmakedefine HAVE_OS_PROTO_H 1 + +/* Define to 1 if Packet32 API (Npcap driver) is available */ +#cmakedefine HAVE_PACKET32 1 + +/* Define to 1 if NPcap's version.h is available */ +#cmakedefine HAVE_VERSION_H 1 + +/* Define to 1 if you have a POSIX-style `strerror_r' function. */ +#cmakedefine HAVE_POSIX_STRERROR_R 1 + +/* define if you have the Septel API */ +#cmakedefine HAVE_SEPTEL_API 1 + +/* define if you have the Myricom SNF API */ +#cmakedefine HAVE_SNF_API 1 + +/* Define to 1 if you have the `snprintf' function. */ +#cmakedefine HAVE_SNPRINTF 1 + +/* Define to 1 if the system has the type `socklen_t'. */ +#cmakedefine HAVE_SOCKLEN_T 1 + +/* On solaris */ +#cmakedefine HAVE_SOLARIS 1 + +/* target host supports Solaris "any" device */ +#cmakedefine HAVE_SOLARIS_ANY_DEVICE 1 + +/* define if we have the Solaris/IRIX getnetbyname_r() */ +#cmakedefine HAVE_SOLARIS_IRIX_GETNETBYNAME_R 1 + +/* define if we have the Solaris/IRIX getprotobyname_r() */ +#cmakedefine HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcat' function. */ +#cmakedefine HAVE_STRLCAT 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#cmakedefine HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strtok_r' function. */ +#cmakedefine HAVE_STRTOK_R 1 + +/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ +#cmakedefine HAVE_STRUCT_BPF_TIMEVAL 1 + +/* Define to 1 if the system has the type `struct ether_addr'. */ +#cmakedefine HAVE_STRUCT_ETHER_ADDR 1 + +/* Define to 1 if `msg_control' is a member of `struct msghdr'. */ +#cmakedefine HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 + +/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */ +#cmakedefine HAVE_STRUCT_MSGHDR_MSG_FLAGS 1 + +/* Define to 1 if the system has the type `struct rte_ether_addr'. */ +#cmakedefine HAVE_STRUCT_RTE_ETHER_ADDR 1 + +/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */ +#cmakedefine HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 1 + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +#cmakedefine HAVE_STRUCT_SOCKADDR_SA_LEN 1 + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */ +#cmakedefine HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI 1 + +/* Define to 1 if `bRequestType' is a member of `struct + usbdevfs_ctrltransfer'. */ +#cmakedefine HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_BUFMOD_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_DLPI_EXT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_DLPI_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_IOCCOM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_NET_NIT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* define if you have the TurboCap API */ +#cmakedefine HAVE_TC_API 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vasprintf' function. */ +#cmakedefine HAVE_VASPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsyslog' function. */ +#cmakedefine HAVE_VSYSLOG 1 + +/* Define to 1 if you have the `_wcserror_s' function. */ +#cmakedefine HAVE__WCSERROR_S 1 + +/* define if __atomic_load_n is supported by the compiler */ +#cmakedefine HAVE___ATOMIC_LOAD_N 1 + +/* define if __atomic_store_n is supported by the compiler */ +#cmakedefine HAVE___ATOMIC_STORE_N 1 + +/* Define to 1 if you have the `PacketGetTimestampModes' function. */ +#cmakedefine HAVE_PACKET_GET_TIMESTAMP_MODES 1 + +/* Define to 1 if you have the `PacketIsLoopbackAdapter' function. */ +#cmakedefine HAVE_PACKET_IS_LOOPBACK_ADAPTER 1 + +/* IPv6 */ +#cmakedefine INET6 1 + +/* Define to 1 if netinet/ether.h declares `ether_hostton' */ +#cmakedefine NETINET_ETHER_H_DECLARES_ETHER_HOSTTON 1 + +/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ +#cmakedefine NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON 1 + +/* Define to 1 if net/ethernet.h declares `ether_hostton' */ +#cmakedefine NET_ETHERNET_H_DECLARES_ETHER_HOSTTON 1 + +/* do not use protochain */ +#cmakedefine NO_PROTOCHAIN 1 + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT 1 + +/* Define to the DLL-preferred version string of this package. */ +#cmakedefine PACKAGE_VERSION_DLL @PACKAGE_VERSION_DLL@ + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME 1 + +/* Define to the home page for this package. */ +#cmakedefine PACKAGE_URL 1 + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" + +/* target host supports Bluetooth sniffing */ +#cmakedefine PCAP_SUPPORT_BT 1 + +/* target host supports Bluetooth Monitor */ +#cmakedefine PCAP_SUPPORT_BT_MONITOR 1 + +/* support D-Bus sniffing */ +#cmakedefine PCAP_SUPPORT_DBUS 1 + +/* target host supports DPDK */ +#cmakedefine PCAP_SUPPORT_DPDK 1 + +/* target host supports Linux usbmon for USB sniffing */ +#cmakedefine PCAP_SUPPORT_LINUX_USBMON 1 + +/* target host supports netfilter sniffing */ +#cmakedefine PCAP_SUPPORT_NETFILTER 1 + +/* target host supports netmap */ +#cmakedefine PCAP_SUPPORT_NETMAP 1 + +/* target host supports RDMA sniffing */ +#cmakedefine PCAP_SUPPORT_RDMASNIFF 1 + +/* Define to 1 if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS 1 + +/* Define to 1 if strings.h declares `ffs' */ +#cmakedefine STRINGS_H_DECLARES_FFS 1 + +/* Define to 1 if sys/ethernet.h declares `ether_hostton' */ +#cmakedefine SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON 1 + +/* Enable parser debugging */ +#cmakedefine YYDEBUG 1 + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#cmakedefine _FILE_OFFSET_BITS 1 + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#cmakedefine _LARGEFILE_SOURCE 1 + +/* Define for large files, on AIX-style hosts. */ +#cmakedefine _LARGE_FILES 1 + +/* define on AIX to get certain functions */ +#cmakedefine _SUN 1 + +#if 0 +/* on sinix */ +#cmakedefine sinix 1 +#endif diff --git a/src/libpcap-1.10.5/config.guess b/src/libpcap-1.10.5/config.guess new file mode 100755 index 0000000000..f6d217a49f --- /dev/null +++ b/src/libpcap-1.10.5/config.guess @@ -0,0 +1,1812 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2024 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2024-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# +# Please send patches to . + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system '$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2024 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try '$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# Just in case it came from the environment. +GUESS= + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still +# use 'HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case $UNAME_SYSTEM in +Linux|GNU|GNU/*) + LIBC=unknown + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #elif defined(__GLIBC__) + LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif + #endif + #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case $UNAME_VERSION in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + GUESS=$machine-${os}${release}${abi-} + ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; + *:ekkoBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; + *:SolidBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; + macppc:MirBSD:*:*) + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; + *:MirBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; + alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case $ALPHA_CPU_TYPE in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; + Amiga*:UNIX_System_V:4.0:*) + GUESS=m68k-unknown-sysv4 + ;; + *:[Aa]miga[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; + *:[Mm]orph[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-morphos + ;; + *:OS/390:*:*) + GUESS=i370-ibm-openedition + ;; + *:z/VM:*:*) + GUESS=s390-ibm-zvmoe + ;; + *:OS400:*:*) + GUESS=powerpc-ibm-os400 + ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + GUESS=arm-unknown-riscos + ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + GUESS=hppa1.1-hitachi-hiuxmpp + ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; + NILE*:*:*:dcosx) + GUESS=pyramid-pyramid-svr4 + ;; + DRS?6000:unix:4.0:6*) + GUESS=sparc-icl-nx6 + ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; + s390x:SunOS:*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; + sun4H:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; + sun4*:SunOS:*:*) + case `/usr/bin/arch -k` in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like '4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; + sun3*:SunOS:*:*) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in + sun3) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun4) + GUESS=sparc-sun-sunos$UNAME_RELEASE + ;; + esac + ;; + aushp:SunOS:*:*) + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; + m68k:machten:*:*) + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; + powerpc:machten:*:*) + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; + RISC*:Mach:*:*) + GUESS=mips-dec-mach_bsd4.3 + ;; + RISC*:ULTRIX:*:*) + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; + VAX*:ULTRIX*:*:*) + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; + Motorola:PowerMAX_OS:*:*) + GUESS=powerpc-motorola-powermax + ;; + Motorola:*:4.3:PL8-*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:Power_UNIX:*:*) + GUESS=powerpc-harris-powerunix + ;; + m88k:CX/UX:7*:*) + GUESS=m88k-harris-cxux7 + ;; + m88k:*:4*:R4*) + GUESS=m88k-motorola-sysv4 + ;; + m88k:*:3*:R3*) + GUESS=m88k-motorola-sysv3 + ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 + then + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x + then + GUESS=m88k-dg-dgux$UNAME_RELEASE + else + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE + fi + else + GUESS=i586-dg-dgux$UNAME_RELEASE + fi + ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + GUESS=m88k-dolphin-sysv3 + ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + GUESS=m88k-motorola-sysv3 + ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + GUESS=m88k-tektronix-sysv3 + ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + GUESS=m68k-tektronix-bsd + ;; + *:IRIX*:*:*) + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + GUESS=i386-ibm-aix + ;; + ia64:AIX:*:*) + if test -x /usr/bin/oslevel ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + GUESS=$SYSTEM_NAME + else + GUESS=rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + GUESS=rs6000-ibm-aix3.2.4 + else + GUESS=rs6000-ibm-aix3.2 + fi + ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; + *:AIX:*:*) + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + GUESS=rs6000-bull-bosx + ;; + DPX/2?00:B.O.S.:*:*) + GUESS=m68k-bull-sysv3 + ;; + 9000/[34]??:4.3bsd:1.*:*) + GUESS=m68k-hp-bsd + ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + GUESS=m68k-hp-bsd4.4 + ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if test -x /usr/bin/getconf; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case $sc_cpu_version in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case $sc_kernel_bits in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if test "$HP_ARCH" = hppa2.0w + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; + 9000/8??:4.3bsd:*:*) + GUESS=hppa1.0-hp-bsd + ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; + hp8??:OSF1:*:*) + GUESS=hppa1.0-hp-osf + ;; + i*86:OSF1:*:*) + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk + else + GUESS=$UNAME_MACHINE-unknown-osf1 + fi + ;; + parisc*:Lites*:*:*) + GUESS=hppa1.1-hp-lites + ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + GUESS=c1-convex-bsd + ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + GUESS=c34-convex-bsd + ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + GUESS=c38-convex-bsd + ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + GUESS=c4-convex-bsd + ;; + CRAY*Y-MP:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; + CRAY*T3E:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; + CRAY*SV1:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; + *:UNICOS/mp:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; + sparc*:BSD/OS:*:*) + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; + *:BSD/OS:*:*) + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; + i*:CYGWIN*:*) + GUESS=$UNAME_MACHINE-pc-cygwin + ;; + *:MINGW64*:*) + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; + *:MINGW*:*) + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) + GUESS=i586-pc-interix$UNAME_RELEASE + ;; + authenticamd | genuineintel | EM64T) + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; + IA64) + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; + esac ;; + i*:UWIN*:*) + GUESS=$UNAME_MACHINE-pc-uwin + ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + GUESS=x86_64-pc-cygwin + ;; + prep*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; + *:GNU:*:*) + # the GNU system + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __ARM_EABI__ + #ifdef __ARM_PCS_VFP + ABI=eabihf + #else + ABI=eabi + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; + esac + fi + GUESS=$CPU-unknown-linux-$LIBCABI + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi + else + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf + fi + fi + ;; + avr32*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + cris:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + crisv32:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + frv:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + hexagon:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:Linux:*:*) + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; + ia64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:cos:*:*) + GUESS=$UNAME_MACHINE-unknown-cos + ;; + kvx:mbr:*:*) + GUESS=$UNAME_MACHINE-unknown-mbr + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m68*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + padre:Linux:*:*) + GUESS=sparc-unknown-linux-$LIBC + ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + GUESS=hppa64-unknown-linux-$LIBC + ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; + esac + ;; + ppc64:Linux:*:*) + GUESS=powerpc64-unknown-linux-$LIBC + ;; + ppc:Linux:*:*) + GUESS=powerpc-unknown-linux-$LIBC + ;; + ppc64le:Linux:*:*) + GUESS=powerpc64le-unknown-linux-$LIBC + ;; + ppcle:Linux:*:*) + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + s390:Linux:*:* | s390x:Linux:*:*) + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; + sh64*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sh*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + tile*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + vax:Linux:*:*) + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; + x86_64:Linux:*:*) + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac + fi + GUESS=$CPU-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + GUESS=i386-sequent-sysv4 + ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) + # If we were able to find 'uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; + i*86:XTS-300:*:STOP) + GUESS=$UNAME_MACHINE-unknown-stop + ;; + i*86:atheos:*:*) + GUESS=$UNAME_MACHINE-unknown-atheos + ;; + i*86:syllable:*:*) + GUESS=$UNAME_MACHINE-pc-syllable + ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; + i*86:*DOS:*:*) + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL + fi + ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv32 + fi + ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + GUESS=i586-pc-msdosdjgpp + ;; + Intel:Mach:3*:*) + GUESS=i386-pc-mach3 + ;; + paragon:*:*:*) + GUESS=i860-intel-osf1 + ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 + fi + ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + GUESS=m68010-convergent-sysv + ;; + mc68k:UNIX:SYSTEM5:3.51m) + GUESS=m68k-convergent-sysv + ;; + M680?0:D-NIX:5.3:*) + GUESS=m68k-diab-dnix + ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; + mc68030:UNIX_System_V:4.*:*) + GUESS=m68k-atari-sysv4 + ;; + TSUNAMI:LynxOS:2.*:*) + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; + rs6000:LynxOS:2.*:*) + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; + SM[BE]S:UNIX_SV:*:*) + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; + RM*:ReliantUNIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + RM*:SINIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 + else + GUESS=ns32k-sni-sysv + fi + ;; + PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort + # says + GUESS=i586-unisys-sysv4 + ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + GUESS=hppa1.1-stratus-sysv4 + ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + GUESS=i860-stratus-sysv4 + ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=$UNAME_MACHINE-stratus-vos + ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=hppa1.1-stratus-vos + ;; + mc68*:A/UX:*:*) + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; + news*:NEWS-OS:6*:*) + GUESS=mips-sony-newsos6 + ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE + else + GUESS=mips-unknown-sysv$UNAME_RELEASE + fi + ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + GUESS=powerpc-be-beos + ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + GUESS=powerpc-apple-beos + ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + GUESS=i586-pc-beos + ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; + SX-5:SUPER-UX:*:*) + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; + SX-6:SUPER-UX:*:*) + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; + SX-7:SUPER-UX:*:*) + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; + SX-8:SUPER-UX:*:*) + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; + SX-8R:SUPER-UX:*:*) + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; + Power*:Rhapsody:*:*) + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; + *:Rhapsody:*:*) + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; + *:QNX:*:4*) + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; + NSE-*:NONSTOP_KERNEL:*:*) + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; + *:NonStop-UX:*:*) + GUESS=mips-compaq-nonstopux + ;; + BS2000:POSIX*:*:*) + GUESS=bs2000-siemens-sysv + ;; + DS/*:UNIX_System_V:*:*) + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "${cputype-}" = 386; then + UNAME_MACHINE=i386 + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype + fi + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; + *:TOPS-10:*:*) + GUESS=pdp10-unknown-tops10 + ;; + *:TENEX:*:*) + GUESS=pdp10-unknown-tenex + ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + GUESS=pdp10-dec-tops20 + ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + GUESS=pdp10-xkl-tops20 + ;; + *:TOPS-20:*:*) + GUESS=pdp10-unknown-tops20 + ;; + *:ITS:*:*) + GUESS=pdp10-unknown-its + ;; + SEI:*:*:SEIUX) + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; + *:DragonFly:*:*) + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; + esac ;; + *:XENIX:*:SysV) + GUESS=i386-pc-xenix + ;; + i*86:skyos:*:*) + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; + x86_64:VMkernel:*:*) + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/src/libpcap-1.10.5/config.h.in b/src/libpcap-1.10.5/config.h.in new file mode 100644 index 0000000000..fbc49c1d15 --- /dev/null +++ b/src/libpcap-1.10.5/config.h.in @@ -0,0 +1,368 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if arpa/inet.h declares `ether_hostton' */ +#undef ARPA_INET_H_DECLARES_ETHER_HOSTTON + +/* Enable optimizer debugging */ +#undef BDEBUG + +/* define if you want to build the instrument functions code */ +#undef ENABLE_INSTRUMENT_FUNCTIONS + +/* Define to 1 if remote packet capture is to be supported */ +#undef ENABLE_REMOTE + +/* define if we have the AIX getnetbyname_r() */ +#undef HAVE_AIX_GETNETBYNAME_R + +/* define if we have the AIX getprotobyname_r() */ +#undef HAVE_AIX_GETPROTOBYNAME_R + +/* Define to 1 if you have the `asprintf' function. */ +#undef HAVE_ASPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_CONFIG_HAIKUCONFIG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DAGAPI_H + +/* define if you have the DAG API */ +#undef HAVE_DAG_API + +/* define if you have dag_get_erf_types() */ +#undef HAVE_DAG_GET_ERF_TYPES + +/* define if you have dag_get_stream_erf_types() */ +#undef HAVE_DAG_GET_STREAM_ERF_TYPES + +/* define if you have large streams capable DAG API */ +#undef HAVE_DAG_LARGE_STREAMS_API + +/* define if you have vdag_set_device_info() */ +#undef HAVE_DAG_VDAG + +/* Define to 1 if you have the declaration of `ether_hostton' */ +#undef HAVE_DECL_ETHER_HOSTTON + +/* Define to 1 if `dl_module_id_1' is a member of `dl_hp_ppa_info_t'. */ +#undef HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1 + +/* Define to 1 if the system has the type `dl_passive_req_t'. */ +#undef HAVE_DL_PASSIVE_REQ_T + +/* Define to 1 if you have the `ether_hostton' function. */ +#undef HAVE_ETHER_HOSTTON + +/* Define to 1 if you have the `ffs' function. */ +#undef HAVE_FFS + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#undef HAVE_FSEEKO + +/* Define to 1 if you have the `getspnam' function. */ +#undef HAVE_GETSPNAM + +/* Define to 1 if you have a GNU-style `strerror_r' function. */ +#undef HAVE_GNU_STRERROR_R + +/* on HP-UX 10.20 or later */ +#undef HAVE_HPUX10_20_OR_LATER + +/* on HP-UX 9.x */ +#undef HAVE_HPUX9 + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `bsd' library (-lbsd). */ +#undef HAVE_LIBBSD + +/* if libdlpi exists */ +#undef HAVE_LIBDLPI + +/* if libnl exists */ +#undef HAVE_LIBNL + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_COMPILER_H + +/* define if we have the Linux getnetbyname_r() */ +#undef HAVE_LINUX_GETNETBYNAME_R + +/* define if we have the Linux getprotobyname_r() */ +#undef HAVE_LINUX_GETPROTOBYNAME_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_NET_TSTAMP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_USBDEVICE_FS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_WIRELESS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETPACKET_PACKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_BPF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_ENET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_DL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_MEDIA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_NIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_PFILT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_RAW_H + +/* Use OpenSSL */ +#undef HAVE_OPENSSL + +/* if there's an os_proto.h for this platform, to use additional prototypes */ +#undef HAVE_OS_PROTO_H + +/* Define to 1 if you have a POSIX-style `strerror_r' function. */ +#undef HAVE_POSIX_STRERROR_R + +/* define if you have the Septel API */ +#undef HAVE_SEPTEL_API + +/* define if you have the Myricom SNF API */ +#undef HAVE_SNF_API + +/* Define to 1 if the system has the type `socklen_t'. */ +#undef HAVE_SOCKLEN_T + +/* On solaris */ +#undef HAVE_SOLARIS + +/* target host supports Solaris "any" device */ +#undef HAVE_SOLARIS_ANY_DEVICE + +/* define if we have the Solaris/IRIX getnetbyname_r() */ +#undef HAVE_SOLARIS_IRIX_GETNETBYNAME_R + +/* define if we have the Solaris/IRIX getprotobyname_r() */ +#undef HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strtok_r' function. */ +#undef HAVE_STRTOK_R + +/* Define to 1 if the system has the type `struct BPF_TIMEVAL'. */ +#undef HAVE_STRUCT_BPF_TIMEVAL + +/* Define to 1 if the system has the type `struct ether_addr'. */ +#undef HAVE_STRUCT_ETHER_ADDR + +/* Define to 1 if `msg_control' is a member of `struct msghdr'. */ +#undef HAVE_STRUCT_MSGHDR_MSG_CONTROL + +/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */ +#undef HAVE_STRUCT_MSGHDR_MSG_FLAGS + +/* Define to 1 if the system has the type `struct rte_ether_addr'. */ +#undef HAVE_STRUCT_RTE_ETHER_ADDR + +/* Define to 1 if `hci_channel' is a member of `struct sockaddr_hci'. */ +#undef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +#undef HAVE_STRUCT_SOCKADDR_SA_LEN + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE + +/* Define to 1 if `tp_vlan_tci' is a member of `struct tpacket_auxdata'. */ +#undef HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI + +/* Define to 1 if `bRequestType' is a member of `struct + usbdevfs_ctrltransfer'. */ +#undef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BUFMOD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DLPI_EXT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DLPI_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCCOM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_NET_NIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* define if you have the TurboCap API */ +#undef HAVE_TC_API + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to 1 if you have the `_wcserror_s' function. */ +#undef HAVE__WCSERROR_S + +/* define if __atomic_load_n is supported by the compiler */ +#undef HAVE___ATOMIC_LOAD_N + +/* define if __atomic_store_n is supported by the compiler */ +#undef HAVE___ATOMIC_STORE_N + +/* IPv6 */ +#undef INET6 + +/* Define to 1 if netinet/ether.h declares `ether_hostton' */ +#undef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON + +/* Define to 1 if netinet/if_ether.h declares `ether_hostton' */ +#undef NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON + +/* Define to 1 if net/ethernet.h declares `ether_hostton' */ +#undef NET_ETHERNET_H_DECLARES_ETHER_HOSTTON + +/* do not use protochain */ +#undef NO_PROTOCHAIN + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* target host supports Bluetooth sniffing */ +#undef PCAP_SUPPORT_BT + +/* target host supports Bluetooth Monitor */ +#undef PCAP_SUPPORT_BT_MONITOR + +/* support D-Bus sniffing */ +#undef PCAP_SUPPORT_DBUS + +/* target host supports DPDK */ +#undef PCAP_SUPPORT_DPDK + +/* target host supports Linux usbmon for USB sniffing */ +#undef PCAP_SUPPORT_LINUX_USBMON + +/* target host supports netfilter sniffing */ +#undef PCAP_SUPPORT_NETFILTER + +/* target host supports netmap */ +#undef PCAP_SUPPORT_NETMAP + +/* target host supports RDMA sniffing */ +#undef PCAP_SUPPORT_RDMASNIFF + +/* The size of `time_t', as computed by sizeof. */ +#undef SIZEOF_TIME_T + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* Define to 1 if strings.h declares `ffs' */ +#undef STRINGS_H_DECLARES_FFS + +/* Define to 1 if sys/ethernet.h declares `ether_hostton' */ +#undef SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON + +/* Enable parser debugging */ +#undef YYDEBUG + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#undef _LARGEFILE_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* define on AIX to get certain functions */ +#undef _SUN + +/* to handle Ultrix compilers that don't support const in prototypes */ +#undef const + +/* Define as token for inline if inlining supported */ +#undef inline + +/* on sinix */ +#undef sinix diff --git a/src/libpcap-1.10.5/config.sub b/src/libpcap-1.10.5/config.sub new file mode 100755 index 0000000000..2c6a07ab3c --- /dev/null +++ b/src/libpcap-1.10.5/config.sub @@ -0,0 +1,1971 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2024 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2024-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2024 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try '$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ + | windows-* ) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x"$basic_os" != x +then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +obj= +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 + fi + ;; + *) + echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 + exit 1 + ;; +esac + +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; + *) + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os-$obj in + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- ) + ;; + uclinux-uclibc*- ) + ;; + managarm-mlibc*- | managarm-kernel*- ) + ;; + windows*-msvc*-) + ;; + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 + exit 1 + ;; + -kernel*- ) + echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 + exit 1 + ;; + *-kernel*- ) + echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 + exit 1 + ;; + *-msvc*- ) + echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 + exit 1 + ;; + kfreebsd*-gnu*- | kopensolaris*-gnu*-) + ;; + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) + ;; + nto-qnx*-) + ;; + os2-emx-) + ;; + *-eabi*- | *-gnueabi*-) + ;; + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format + ;; + -*-) + # Blank kernel with real OS is always fine. + ;; + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) + echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-aix*) + vendor=ibm + ;; + *-beos*) + vendor=be + ;; + *-hpux*) + vendor=hp + ;; + *-mpeix*) + vendor=hp + ;; + *-hiux*) + vendor=hitachi + ;; + *-unos*) + vendor=crds + ;; + *-dgux*) + vendor=dg + ;; + *-luna*) + vendor=omron + ;; + *-genix*) + vendor=ns + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) + vendor=sequent + ;; + *-tpf*) + vendor=ibm + ;; + *-vxsim* | *-vxworks* | *-windiss*) + vendor=wrs + ;; + *-aux*) + vendor=apple + ;; + *-hms*) + vendor=hitachi + ;; + *-mpw* | *-macos*) + vendor=apple + ;; + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) + vendor=atari + ;; + *-vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/src/libpcap-1.10.5/configure b/src/libpcap-1.10.5/configure new file mode 100755 index 0000000000..61fcd037a0 --- /dev/null +++ b/src/libpcap-1.10.5/configure @@ -0,0 +1,15281 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.71 for pcap 1.10.5. +# +# +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else $as_nop + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + +# The user is always right. +if ${PATH_SEPARATOR+false} :; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else \$as_nop + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : + +else \$as_nop + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null +then : + as_have_required=yes +else $as_nop + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : + +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$as_shell as_have_required=yes + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : + break 2 +fi +fi + done;; + esac + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi + + + if test "x$CONFIG_SHELL" != x +then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." + else + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else $as_nop + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else $as_nop + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='pcap' +PACKAGE_TARNAME='pcap' +PACKAGE_VERSION='1.10.5' +PACKAGE_STRING='pcap 1.10.5' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="pcap.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_STDIO_H +# include +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_header_c_list= +ac_subst_vars='LTLIBOBJS +RPCAPD_LIBS +INSTALL_RPCAPD +BUILD_RPCAPD +PTHREAD_LIBS +REMOTE_C_SRC +MODULE_C_SRC +PLATFORM_C_SRC +ADDLARCHIVEOBJS +ADDLOBJS +RPATH +V_SONAME_OPT +V_SHLIB_OPT +V_SHLIB_CMD +V_SHLIB_CCOPT +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +PCAP_SUPPORT_RDMASNIFF +LIBIBVERBS_LIBS_STATIC +LIBIBVERBS_LIBS +LIBIBVERBS_CFLAGS +PCAP_SUPPORT_DBUS +DBUS_LIBS_STATIC +DBUS_LIBS +DBUS_CFLAGS +PCAP_SUPPORT_BT +PCAP_SUPPORT_DPDK +DPDK_LIBS_STATIC +DPDK_LIBS +DPDK_CFLAGS +PCAP_SUPPORT_NETMAP +PCAP_SUPPORT_NETFILTER +PCAP_SUPPORT_LINUX_USBMON +MKDEP +DEPENDENCY_CFLAG +LN_S +AR +RANLIB +MAN_ADMIN_COMMANDS +MAN_MISC_INFO +MAN_FILE_FORMATS +MAN_DEVICES +DYEXT +V_PROG_LDFLAGS_FAT +V_PROG_CCOPT_FAT +V_LIB_LDFLAGS_FAT +V_LIB_CCOPT_FAT +REENTRANT_PARSER +BISON_BYACC +LEXLIB +LEX_OUTPUT_ROOT +LEX +OPENSSL_LIBS_STATIC +OPENSSL_LIBS +OPENSSL_CFLAGS +LIBNL_LIBS_STATIC +LIBNL_LIBS +LIBNL_CFLAGS +BREW +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +VALGRINDTEST_SRC +LIBOBJS +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +SHLICC2 +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBS_PRIVATE +REQUIRES_PRIVATE +LIBS_STATIC +V_INCLS +V_DEFS +V_CCOPT +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_gcc +enable_largefile +enable_instrument_functions +enable_protochain +with_pcap +with_libnl +enable_ipv6 +with_dag +with_dag_includes +with_dag_libraries +with_septel +with_snf +with_snf_includes +with_snf_libraries +with_turbocap +enable_remote +enable_optimizer_dbg +enable_yydebug +enable_universal +enable_shared +enable_usb +enable_netmap +with_dpdk +enable_bluetooth +enable_dbus +enable_rdma +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +LIBNL_CFLAGS +LIBNL_LIBS +LIBNL_LIBS_STATIC +OPENSSL_CFLAGS +OPENSSL_LIBS +OPENSSL_LIBS_STATIC +DPDK_CFLAGS +DPDK_LIBS +DPDK_LIBS_STATIC +DBUS_CFLAGS +DBUS_LIBS +DBUS_LIBS_STATIC +LIBIBVERBS_CFLAGS +LIBIBVERBS_LIBS +LIBIBVERBS_LIBS_STATIC' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: \`$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures pcap 1.10.5 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/pcap] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of pcap 1.10.5:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files + --enable-instrument-functions + enable instrument functions code [default=no] + --disable-protochain disable \"protochain\" insn + --enable-ipv6 build IPv6-capable version [default=yes] + --enable-remote enable remote packet capture [default=no] + --enable-optimizer-dbg build optimizer debugging code + --enable-yydebug build parser debugging code + --disable-universal don't build universal on macOS + --enable-shared build shared libraries [default=yes, if support + available] + --enable-usb enable Linux usbmon USB capture support + [default=yes, if support available] + --enable-netmap enable netmap support [default=yes, if support + available] + --enable-bluetooth enable Bluetooth support [default=yes, if support + available] + --enable-dbus enable D-Bus capture support [default=yes, if + support available] + --enable-rdma enable RDMA capture support [default=yes, if support + available] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-gcc don't use gcc + --with-pcap=TYPE use packet capture TYPE + --without-libnl disable libnl support [default=yes, on Linux, if + present] + --with-dag[=DIR] include Endace DAG support (located in directory + DIR, if supplied). [default=yes, if present] + --with-dag-includes=IDIR + Endace DAG include directory, if not DIR/include + --with-dag-libraries=LDIR + Endace DAG library directory, if not DIR/lib + --with-septel[=DIR] include Septel support (located in directory DIR, if + supplied). [default=yes, if present] + --with-snf[=DIR] include Myricom SNF support (located in directory + DIR, if supplied). [default=yes, if present] + --with-snf-includes=IDIR + Myricom SNF include directory, if not DIR/include + --with-snf-libraries=LDIR + Myricom SNF library directory, if not DIR/lib + --with-turbocap[=DIR] include Riverbed TurboCap support (located in + directory DIR, if supplied). [default=yes, if + present] + --with-dpdk[=DIR] include DPDK support (located in directory DIR, if + supplied). [default=yes, if present] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + LIBNL_CFLAGS + C compiler flags for libnl-genl-3.0, overriding pkg-config + LIBNL_LIBS linker flags for libnl-genl-3.0, overriding pkg-config + LIBNL_LIBS_STATIC + static-link linker flags for libnl-genl-3.0, overriding + pkg-config + OPENSSL_CFLAGS + C compiler flags for openssl, overriding pkg-config + OPENSSL_LIBS + linker flags for openssl, overriding pkg-config + OPENSSL_LIBS_STATIC + static-link linker flags for openssl, overriding pkg-config + DPDK_CFLAGS C compiler flags for libdpdk, overriding pkg-config + DPDK_LIBS linker flags for libdpdk, overriding pkg-config + DPDK_LIBS_STATIC + static-link linker flags for libdpdk, overriding pkg-config + DBUS_CFLAGS C compiler flags for dbus-1, overriding pkg-config + DBUS_LIBS linker flags for dbus-1, overriding pkg-config + DBUS_LIBS_STATIC + static-link linker flags for dbus-1, overriding pkg-config + LIBIBVERBS_CFLAGS + C compiler flags for libibverbs, overriding pkg-config + LIBIBVERBS_LIBS + linker flags for libibverbs, overriding pkg-config + LIBIBVERBS_LIBS_STATIC + static-link linker flags for libibverbs, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +pcap configure 1.10.5 +generated by GNU Autoconf 2.71 + +Copyright (C) 2021 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_hi=$ac_mid; break +else $as_nop + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_lo=$ac_mid; break +else $as_nop + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done +else $as_nop + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_hi=$ac_mid +else $as_nop + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } +#include +#include +int +main (void) +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO" +then : + echo >>conftest.val; read $3 &5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. */ + +#include +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main (void) +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR +# ------------------------------------------------------------------ +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. +ac_fn_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +printf %s "checking whether $as_decl_name is declared... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS + +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_check_decl + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main (void) +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$4=yes" +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main (void) +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$4=yes" +else $as_nop + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$4 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by pcap $as_me 1.10.5, which was +generated by GNU Autoconf 2.71. Invocation command line was + + $ $0$ac_configure_args_raw + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" + # Save into config.log some information that might help in debugging. + { + echo + + printf "%s\n" "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + printf "%s\n" "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + printf "%s\n" "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + printf "%s\n" "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +printf "%s\n" "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + ac_site_files="$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" +else + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" +fi + +for ac_site_file in $ac_site_files +do + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +# +# These are the variables that are used in Makefile, pcap-config, and +# libpcap.pc. +# +# CFLAGS: inherited from the environment, not modified by us except +# for flags required for the platform for which we're building (and +# except temporarily during tests that involve compilation). Used only +# when compiling C source. +# +# LDFLAGS: inherited from the environment, not modified by us. +# +# LIBS: inherited from the environment; we add libraries required by +# libpcap. Libraries that the core libpcap code requires are added +# first; libraries required by additional pcap modules are first +# added to ADDITIONAL_LIBS, and only added to LIBS at the end, after +# we're finished doing configuration tests for the modules. +# +# LIBS_STATIC: libraries with which a program using the libpcap *static* +# library needs to be linked. This is a superset of LIBS, used in +# pcap-config, so that "pcap-config --libs --static" will report them. +# Initialized to LIBS. +# +# REQUIRES_PRIVATE: pkg-config package names for additional libraries +# with which a program using the libpcap *static* library needs to be +# linked and for which a .pc file exists. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them, and so that +# those libraries will be determined using the library's .pc file, not +# from our .pc file. Initialized to an empty string. +# +# V_CCOPT: additional compiler flags other than -I and -D flags +# needed when compiling libpcap. Used in Makefile for both C and +# C++ source. +# +# V_DEFS: additional -D compiler flags needed when compiling +# libpcap. Used in Makefile for both C and C++ source. +# +# V_INCLS: additional -I compiler flags needed when compiling +# libpcap. Used in Makefile for both C and C++ source. +# +# ADDITIONAL_LIBS: additional libraries with which the libpcap dynamic +# library needs to be linked. Used in Makefile; not used in pcap-config +# or libpcap.pc, as, in all platforms on which we run, if a dynamic +# library is linked with other dynamic libraries, a program using +# that dynamic library doesn't have to link with those libraries - +# they will be automatically loaded at run time. Initialized to an +# empty string. +# +# ADDITIONAL_LIBS_STATIC: additional libraries with which a program +# using the libpcap *static* library needs to be linked. This is used +# in pcap-config, so that "pcap-config --libs --static" will report +# them. Initialized to an empty string. +# +# REQUIRES_PRIVATE: pkg-config package names for additional libraries +# with which a program using the libpcap *static* library needs to be +# linked and for which a .pc file exists. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them, and so that +# those libraries will be determined using the library's .pc file, not +# from our .pc file. Initialized to an empty string. +# +# LIBS_PRIVATE: pkg-config package names for additional libraries with +# which a program using the libpcap *static* library needs to be linked +# and for which a .pc file does not exist. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them (those libraries +# cannot be determined using the library's .pc file, as there is no such +# file, so it has to come from our .pc file. Initialized to an empty +# string. +# +LIBS_STATIC="" +REQUIRES_PRIVATE="" +LIBS_PRIVATE="" + + + + + + + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + + + + + + +# Check whether --with-gcc was given. +if test ${with_gcc+y} +then : + withval=$with_gcc; +fi + + V_CCOPT="" + if test "${srcdir}" != "." ; then + V_CCOPT="-I\$(srcdir)" + fi + if test "${CFLAGS+set}" = set; then + LBL_CFLAGS="$CFLAGS" + fi + if test -z "$CC" ; then + case "$host_os" in + + bsdi*) + # Extract the first word of "shlicc2", so it can be a program name with args. +set dummy shlicc2; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_SHLICC2+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$SHLICC2"; then + ac_cv_prog_SHLICC2="$SHLICC2" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_SHLICC2="yes" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_SHLICC2" && ac_cv_prog_SHLICC2="no" +fi +fi +SHLICC2=$ac_cv_prog_SHLICC2 +if test -n "$SHLICC2"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SHLICC2" >&5 +printf "%s\n" "$SHLICC2" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test $SHLICC2 = yes ; then + CC=shlicc2 + export CC + fi + ;; + esac + fi + if test -z "$CC" -a "$with_gcc" = no ; then + CC=cc + export CC + fi + +# +# We require C99 or later. +# Try to get it, which may involve adding compiler flags; +# if that fails, give up. +# + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion -version; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else $as_nop + ac_file='' +fi +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_compiler_gnu=yes +else $as_nop + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+y} +ac_save_CFLAGS=$CFLAGS +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +else $as_nop + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +if test "$ac_cv_prog_cc_c99" = "no"; then + as_fn_error $? "The C compiler does not support C99" "$LINENO" 5 +fi + +# +# Get the size of a void *, to determine whether this is a 32-bit +# or 64-bit build. +# + +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop + if test "$ac_cv_type_void_p" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 + fi +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } + + + +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h + + +ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" + +# +# Get the size of a time_t, to know whether it's 32-bit or 64-bit. +# +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 +printf %s "checking size of time_t... " >&6; } +if test ${ac_cv_sizeof_time_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "#include +" +then : + +else $as_nop + if test "$ac_cv_type_time_t" = yes; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (time_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_time_t=0 + fi +fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 +printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } + + + +printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h + + + + + + + + if test "$GCC" = yes ; then + # + # -Werror forces warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -fvisibility=hidden option" >&5 +printf %s "checking whether the compiler supports the -fvisibility=hidden option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 +printf %s "checking whether -fvisibility=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -fvisibility=hidden" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + else + V_INCLS="$V_INCLS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + + case "$host_os" in + + darwin*) + # + # This is assumed either to be GCC or clang, both + # of which use -Werror to force warnings to be errors. + # + ac_lbl_cc_force_warning_errors=-Werror + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -fvisibility=hidden option" >&5 +printf %s "checking whether the compiler supports the -fvisibility=hidden option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fvisibility=hidden" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -fvisibility=hidden " >&5 +printf %s "checking whether -fvisibility=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -fvisibility=hidden" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + ;; + + hpux*) + # + # HP C, which is what we presume we're using, doesn't + # exit with a non-zero exit status if we hand it an + # invalid -W flag, can't be forced to do so even with + # +We, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + ;; + + irix*) + # + # MIPS C, which is what we presume we're using, doesn't + # necessarily exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # It also, apparently, defaults to "char" being + # unsigned, unlike most other C implementations; + # I suppose we could say "signed char" whenever + # we want to guarantee a signed "char", but let's + # just force signed chars. + # + # -xansi is normally the default, but the + # configure script was setting it; perhaps -cckr + # was the default in the Old Days. (Then again, + # that would probably be for backwards compatibility + # in the days when ANSI C was Shiny and New, i.e. + # 1989 and the early '90's, so maybe we can just + # drop support for those compilers.) + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + V_CCOPT="$V_CCOPT -xansi -signed -g3" + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + # The DEC C compiler, which is what we presume we're + # using, doesn't exit with a non-zero exit status if we + # hand it an invalid -W flag, can't be forced to do + # so, and doesn't handle GCC-style -W flags, so we + # don't want to try using GCC-style -W flags. + # + ac_lbl_cc_dont_try_gcc_dashW=yes + # + # -g is equivalent to -g2, which turns off + # optimization; we choose -g3, which generates + # debugging information but doesn't turn off + # optimization (even if the optimization would + # cause inaccuracies in debugging). + # + V_CCOPT="$V_CCOPT -g3" + ;; + + solaris*) + # + # Assumed to be Sun C, which requires -errwarn to force + # warnings to be treated as errors. + # + ac_lbl_cc_force_warning_errors=-errwarn + + # + # Try to have the compiler default to hiding symbols, + # so that only symbols explicitly exported with + # PCAP_API will be visible outside (shared) libraries. + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -xldscope=hidden option" >&5 +printf %s "checking whether the compiler supports the -xldscope=hidden option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -xldscope=hidden" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -xldscope=hidden " >&5 +printf %s "checking whether -xldscope=hidden ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -xldscope=hidden" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + ;; + + ultrix*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that Ultrix $CC hacks const in prototypes" >&5 +printf %s "checking that Ultrix $CC hacks const in prototypes... " >&6; } + if test ${ac_cv_lbl_cc_const_proto+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +struct a { int b; }; + void c(const struct a *) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lbl_cc_const_proto=yes +else $as_nop + ac_cv_lbl_cc_const_proto=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_cc_const_proto" >&5 +printf "%s\n" "$ac_cv_lbl_cc_const_proto" >&6; } + if test $ac_cv_lbl_cc_const_proto = no ; then + +printf "%s\n" "#define const /**/" >>confdefs.h + + fi + ;; + esac + V_CCOPT="$V_CCOPT -O" + fi + + + if test "$GCC" = yes ; then + # + # On platforms where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in AIX and Darwin/macOS); + # + # define option to set the soname of the shared library, + # if the OS supports that; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + case "$host_os" in + + aix*) + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|osf*|haiku*|midipix*) + # + # Platforms where the C compiler is GCC or accepts + # compatible command-line arguments, and the linker + # is the GNU linker or accepts compatible command-line + # arguments. + # + # Some instruction sets require -fPIC on some + # operating systems. Check for them. If you + # have a combination that requires it, add it + # here. + # + PIC_OPT=-fpic + case "$host_cpu" in + + sparc64*) + case "$host_os" in + + freebsd*|openbsd*|linux*) + PIC_OPT=-fPIC + ;; + esac + ;; + esac + V_SHLIB_CCOPT="$V_SHLIB_CCOPT $PIC_OPT" + V_SONAME_OPT="-Wl,-soname," + ;; + + hpux*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + # + # XXX - this assumes GCC is using the HP linker, + # rather than the GNU linker, and that the "+h" + # option is used on all HP-UX platforms, both .sl + # and .so. + # + V_SONAME_OPT="-Wl,+h," + # + # By default, directories specified with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + solaris*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + # + # Sun/Oracle's C compiler, GCC, and GCC-compatible + # compilers support -Wl,{comma-separated list of options}, + # and we use the C compiler, not ld, for all linking, + # including linking to produce a shared library. + # + V_SONAME_OPT="-Wl,-h," + ;; + esac + else + # + # Set the appropriate compiler flags and, on platforms + # where we build a shared library: + # + # add options to generate position-independent code, + # if necessary (it's the default in Darwin/macOS); + # + # if we generate ".so" shared libraries, define the + # appropriate options for building the shared library; + # + # add options to specify, at link time, a directory to + # add to the run-time search path, if that's necessary. + # + # Note: spaces after V_SONAME_OPT are significant; on + # some platforms the soname is passed with a GCC-like + # "-Wl,-soname,{soname}" option, with the soname part + # of the option, while on other platforms the C compiler + # driver takes it as a regular option with the soname + # following the option. + # + case "$host_os" in + + aix*) + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G -bnoentry -bexpall" + ;; + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*) + # + # Platforms where the C compiler is GCC or accepts + # compatible command-line arguments, and the linker + # is the GNU linker or accepts compatible command-line + # arguments. + # + # XXX - does 64-bit SPARC require -fPIC? + # + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -fpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-Wl,-soname," + ;; + + hpux*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT +z" + V_SHLIB_CMD="\$(LD)" + V_SHLIB_OPT="-b" + V_SONAME_OPT="+h " + # + # By default, directories specified with -L + # are added to the run-time search path, so + # we don't add them in pcap-config. + # + ;; + + osf*) + # + # Presumed to be DEC OSF/1, Digital UNIX, or + # Tru64 UNIX. + # + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-shared" + V_SONAME_OPT="-soname " + ;; + + solaris*) + V_SHLIB_CCOPT="$V_SHLIB_CCOPT -Kpic" + V_SHLIB_CMD="\$(CC)" + V_SHLIB_OPT="-G" + # + # Sun/Oracle's C compiler, GCC, and GCC-compatible + # compilers support -Wl,{comma-separated list of options}, + # and we use the C compiler, not ld, for all linking, + # including linking to produce a shared library. + # + V_SONAME_OPT="-Wl,-h," + ;; + esac + fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +printf %s "checking for inline... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$V_CCOPT" + if test ${ac_cv_lbl_inline+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ac_cv_lbl_inline="" + ac_lbl_cc_inline=no + for ac_lbl_inline in inline __inline__ __inline + do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define inline $ac_lbl_inline + static inline struct iltest *foo(void); + struct iltest { + int iltest1; + int iltest2; + }; + + static inline struct iltest * + foo() + { + static struct iltest xxx; + + return &xxx; + } +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_lbl_cc_inline=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + if test "$ac_lbl_cc_inline" = yes ; then + break; + fi + done + if test "$ac_lbl_cc_inline" = yes ; then + ac_cv_lbl_inline=$ac_lbl_inline + fi +fi + + CFLAGS="$save_CFLAGS" + if test ! -z "$ac_cv_lbl_inline" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_inline" >&5 +printf "%s\n" "$ac_cv_lbl_inline" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + +printf "%s\n" "#define inline $ac_cv_lbl_inline" >>confdefs.h + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __atomic_load_n" >&5 +printf %s "checking for __atomic_load_n... " >&6; } + if test ${ac_cv_have___atomic_load_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + int i = 17; + int j; + j = __atomic_load_n(&i, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_have___atomic_load_n=yes +else $as_nop + ac_have___atomic_load_n=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_have___atomic_load_n" >&5 +printf "%s\n" "$ac_have___atomic_load_n" >&6; } + if test $ac_have___atomic_load_n = yes ; then + +printf "%s\n" "#define HAVE___ATOMIC_LOAD_N 1" >>confdefs.h + + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __atomic_store_n" >&5 +printf %s "checking for __atomic_store_n... " >&6; } + if test ${ac_cv_have___atomic_store_n+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + int i; + __atomic_store_n(&i, 17, __ATOMIC_RELAXED); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_have___atomic_store_n=yes +else $as_nop + ac_have___atomic_store_n=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_have___atomic_store_n" >&5 +printf "%s\n" "$ac_have___atomic_store_n" >&6; } + if test $ac_have___atomic_store_n = yes ; then + +printf "%s\n" "#define HAVE___ATOMIC_STORE_N 1" >>confdefs.h + + fi + +# +# Try to arrange for large file support. +# +# Check whether --enable-largefile was given. +if test ${enable_largefile+y} +then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +printf %s "checking for special C compiler options needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO" +then : + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test ${ac_cv_sys_file_offset_bits+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } +if test ${ac_cv_sys_large_files+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +printf "%s\n" "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h +;; +esac +rm -rf conftest* + fi +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 +printf %s "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_source+y} +then : + printf %s "(cached) " >&6 +else $as_nop + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include /* for off_t */ + #include +int +main (void) +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_sys_largefile_source=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGEFILE_SOURCE 1 +#include /* for off_t */ + #include +int +main (void) +{ +int (*fp) (FILE *, off_t, int) = fseeko; + return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_sys_largefile_source=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + ac_cv_sys_largefile_source=unknown + break +done +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 +printf "%s\n" "$ac_cv_sys_largefile_source" >&6; } +case $ac_cv_sys_largefile_source in #( + no | unknown) ;; + *) +printf "%s\n" "#define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source" >>confdefs.h +;; +esac +rm -rf conftest* + +# We used to try defining _XOPEN_SOURCE=500 too, to work around a bug +# in glibc 2.1.3, but that breaks too many other things. +# If you want fseeko and ftello with glibc, upgrade to a fixed glibc. +if test $ac_cv_sys_largefile_source != unknown; then + +printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_compile "$LINENO" "sys/ioccom.h" "ac_cv_header_sys_ioccom_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_ioccom_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_IOCCOM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sockio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h + +fi + +ac_fn_c_check_header_compile "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" +if test "x$ac_cv_header_netpacket_packet_h" = xyes +then : + printf "%s\n" "#define HAVE_NETPACKET_PACKET_H 1" >>confdefs.h + +fi + + +# +# Check whether the platform for which we're compiling requires extra +# defines and libraries. If so, add them to CFLAGS and LIBS, as we want +# all subsequent tests to be done with those defines and libraries. +# +case "$host_os" in +haiku*) + # + # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't + # use them. + # + CFLAGS="$CFLAGS -D_BSD_SOURCE" + # + # Haiku has getpass in libbsd. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getpass in -lbsd" >&5 +printf %s "checking for getpass in -lbsd... " >&6; } +if test ${ac_cv_lib_bsd_getpass+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char getpass (); +int +main (void) +{ +return getpass (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_bsd_getpass=yes +else $as_nop + ac_cv_lib_bsd_getpass=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_getpass" >&5 +printf "%s\n" "$ac_cv_lib_bsd_getpass" >&6; } +if test "x$ac_cv_lib_bsd_getpass" = xyes +then : + printf "%s\n" "#define HAVE_LIBBSD 1" >>confdefs.h + + LIBS="-lbsd $LIBS" + +fi + + ;; +esac + + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + +if test "$GCC" = yes ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ANSI ioctl definitions" >&5 +printf %s "checking for ANSI ioctl definitions... " >&6; } + if test ${ac_cv_lbl_gcc_fixincludes+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* + * This generates a "duplicate case value" when fixincludes + * has not be run. + */ +# include +# include +# include +# ifdef HAVE_SYS_IOCCOM_H +# include +# endif +int +main (void) +{ +switch (0) { + case _IO('A', 1):; + case _IO('B', 1):; + } + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lbl_gcc_fixincludes=yes +else $as_nop + ac_cv_lbl_gcc_fixincludes=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_gcc_fixincludes" >&5 +printf "%s\n" "$ac_cv_lbl_gcc_fixincludes" >&6; } + if test $ac_cv_lbl_gcc_fixincludes = no ; then + # Don't cache failure + unset ac_cv_lbl_gcc_fixincludes + as_fn_error $? "see the INSTALL for more info" "$LINENO" 5 + fi + fi + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + +ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r" +if test "x$ac_cv_func_strerror_r" = xyes +then : + + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r is GNU-style" >&5 +printf %s "checking whether strerror_r is GNU-style... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define _GNU_SOURCE +#include + +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} + + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # GNU-style + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_GNU_STRERROR_R /**/" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +printf "%s\n" "#define HAVE_POSIX_STRERROR_R /**/" >>confdefs.h + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +else $as_nop + + # + # We don't have strerror_r; do we have _wcserror_s? + # + ac_fn_c_check_func "$LINENO" "_wcserror_s" "ac_cv_func__wcserror_s" +if test "x$ac_cv_func__wcserror_s" = xyes +then : + printf "%s\n" "#define HAVE__WCSERROR_S 1" >>confdefs.h + +fi + + +fi + + +# +# Thanks, IBM, for not providing vsyslog() in AIX! +# +ac_fn_c_check_func "$LINENO" "vsyslog" "ac_cv_func_vsyslog" +if test "x$ac_cv_func_vsyslog" = xyes +then : + printf "%s\n" "#define HAVE_VSYSLOG 1" >>confdefs.h + +fi + + +# +# Make sure we have vsnprintf() and snprintf(); we require them. +# +ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" +if test "x$ac_cv_func_vsnprintf" = xyes +then : + +else $as_nop + as_fn_error $? "vsnprintf() is required but wasn't found" "$LINENO" 5 +fi + +ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" +if test "x$ac_cv_func_snprintf" = xyes +then : + +else $as_nop + as_fn_error $? "snprintf() is required but wasn't found" "$LINENO" 5 +fi + + +needasprintf=no + + for ac_func in vasprintf asprintf +do : + as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else $as_nop + needasprintf=yes +fi + +done +if test $needasprintf = yes; then + case " $LIBOBJS " in + *" asprintf.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" + ;; +esac + +fi + +needstrlcat=no + + for ac_func in strlcat +do : + ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes +then : + printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h + +else $as_nop + needstrlcat=yes +fi + +done +if test $needstrlcat = yes; then + case " $LIBOBJS " in + *" strlcat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" + ;; +esac + +fi + +needstrlcpy=no + + for ac_func in strlcpy +do : + ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes +then : + printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h + +else $as_nop + needstrlcpy=yes +fi + +done +if test $needstrlcpy = yes; then + case " $LIBOBJS " in + *" strlcpy.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" + ;; +esac + +fi + +needstrtok_r=no + + for ac_func in strtok_r +do : + ac_fn_c_check_func "$LINENO" "strtok_r" "ac_cv_func_strtok_r" +if test "x$ac_cv_func_strtok_r" = xyes +then : + printf "%s\n" "#define HAVE_STRTOK_R 1" >>confdefs.h + +else $as_nop + needstrtok_r=yes +fi + +done +if test $needstrtok_r = yes; then + case " $LIBOBJS " in + *" strtok_r.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strtok_r.$ac_objext" + ;; +esac + +fi + +# +# Do we have ffs(), and is it declared in ? +# +ac_fn_c_check_func "$LINENO" "ffs" "ac_cv_func_ffs" +if test "x$ac_cv_func_ffs" = xyes +then : + printf "%s\n" "#define HAVE_FFS 1" >>confdefs.h + +fi + +if test "$ac_cv_func_ffs" = yes; then + # + # We have ffs(); is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ffs(). + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 +printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +if test ${ac_cv_c_undeclared_builtin_options+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" + # This test program should *not* compile successfully. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +(void) strchr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the + # off chance that they somehow elicit warnings. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +extern void ac_decl (int, char *); + +int +main (void) +{ +(void) ac_decl (0, (char *) 0); + (void) ac_decl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + if test x"$ac_arg" = x +then : + ac_cv_c_undeclared_builtin_options='none needed' +else $as_nop + ac_cv_c_undeclared_builtin_options=$ac_arg +fi + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot make $CC report undeclared builtins +See \`config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : + ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; +esac + +ac_fn_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" " +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ffs" = xyes +then : + + +printf "%s\n" "#define STRINGS_H_DECLARES_FFS /**/" >>confdefs.h + + +fi +fi + +# +# Do this before checking for ether_hostton(), as it's a +# "getaddrinfo()-ish function". +# + + # + # Most operating systems have getaddrinfo(), and the other routines + # we may need, in the default searched libraries (e.g., libc). + # Check there first. + # + ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" +if test "x$ac_cv_func_getaddrinfo" = xyes +then : + +else $as_nop + + # + # Not found in the standard system libraries. + # + # In some versions of Solaris, we need to link with libsocket + # and libnsl, so check in libsocket and also link with liblnsl + # when doing this test. + # + # Linking with libsocket and libnsl will find all the routines + # we need. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lsocket" >&5 +printf %s "checking for getaddrinfo in -lsocket... " >&6; } +if test ${ac_cv_lib_socket_getaddrinfo+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket -lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char getaddrinfo (); +int +main (void) +{ +return getaddrinfo (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_socket_getaddrinfo=yes +else $as_nop + ac_cv_lib_socket_getaddrinfo=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_getaddrinfo" >&5 +printf "%s\n" "$ac_cv_lib_socket_getaddrinfo" >&6; } +if test "x$ac_cv_lib_socket_getaddrinfo" = xyes +then : + + # + # OK, we found it in libsocket. + # + LIBS="-lsocket -lnsl $LIBS" + +else $as_nop + + # + # Not found in libsocket; test for it in libnetwork, which + # is where it is in Haiku. + # + # Linking with libnetwork will find all the routines we + # need. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -lnetwork" >&5 +printf %s "checking for getaddrinfo in -lnetwork... " >&6; } +if test ${ac_cv_lib_network_getaddrinfo+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetwork $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char getaddrinfo (); +int +main (void) +{ +return getaddrinfo (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_network_getaddrinfo=yes +else $as_nop + ac_cv_lib_network_getaddrinfo=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_getaddrinfo" >&5 +printf "%s\n" "$ac_cv_lib_network_getaddrinfo" >&6; } +if test "x$ac_cv_lib_network_getaddrinfo" = xyes +then : + + # + # OK, we found it in libnetwork. + # + LIBS="-lnetwork $LIBS" + +else $as_nop + + # + # We didn't find it. + # + as_fn_error $? "getaddrinfo is required, but wasn't found" "$LINENO" 5 + +fi + + +fi + + + # + # We require a version of recvmsg() that conforms to the Single + # UNIX Specification, so that we can check whether a datagram + # received with recvmsg() was truncated when received due to the + # buffer being too small. + # + # On most systems, the version of recvmsg() in the libraries + # found above conforms to the SUS. + # + # On at least some versions of Solaris, it does not conform to + # the SUS, and we need the version in libxnet, which does + # conform. + # + # Check whether libxnet exists and has a version of recvmsg(); + # if it does, link with libxnet before we link with libsocket, + # to get that version. + # + # This test also links with libsocket and libnsl. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recvmsg in -lxnet" >&5 +printf %s "checking for recvmsg in -lxnet... " >&6; } +if test ${ac_cv_lib_xnet_recvmsg+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lxnet -lsocket -lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char recvmsg (); +int +main (void) +{ +return recvmsg (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_xnet_recvmsg=yes +else $as_nop + ac_cv_lib_xnet_recvmsg=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xnet_recvmsg" >&5 +printf "%s\n" "$ac_cv_lib_xnet_recvmsg" >&6; } +if test "x$ac_cv_lib_xnet_recvmsg" = xyes +then : + + # + # libxnet has recvmsg(); link with it as well. + # + LIBS="-lxnet $LIBS" + +fi + + +fi + + + # + # DLPI needs putmsg under HP-UX, so test for -lstr while we're at it. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing putmsg" >&5 +printf %s "checking for library containing putmsg... " >&6; } +if test ${ac_cv_search_putmsg+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char putmsg (); +int +main (void) +{ +return putmsg (); + ; + return 0; +} +_ACEOF +for ac_lib in '' str +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_putmsg=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_putmsg+y} +then : + break +fi +done +if test ${ac_cv_search_putmsg+y} +then : + +else $as_nop + ac_cv_search_putmsg=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_putmsg" >&5 +printf "%s\n" "$ac_cv_search_putmsg" >&6; } +ac_res=$ac_cv_search_putmsg +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + + +# +# Check for reentrant versions of getnetbyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getnetbyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getnetbyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +ac_fn_check_decl "$LINENO" "getnetbyname_r" "ac_cv_have_decl_getnetbyname_r" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_getnetbyname_r" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Linux getnetbyname_r()" >&5 +printf %s "checking for the Linux getnetbyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct netent netent_buf; + char buf[1024]; + struct netent *resultp; + int h_errnoval; + + return getnetbyname_r((const char *)0, &netent_buf, buf, sizeof buf, &resultp, &h_errnoval); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_LINUX_GETNETBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Solaris/IRIX getnetbyname_r()" >&5 +printf %s "checking for Solaris/IRIX getnetbyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct netent netent_buf; + char buf[1024]; + + return getnetbyname_r((const char *)0, &netent_buf, buf, (int)sizeof buf) != NULL; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOLARIS_IRIX_GETNETBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for AIX getnetbyname_r()" >&5 +printf %s "checking for AIX getnetbyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct netent netent_buf; + struct netent_data net_data; + + return getnetbyname_r((const char *)0, &netent_buf, &net_data); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_AIX_GETNETBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi + +# +# Check for reentrant versions of getprotobyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getprotobyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getprotobyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +ac_fn_check_decl "$LINENO" "getprotobyname_r" "ac_cv_have_decl_getprotobyname_r" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_getprotobyname_r" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Linux getprotobyname_r()" >&5 +printf %s "checking for the Linux getprotobyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct protoent protoent_buf; + char buf[1024]; + struct protoent *resultp; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, sizeof buf, &resultp); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_LINUX_GETPROTOBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Solaris/IRIX getprotobyname_r()" >&5 +printf %s "checking for Solaris/IRIX getprotobyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct protoent protoent_buf; + char buf[1024]; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, (int)sizeof buf) != NULL; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for AIX getprotobyname_r()" >&5 +printf %s "checking for AIX getprotobyname_r()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ + + struct protoent protoent_buf; + struct protoent_data proto_data; + + return getprotobyname_r((const char *)0, &protoent_buf, &proto_data); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_AIX_GETPROTOBYNAME_R 1" >>confdefs.h + + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi + +# +# You are in a twisty little maze of UN*Xes, all different. +# Some might not have ether_hostton(). +# Some might have it and declare it in . +# Some might have it and declare it in +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and not declare it in any header file. +# +# Before you is a C compiler. +# +ac_fn_c_check_func "$LINENO" "ether_hostton" "ac_cv_func_ether_hostton" +if test "x$ac_cv_func_ether_hostton" = xyes +then : + printf "%s\n" "#define HAVE_ETHER_HOSTTON 1" >>confdefs.h + +fi + +if test "$ac_cv_func_ether_hostton" = yes; then + # + # OK, we have ether_hostton(). Is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ether_hostton(). + # + ac_fn_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ether_hostton" = xyes +then : + + +printf "%s\n" "#define NET_ETHERNET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Linux? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + ac_fn_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ether_hostton" = xyes +then : + + +printf "%s\n" "#define NETINET_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Solaris 10 + # and later? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + ac_fn_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ether_hostton" = xyes +then : + + +printf "%s\n" "#define SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as in AIX? + # + # This test fails if we don't have + # (if we have ether_hostton(), we should have + # networking, and if we have networking, we should + # have ) or if we do but it doesn't + # declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + ac_fn_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ether_hostton" = xyes +then : + + +printf "%s\n" "#define ARPA_INET_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about ? + # On some platforms, it requires and + # , and we always include it with + # both of them, so test it with both of them. + # + # This test fails if we don't have + # and the headers we include before it, or if we do but + # doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + ac_fn_check_decl "$LINENO" "ether_hostton" "ac_cv_have_decl_ether_hostton" " +#include +#include +#include +#include +#include + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_ether_hostton" = xyes +then : + + +printf "%s\n" "#define NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON /**/" >>confdefs.h + + +fi + fi + # + # After all that, is ether_hostton() declared? + # + if test "$ac_cv_have_decl_ether_hostton" = yes; then + # + # Yes. + # + +printf "%s\n" "#define HAVE_DECL_ETHER_HOSTTON 1" >>confdefs.h + + else + # + # No, we'll have to declare it ourselves. + # Do we have "struct ether_addr" if we include + # ? + # + ac_fn_c_check_type "$LINENO" "struct ether_addr" "ac_cv_type_struct_ether_addr" " + #include + #include + #include + #include + #include + +" +if test "x$ac_cv_type_struct_ether_addr" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_ETHER_ADDR 1" >>confdefs.h + + +fi + + fi +fi + +# +# For various things that might use pthreads. +# +ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : + + # + # OK, we have pthread.h. Do we have pthread_create in the + # system libraries? + # + ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" +if test "x$ac_cv_func_pthread_create" = xyes +then : + + # + # Yes. + # + ac_lbl_have_pthreads="found" + +else $as_nop + + # + # No - do we have it in -lpthreads? + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 +printf %s "checking for pthread_create in -lpthreads... " >&6; } +if test ${ac_cv_lib_pthreads_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthreads $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char pthread_create (); +int +main (void) +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_pthreads_pthread_create=yes +else $as_nop + ac_cv_lib_pthreads_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthreads_pthread_create" >&6; } +if test "x$ac_cv_lib_pthreads_pthread_create" = xyes +then : + + # + # Yes - add -lpthreads. + # + ac_lbl_have_pthreads="found" + PTHREAD_LIBS="$PTHREAD_LIBS -lpthreads" + +else $as_nop + + # + # No - do we have it in -lpthread? + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char pthread_create (); +int +main (void) +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_pthread_pthread_create=yes +else $as_nop + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : + + # + # Yes - add -lpthread. + # + ac_lbl_have_pthreads="found" + PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" + +else $as_nop + + # + # No. + # + ac_lbl_have_pthreads="not found" + +fi + + +fi + + +fi + + +else $as_nop + + # + # We didn't find pthread.h. + # + ac_lbl_have_pthreads="not found" + + +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable the instrument functions code" >&5 +printf %s "checking whether to enable the instrument functions code... " >&6; } +# Check whether --enable-instrument-functions was given. +if test ${enable_instrument_functions+y} +then : + enableval=$enable_instrument_functions; +else $as_nop + enableval=no +fi + +case "$enableval" in +yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define ENABLE_INSTRUMENT_FUNCTIONS 1" >>confdefs.h + + # Add '-finstrument-functions' instrumentation option to generate + # instrumentation calls for entry and exit to functions. + # Use '--enable-instrument-functions' also with tcpdump (or tcpslice) + # to see the output. See also https://www.tcpdump.org/faq.html#q17. + CFLAGS="$CFLAGS -O0 -ggdb -finstrument-functions" + ;; +*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; +esac + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if --disable-protochain option is specified" >&5 +printf %s "checking if --disable-protochain option is specified... " >&6; } +# Check whether --enable-protochain was given. +if test ${enable_protochain+y} +then : + enableval=$enable_protochain; +fi + +case "x$enable_protochain" in +xyes) enable_protochain=enabled ;; +xno) enable_protochain=disabled ;; +x) enable_protochain=enabled ;; +esac + +if test "$enable_protochain" = "disabled"; then + +printf "%s\n" "#define NO_PROTOCHAIN 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${enable_protochain}" >&5 +printf "%s\n" "${enable_protochain}" >&6; } + +# +# valgrindtest directly uses the native capture mechanism, but +# only tests with BPF and PF_PACKET sockets; only enable it if +# we have BPF or PF_PACKET sockets. +# +VALGRINDTEST_SRC= + + +# Check whether --with-pcap was given. +if test ${with_pcap+y} +then : + withval=$with_pcap; +fi + +if test ! -z "$with_pcap" ; then + V_PCAP="$withval" +else + # + # Check for a bunch of headers for various packet + # capture mechanisms. + # + ac_fn_c_check_header_compile "$LINENO" "net/bpf.h" "ac_cv_header_net_bpf_h" "$ac_includes_default" +if test "x$ac_cv_header_net_bpf_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_BPF_H 1" >>confdefs.h + +fi + + if test "$ac_cv_header_net_bpf_h" = yes; then + # + # Does it define BIOCSETIF? + # I.e., is it a header for an LBL/BSD-style capture + # mechanism, or is it just a header for a BPF filter + # engine? Some versions of Arch Linux, for example, + # have a net/bpf.h that doesn't define BIOCSETIF; + # as it's a Linux, it should use packet sockets, + # instead. + # + # We need: + # + # sys/types.h, because FreeBSD 10's net/bpf.h + # requires that various BSD-style integer types + # be defined; + # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # + # sys/ioctl.h and, if we have it, sys/ioccom.h, + # because net/bpf.h defines ioctls; + # + # net/if.h, because it defines some structures + # used in ioctls defined by net/bpf.h; + # + # sys/socket.h, because OpenBSD 5.9's net/bpf.h + # defines some structure fields as being + # struct sockaddrs; + # + # and net/bpf.h doesn't necessarily include all + # of those headers itself. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if net/bpf.h defines BIOCSETIF" >&5 +printf %s "checking if net/bpf.h defines BIOCSETIF... " >&6; } + if test ${ac_cv_lbl_bpf_h_defines_biocsetif+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include +#include + +int +main (void) +{ +u_int i = BIOCSETIF; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lbl_bpf_h_defines_biocsetif=yes +else $as_nop + ac_cv_lbl_bpf_h_defines_biocsetif=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_bpf_h_defines_biocsetif" >&5 +printf "%s\n" "$ac_cv_lbl_bpf_h_defines_biocsetif" >&6; } + fi + ac_fn_c_check_header_compile "$LINENO" "net/pfilt.h" "ac_cv_header_net_pfilt_h" "$ac_includes_default" +if test "x$ac_cv_header_net_pfilt_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_PFILT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/enet.h" "ac_cv_header_net_enet_h" "$ac_includes_default" +if test "x$ac_cv_header_net_enet_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_ENET_H 1" >>confdefs.h + +fi + + ac_fn_c_check_header_compile "$LINENO" "net/nit.h" "ac_cv_header_net_nit_h" "$ac_includes_default" +if test "x$ac_cv_header_net_nit_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_NIT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/net/nit.h" "ac_cv_header_sys_net_nit_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_net_nit_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_NET_NIT_H 1" >>confdefs.h + +fi + + ac_fn_c_check_header_compile "$LINENO" "linux/socket.h" "ac_cv_header_linux_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_SOCKET_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/raw.h" "ac_cv_header_net_raw_h" "$ac_includes_default" +if test "x$ac_cv_header_net_raw_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_RAW_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/dlpi.h" "ac_cv_header_sys_dlpi_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_dlpi_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_DLPI_H 1" >>confdefs.h + +fi + + ac_fn_c_check_header_compile "$LINENO" "config/HaikuConfig.h" "ac_cv_header_config_HaikuConfig_h" "$ac_includes_default" +if test "x$ac_cv_header_config_HaikuConfig_h" = xyes +then : + printf "%s\n" "#define HAVE_CONFIG_HAIKUCONFIG_H 1" >>confdefs.h + +fi + + + if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then + # + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. + # + V_PCAP=bpf + + # + # We have BPF, so build valgrindtest with "make test" + # on macOS and FreeBSD (add your OS once there's a + # valgrind for it). + # + case "$host_os" in + + freebsd*|darwin*|linux*) + VALGRINDTEST_SRC=valgrindtest.c + ;; + esac + elif test "$ac_cv_header_linux_socket_h" = yes; then + # + # No prizes for guessing this one. + # + V_PCAP=linux + VALGRINDTEST_SRC=valgrindtest.c + elif test "$ac_cv_header_net_pfilt_h" = yes; then + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # + V_PCAP=pf + elif test "$ac_cv_header_net_enet_h" = yes; then + # + # Stanford Enetfilter. + # + V_PCAP=enet + elif test "$ac_cv_header_net_nit_h" = yes; then + # + # SunOS 4.x STREAMS NIT. + # + V_PCAP=snit + elif test "$ac_cv_header_sys_net_nit_h" = yes; then + # + # Pre-SunOS 4.x non-STREAMS NIT. + # + V_PCAP=nit + elif test "$ac_cv_header_net_raw_h" = yes; then + # + # IRIX snoop. + # + V_PCAP=snoop + elif test "$ac_cv_header_sys_dlpi_h" = yes; then + # + # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. + # + V_PCAP=dlpi + elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then + # + # Haiku. + # + V_PCAP=haiku + else + # + # We don't have any capture type we know about. + # Report an error, and tell the user to configure with + # --with-pcap=null if they want a libpcap that can't + # capture but that can read capture files. That way, + # nobody gets surprised by getting a no-capture + # libpcap without asking for that. + # + as_fn_error $? "No supported packet capture interface was found. + See the INSTALL.md file for information on packet capture support in + various operating systems. + If you want a libpcap that cannot capture packets but that can read + pcap and pcapng files, run configure with --with-pcap=null." "$LINENO" 5 + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking packet capture type" >&5 +printf %s "checking packet capture type... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $V_PCAP" >&5 +printf "%s\n" "$V_PCAP" >&6; } + + +# +# Do we have pkg-config? +# + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.17.0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + PKG_CONFIG="" + fi +fi + +# +# Do we have the brew command from Homebrew? +# +# Extract the first word of "brew", so it can be a program name with args. +set dummy brew; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_BREW+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $BREW in + [\\/]* | ?:[\\/]*) + ac_cv_path_BREW="$BREW" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_BREW="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BREW=$ac_cv_path_BREW +if test -n "$BREW"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BREW" >&5 +printf "%s\n" "$BREW" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or something), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +case "$host_os" in + +solaris*) + if test "$ac_cv_sizeof_void_p" -eq 8; then + # + # 64-bit build. If the path is empty, set it to + # /usr/lib/amd64/pkgconfig; otherwise, if + # /usr/lib/pkgconfig appears in the path, prepend + # /usr/lib/amd64/pkgconfig to it; otherwise, put + # /usr/lib/amd64/pkgconfig at the end. + # + if test -z "$PKG_CONFIG_PATH"; then + # + # Not set, or empty. Set it to + # /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig + elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` + else + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" + fi + export PKG_CONFIG_PATH + elif test "$ac_cv_sizeof_void_p" -eq 4; then + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears + # in the path, prepend /usr/lib/pkgconfig to it. + # + if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` + export PKG_CONFIG_PATH + fi + fi +esac + +# +# Handle each capture type. +# +case "$V_PCAP" in +dlpi) + # + # Checks for some header files. + # + ac_fn_c_check_header_compile "$LINENO" "sys/bufmod.h" "ac_cv_header_sys_bufmod_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_bufmod_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_BUFMOD_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/dlpi_ext.h" "ac_cv_header_sys_dlpi_ext_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_dlpi_ext_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_DLPI_EXT_H 1" >>confdefs.h + +fi + + + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LIBS -L/lib" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlpi_walk in -ldlpi" >&5 +printf %s "checking for dlpi_walk in -ldlpi... " >&6; } +if test ${ac_cv_lib_dlpi_dlpi_walk+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldlpi $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dlpi_walk (); +int +main (void) +{ +return dlpi_walk (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dlpi_dlpi_walk=yes +else $as_nop + ac_cv_lib_dlpi_dlpi_walk=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dlpi_dlpi_walk" >&5 +printf "%s\n" "$ac_cv_lib_dlpi_dlpi_walk" >&6; } +if test "x$ac_cv_lib_dlpi_dlpi_walk" = xyes +then : + + LIBS="-ldlpi $LIBS" + LIBS_STATIC="-ldlpi $LIBS_STATIC" + LIBS_PRIVATE="-ldlpi $LIBS_PRIVATE" + V_PCAP=libdlpi + + # + # Capture module plus common code needed for + # common functions used by pcap-[dlpi,libdlpi].c + # + PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c" + +printf "%s\n" "#define HAVE_LIBDLPI 1" >>confdefs.h + + +else $as_nop + + V_PCAP=dlpi + + # + # Capture module plus common code needed for + # common functions used by pcap-[dlpi,libdlpi].c + # + PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c" + +fi + + LDFLAGS="$save_LDFLAGS" + + # + # Checks whether is usable, to catch weird SCO + # versions of DLPI. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether is usable" >&5 +printf %s "checking whether is usable... " >&6; } + if test ${ac_cv_sys_dlpi_usable+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main (void) +{ +int i = DL_PROMISC_PHYS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_sys_dlpi_usable=yes +else $as_nop + ac_cv_sys_dlpi_usable=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_dlpi_usable" >&5 +printf "%s\n" "$ac_cv_sys_dlpi_usable" >&6; } + if test $ac_cv_sys_dlpi_usable = no ; then + as_fn_error $? " is not usable on this system; it probably has a non-standard DLPI" "$LINENO" 5 + fi + + # + # Check to see if Solaris has the dl_passive_req_t struct defined + # in . + # This check is for DLPI support for passive modes. + # See dlpi(7P) for more details. + # + ac_fn_c_check_type "$LINENO" "dl_passive_req_t" "ac_cv_type_dl_passive_req_t" " + #include + #include + +" +if test "x$ac_cv_type_dl_passive_req_t" = xyes +then : + +printf "%s\n" "#define HAVE_DL_PASSIVE_REQ_T 1" >>confdefs.h + + +fi + + ;; + +enet) + # + # Capture module + # + PLATFORM_C_SRC="pcap-enet.c" + ;; + +haiku) + # + # Capture module + # + PLATFORM_C_SRC="pcap-haiku.c" + + # + # Just for the sake of it. + # + ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/if_dl.h" "ac_cv_header_net_if_dl_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_dl_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_DL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "net/if_types.h" "ac_cv_header_net_if_types_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_types_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_TYPES_H 1" >>confdefs.h + +fi + + ;; + +linux) + # + # Capture module + # + PLATFORM_C_SRC="pcap-linux.c" + + # + # Do we have the wireless extensions? + # + ac_fn_c_check_header_compile "$LINENO" "linux/wireless.h" "ac_cv_header_linux_wireless_h" " +#include +#include +#include + +" +if test "x$ac_cv_header_linux_wireless_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_WIRELESS_H 1" >>confdefs.h + +fi + + + # + # Do we have libnl? + # We only want version 3. Version 2 was, apparently, + # short-lived, and version 1 is source and binary + # incompatible with version 3, and it appears that, + # these days, everybody's using version 3. We're + # not supporting older versions of the Linux kernel; + # let's drop support for older versions of libnl, too. + # + +# Check whether --with-libnl was given. +if test ${with_libnl+y} +then : + withval=$with_libnl; with_libnl=$withval +else $as_nop + with_libnl=if_available +fi + + + if test x$with_libnl != xno ; then + # + # Check for libnl-genl-3.0 with pkg-config. + # + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnl-genl-3.0 with pkg-config" >&5 +printf %s "checking for libnl-genl-3.0 with pkg-config... " >&6; } +if test -n "$PKG_CONFIG"; then + + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnl-genl-3.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libnl-genl-3.0") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # + # The package was found, so try to get its C flags and + # libraries. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + if test ! -n "$LIBNL_CFLAGS"; then + LIBNL_CFLAGS=`$PKG_CONFIG --cflags "libnl-genl-3.0" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --cflags "libnl-genl-3.0" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --cflags "libnl-genl-3.0" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --cflags \"libnl-genl-3.0\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$LIBNL_LIBS"; then + LIBNL_LIBS=`$PKG_CONFIG --libs "libnl-genl-3.0" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs "libnl-genl-3.0" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs "libnl-genl-3.0" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs \"libnl-genl-3.0\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$LIBNL_LIBS_STATIC"; then + LIBNL_LIBS_STATIC=`$PKG_CONFIG --libs --static "libnl-genl-3.0" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs --static "libnl-genl-3.0" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs --static "libnl-genl-3.0" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs --static \"libnl-genl-3.0\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + + pkg_config_found_libnl=yes + V_INCLS="$V_INCLS $LIBNL_CFLAGS" + ADDITIONAL_LIBS="$LIBNL_LIBS $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="$LIBNL_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" + REQUIRES_PRIVATE="libnl-genl-3.0 $REQUIRES_PRIVATE" + +printf "%s\n" "#define HAVE_LIBNL 1" >>confdefs.h + + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + : + fi +else + # No pkg-config, so obviously not found with pkg-config. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: pkg-config not found" >&5 +printf "%s\n" "pkg-config not found" >&6; } + : +fi + + + if test x$pkg_config_found_libnl != xyes; then + # + # OK, either we don't have pkg-config or there + # wasn't a .pc file for it; Check for it directly. + # + case "$with_libnl" in + + yes|if_available) + incdir=-I/usr/include/libnl3 + libnldir= + ;; + + *) + if test -d $withval; then + libnldir=-L${withval}/lib + incdir=-I${withval}/include + fi + ;; + esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nl_socket_alloc in -lnl-3" >&5 +printf %s "checking for nl_socket_alloc in -lnl-3... " >&6; } +if test ${ac_cv_lib_nl_3_nl_socket_alloc+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnl-3 ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char nl_socket_alloc (); +int +main (void) +{ +return nl_socket_alloc (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_nl_3_nl_socket_alloc=yes +else $as_nop + ac_cv_lib_nl_3_nl_socket_alloc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nl_3_nl_socket_alloc" >&5 +printf "%s\n" "$ac_cv_lib_nl_3_nl_socket_alloc" >&6; } +if test "x$ac_cv_lib_nl_3_nl_socket_alloc" = xyes +then : + + # + # Yes, we have libnl 3.x. + # + ADDITIONAL_LIBS="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS_STATIC" + LIBS_PRIVATE="${libnldir} -lnl-genl-3 -lnl-3 $LIBS_PRIVATE" + +printf "%s\n" "#define HAVE_LIBNL 1" >>confdefs.h + + V_INCLS="$V_INCLS ${incdir}" + +else $as_nop + + # + # No, we don't have libnl at all. + # Fail if the user explicitly requested + # it. + # + if test x$with_libnl = xyes ; then + as_fn_error $? "libnl support requested but libnl not found" "$LINENO" 5 + fi + +fi + + fi + fi + + # + # Check to see if the tpacket_auxdata struct has a tp_vlan_tci member. + # + # NOTE: any failure means we conclude that it doesn't have that + # member, so if we don't have tpacket_auxdata, we conclude it + # doesn't have that member (which is OK, as either we won't be + # using code that would use that member, or we wouldn't compile + # in any case). + ac_fn_c_check_member "$LINENO" "struct tpacket_auxdata" "tp_vlan_tci" "ac_cv_member_struct_tpacket_auxdata_tp_vlan_tci" " + #include + #include + +" +if test "x$ac_cv_member_struct_tpacket_auxdata_tp_vlan_tci" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_TPACKET_AUXDATA_TP_VLAN_TCI 1" >>confdefs.h + + +fi + + ;; + +bpf) + # + # Capture module + # + PLATFORM_C_SRC="pcap-bpf.c" + + # + # Check whether we have the *BSD-style ioctls. + # + ac_fn_c_check_header_compile "$LINENO" "net/if_media.h" "ac_cv_header_net_if_media_h" "$ac_includes_default" +if test "x$ac_cv_header_net_if_media_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_MEDIA_H 1" >>confdefs.h + +fi + + + # + # Check whether we have struct BPF_TIMEVAL. + # + ac_fn_c_check_type "$LINENO" "struct BPF_TIMEVAL" "ac_cv_type_struct_BPF_TIMEVAL" " + #include + #include + #ifdef HAVE_SYS_IOCCOM_H + #include + #endif + #include + +" +if test "x$ac_cv_type_struct_BPF_TIMEVAL" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_BPF_TIMEVAL 1" >>confdefs.h + + +fi + + + # + # Check whether there's a net/ipnet.h header and, + # if so, whether it defines IPNET_ANY_LINK - if so, + # we assume we have the "any" device (that's a + # Solaris header, and later versions of Solaris + # have an "any" device). + # + # Attempting to include it at compile time could + # be a pain, as it's a kernel header. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the Solaris \"any\" device is supported" >&5 +printf %s "checking whether the Solaris \"any\" device is supported... " >&6; } + if test -e /usr/include/inet/ipnet.h && + grep -q IPNET_ANY_LINK /usr/include/inet/ipnet.h; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_SOLARIS_ANY_DEVICE 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + ;; + +pf) + # + # Capture module + # + PLATFORM_C_SRC="pcap-pf.c" + ;; + +snit) + # + # Capture module + # + PLATFORM_C_SRC="pcap-snit.c" + ;; + +snoop) + # + # Capture module + # + PLATFORM_C_SRC="pcap-snoop.c" + ;; + +dag) + # + # --with-pcap=dag is the only way to get here, and it means + # "DAG support but nothing else" + # + V_DEFS="$V_DEFS -DDAG_ONLY" + PLATFORM_C_SRC="pcap-dag.c" + xxx_only=yes + ;; + +dpdk) + # + # --with-pcap=dpdk is the only way to get here, and it means + # "DPDK support but nothing else" + # + V_DEFS="$V_DEFS -DDPDK_ONLY" + PLATFORM_C_SRC="pcap-dpdk.c" + xxx_only=yes + ;; + +septel) + # + # --with-pcap=septel is the only way to get here, and it means + # "Septel support but nothing else" + # + V_DEFS="$V_DEFS -DSEPTEL_ONLY" + PLATFORM_C_SRC="pcap-septel.c" + xxx_only=yes + ;; + +snf) + # + # --with-pcap=snf is the only way to get here, and it means + # "SNF support but nothing else" + # + V_DEFS="$V_DEFS -DSNF_ONLY" + PLATFORM_C_SRC="pcap-snf.c" + xxx_only=yes + ;; + +null) + # + # Capture module + # + PLATFORM_C_SRC="pcap-null.c" + ;; + +*) + as_fn_error $? "$V_PCAP is not a valid pcap type" "$LINENO" 5 + ;; +esac + +if test "$V_PCAP" != null +then + ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" +if test "x$ac_cv_func_getifaddrs" = xyes +then : + + # + # We have "getifaddrs()"; make sure we have + # as well, just in case some platform is really weird. + # + ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "$ac_includes_default" +if test "x$ac_cv_header_ifaddrs_h" = xyes +then : + + # + # We have the header, so we use "getifaddrs()" to + # get the list of interfaces. + # + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c" + +else $as_nop + + # + # We don't have the header - give up. + # XXX - we could also fall back on some other + # mechanism, but, for now, this'll catch this + # problem so that we can at least try to figure + # out something to do on systems with "getifaddrs()" + # but without "ifaddrs.h", if there is something + # we can do on those systems. + # + as_fn_error $? "Your system has getifaddrs() but doesn't have a usable ." "$LINENO" 5 + +fi + + +else $as_nop + + # + # Well, we don't have "getifaddrs()", at least not with the + # libraries with which we've decided we need to link + # libpcap with, so we have to use some other mechanism. + # + # Note that this may happen on Solaris, which has + # getifaddrs(), but in -lsocket, not in -lxnet, so we + # won't find it if we link with -lxnet, which we want + # to do for other reasons. + # + # For now, we use either the SIOCGIFCONF ioctl or the + # SIOCGLIFCONF ioctl, preferring the latter if we have + # it; the latter is a Solarisism that first appeared + # in Solaris 8. (Solaris's getifaddrs() appears to + # be built atop SIOCGLIFCONF; using it directly + # avoids a not-all-that-useful middleman.) + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we have SIOCGLIFCONF" >&5 +printf %s "checking whether we have SIOCGLIFCONF... " >&6; } + if test ${ac_cv_lbl_have_siocglifconf+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include + #include + #include +int +main (void) +{ +ioctl(0, SIOCGLIFCONF, (char *)0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lbl_have_siocglifconf=yes +else $as_nop + ac_cv_lbl_have_siocglifconf=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lbl_have_siocglifconf" >&5 +printf "%s\n" "$ac_cv_lbl_have_siocglifconf" >&6; } + if test $ac_cv_lbl_have_siocglifconf = yes ; then + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c" + else + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c" + fi + +fi + +fi + +case "$host_os" in +linux*) + ac_fn_c_check_header_compile "$LINENO" "linux/net_tstamp.h" "ac_cv_header_linux_net_tstamp_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_net_tstamp_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_NET_TSTAMP_H 1" >>confdefs.h + +fi + + ;; +*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: no hardware timestamp support implemented for $host_os" >&5 +printf "%s\n" "$as_me: no hardware timestamp support implemented for $host_os" >&6;} + ;; +esac + +# +# Check for socklen_t. +# +ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " + #include + #include + +" +if test "x$ac_cv_type_socklen_t" = xyes +then : + +printf "%s\n" "#define HAVE_SOCKLEN_T 1" >>confdefs.h + + +fi + + +# Check whether --enable-ipv6 was given. +if test ${enable_ipv6+y} +then : + enableval=$enable_ipv6; +else $as_nop + enable_ipv6=yes +fi + +if test "$enable_ipv6" != "no"; then + # + # We've already made sure we have getaddrinfo above in + # AC_LBL_LIBRARY_NET. + # + +printf "%s\n" "#define INET6 1" >>confdefs.h + +fi + +# Check for Endace DAG card support. + +# Check whether --with-dag was given. +if test ${with_dag+y} +then : + withval=$with_dag; + if test "$withval" = no + then + # User doesn't want DAG support. + want_dag=no + elif test "$withval" = yes + then + # User wants DAG support but hasn't specified a directory. + want_dag=yes + else + # User wants DAG support and has specified a directory, so use the provided value. + want_dag=yes + dag_root=$withval + fi + +else $as_nop + + if test "$V_PCAP" = dag; then + # User requested DAG-only libpcap, so we'd better have + # the DAG API. + want_dag=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want DAG support. + want_dag=no + else + # + # Use DAG API if present, otherwise don't + # + want_dag=ifpresent + fi + +fi + + + +# Check whether --with-dag-includes was given. +if test ${with_dag_includes+y} +then : + withval=$with_dag_includes; + # User wants DAG support and has specified a header directory, so use the provided value. + want_dag=yes + dag_include_dir=$withval + +fi + + + +# Check whether --with-dag-libraries was given. +if test ${with_dag_libraries+y} +then : + withval=$with_dag_libraries; + # User wants DAG support and has specified a library directory, so use the provided value. + want_dag=yes + dag_lib_dir=$withval + +fi + + +if test "$want_dag" != no; then + + # If necessary, set default paths for DAG API headers and libraries. + if test -z "$dag_root"; then + dag_root=/usr/local + fi + + if test -z "$dag_include_dir"; then + dag_include_dir="$dag_root/include" + fi + + if test -z "$dag_lib_dir"; then + dag_lib_dir="$dag_root/lib" + # + # Handle multiarch systems. + # + if test -d "$dag_lib_dir/$host" + then + dag_lib_dir="$dag_lib_dir/$host" + fi + fi + + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS -I$dag_include_dir" + ac_fn_c_check_header_compile "$LINENO" "dagapi.h" "ac_cv_header_dagapi_h" "$ac_includes_default" +if test "x$ac_cv_header_dagapi_h" = xyes +then : + printf "%s\n" "#define HAVE_DAGAPI_H 1" >>confdefs.h + +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + + if test "$ac_cv_header_dagapi_h" = yes; then + + V_INCLS="$V_INCLS -I$dag_include_dir" + + if test $V_PCAP != dag ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c" + fi + + # Check for various DAG API functions. + # Don't need to save and restore LIBS to prevent -ldag being + # included if there's a found-action (arg 3). + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + LDFLAGS="-L$dag_lib_dir" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream in -ldag" >&5 +printf %s "checking for dag_attach_stream in -ldag... " >&6; } +if test ${ac_cv_lib_dag_dag_attach_stream+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dag_attach_stream (); +int +main (void) +{ +return dag_attach_stream (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dag_dag_attach_stream=yes +else $as_nop + ac_cv_lib_dag_dag_attach_stream=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_attach_stream" >&5 +printf "%s\n" "$ac_cv_lib_dag_dag_attach_stream" >&6; } +if test "x$ac_cv_lib_dag_dag_attach_stream" = xyes +then : + + # + # We assume that if we have libdag we have + # libdagconf, as they're installed at the + # same time from the same package. + # + ADDITIONAL_LIBS="-L$dag_lib_dir $ADDITIONAL_LIBS -ldag -ldagconf" + ADDITIONAL_LIBS_STATIC="-L$dag_lib_dir $ADDITIONAL_LIBS_STATIC -ldag -ldagconf" + LIBS_PRIVATE="-L$dag_lib_dir $LIBS_PRIVATE -ldag -ldagconf" + +else $as_nop + as_fn_error $? "DAG library lacks streams support" "$LINENO" 5 +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dag_attach_stream64 in -ldag" >&5 +printf %s "checking for dag_attach_stream64 in -ldag... " >&6; } +if test ${ac_cv_lib_dag_dag_attach_stream64+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dag_attach_stream64 (); +int +main (void) +{ +return dag_attach_stream64 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dag_dag_attach_stream64=yes +else $as_nop + ac_cv_lib_dag_dag_attach_stream64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_attach_stream64" >&5 +printf "%s\n" "$ac_cv_lib_dag_dag_attach_stream64" >&6; } +if test "x$ac_cv_lib_dag_dag_attach_stream64" = xyes +then : + dag_large_streams="1" +else $as_nop + dag_large_streams="0" +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dag_get_erf_types in -ldag" >&5 +printf %s "checking for dag_get_erf_types in -ldag... " >&6; } +if test ${ac_cv_lib_dag_dag_get_erf_types+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dag_get_erf_types (); +int +main (void) +{ +return dag_get_erf_types (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dag_dag_get_erf_types=yes +else $as_nop + ac_cv_lib_dag_dag_get_erf_types=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_erf_types" >&5 +printf "%s\n" "$ac_cv_lib_dag_dag_get_erf_types" >&6; } +if test "x$ac_cv_lib_dag_dag_get_erf_types" = xyes +then : + + +printf "%s\n" "#define HAVE_DAG_GET_ERF_TYPES 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dag_get_stream_erf_types in -ldag" >&5 +printf %s "checking for dag_get_stream_erf_types in -ldag... " >&6; } +if test ${ac_cv_lib_dag_dag_get_stream_erf_types+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char dag_get_stream_erf_types (); +int +main (void) +{ +return dag_get_stream_erf_types (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dag_dag_get_stream_erf_types=yes +else $as_nop + ac_cv_lib_dag_dag_get_stream_erf_types=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dag_dag_get_stream_erf_types" >&5 +printf "%s\n" "$ac_cv_lib_dag_dag_get_stream_erf_types" >&6; } +if test "x$ac_cv_lib_dag_dag_get_stream_erf_types" = xyes +then : + + +printf "%s\n" "#define HAVE_DAG_GET_STREAM_ERF_TYPES 1" >>confdefs.h + +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + + # + # We assume that if we have libdag we have libdagconf, + # as they're installed at the same time from the same + # package. + # + if test "$dag_large_streams" = 1; then + +printf "%s\n" "#define HAVE_DAG_LARGE_STREAMS_API 1" >>confdefs.h + + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + LIBS="$LIBS -ldag -ldagconf" + LDFLAGS="$LDFLAGS -L$dag_lib_dir" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vdag_set_device_info in -lvdag" >&5 +printf %s "checking for vdag_set_device_info in -lvdag... " >&6; } +if test ${ac_cv_lib_vdag_vdag_set_device_info+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lvdag $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char vdag_set_device_info (); +int +main (void) +{ +return vdag_set_device_info (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_vdag_vdag_set_device_info=yes +else $as_nop + ac_cv_lib_vdag_vdag_set_device_info=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vdag_vdag_set_device_info" >&5 +printf "%s\n" "$ac_cv_lib_vdag_vdag_set_device_info" >&6; } +if test "x$ac_cv_lib_vdag_vdag_set_device_info" = xyes +then : + ac_dag_have_vdag="1" +else $as_nop + ac_dag_have_vdag="0" +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + if test "$ac_dag_have_vdag" = 1; then + +printf "%s\n" "#define HAVE_DAG_VDAG 1" >>confdefs.h + + if test "$ac_lbl_have_pthreads" != "found"; then + as_fn_error $? "DAG requires pthreads, but we didn't find them" "$LINENO" 5 + fi + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $PTHREAD_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $PTHREAD_LIBS" + LIBS_PRIVATE="$LIBS_PRIVATE $PTHREAD_LIBS" + fi + fi + + +printf "%s\n" "#define HAVE_DAG_API 1" >>confdefs.h + + else + if test "$V_PCAP" = dag; then + # User requested "dag" capture type but we couldn't + # find the DAG API support. + as_fn_error $? "DAG support requested with --with-pcap=dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5 + fi + + if test "$want_dag" = yes; then + # User wanted DAG support but we couldn't find it. + as_fn_error $? "DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support" "$LINENO" 5 + fi + fi + CFLAGS="$save_CFLAGS" +fi + + +# Check whether --with-septel was given. +if test ${with_septel+y} +then : + withval=$with_septel; + if test "$withval" = no + then + want_septel=no + elif test "$withval" = yes + then + want_septel=yes + septel_root= + else + want_septel=yes + septel_root=$withval + fi + +else $as_nop + + if test "$V_PCAP" = septel; then + # User requested Septel-only libpcap, so we'd better have + # the Septel API. + want_septel=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want Septel support. + want_septel=no + else + # + # Use Septel API if present, otherwise don't + # + want_septel=ifpresent + fi + +fi + + +ac_cv_lbl_septel_api=no +if test "$with_septel" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we have Septel API headers" >&5 +printf %s "checking whether we have Septel API headers... " >&6; } + + # If necessary, set default paths for Septel API headers and libraries. + if test -z "$septel_root"; then + septel_root=$srcdir/../septel + fi + + septel_tools_dir="$septel_root" + septel_include_dir="$septel_root/INC" + + if test -r "$septel_include_dir/msg.h"; then + ac_cv_lbl_septel_api=yes + fi + + if test "$ac_cv_lbl_septel_api" = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($septel_include_dir)" >&5 +printf "%s\n" "yes ($septel_include_dir)" >&6; } + + V_INCLS="$V_INCLS -I$septel_include_dir" + ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + + if test "$V_PCAP" != septel ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c" + fi + + +printf "%s\n" "#define HAVE_SEPTEL_API 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + if test "$V_PCAP" = septel; then + # User requested "septel" capture type but + # we couldn't find the Septel API support. + as_fn_error $? "Septel support requested with --with-pcap=septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5 + fi + + if test "$want_septel" = yes; then + # User wanted Septel support but we couldn't find it. + as_fn_error $? "Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support" "$LINENO" 5 + fi + fi +fi + +# Check for Myricom SNF support. + +# Check whether --with-snf was given. +if test ${with_snf+y} +then : + withval=$with_snf; + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specified a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi + +else $as_nop + + if test "$V_PCAP" = snf; then + # User requested Sniffer-only libpcap, so we'd better have + # the Sniffer API. + want_snf=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want SNF support. + want_snf=no + else + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent + fi + +fi + + + +# Check whether --with-snf-includes was given. +if test ${with_snf_includes+y} +then : + withval=$with_snf_includes; + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval + +fi + + + +# Check whether --with-snf-libraries was given. +if test ${with_snf_libraries+y} +then : + withval=$with_snf_libraries; + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval + +fi + + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we have Myricom Sniffer API" >&5 +printf %s "checking whether we have Myricom Sniffer API... " >&6; } + + # If necessary, set default paths for Sniffer headers and libraries. + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + # + # Handle multiarch systems. + # + if test -d "$snf_lib_dir/$host" + then + snf_lib_dir="$snf_lib_dir/$host" + fi + fi + + if test -f "$snf_include_dir/snf.h"; then + # We found a header; make sure we can link with the library + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snf_init in -lsnf" >&5 +printf %s "checking for snf_init in -lsnf... " >&6; } +if test ${ac_cv_lib_snf_snf_init+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnf $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char snf_init (); +int +main (void) +{ +return snf_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_snf_snf_init=yes +else $as_nop + ac_cv_lib_snf_snf_init=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_snf_snf_init" >&5 +printf "%s\n" "$ac_cv_lib_snf_snf_init" >&6; } +if test "x$ac_cv_lib_snf_snf_init" = xyes +then : + ac_cv_lbl_snf_api="yes" +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + if test "$ac_cv_lbl_snf_api" = no; then + as_fn_error $? "SNF API cannot correctly be linked; check config.log" "$LINENO" 5 + fi + fi + + if test "$ac_cv_lbl_snf_api" = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($snf_root)" >&5 +printf "%s\n" "yes ($snf_root)" >&6; } + + V_INCLS="$V_INCLS -I$snf_include_dir" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS -L$snf_lib_dir -lsnf" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC -L$snf_lib_dir -lsnf" + LIBS_PRIVATE="$LIBS_PRIVATE -L$snf_lib_dir -lsnf" + + if test "$V_PCAP" != snf ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c" + fi + + +printf "%s\n" "#define HAVE_SNF_API 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + if test "$want_snf" = yes; then + # User requested "snf" capture type but + # we couldn't find the Sniffer API support. + as_fn_error $? "Myricom Sniffer support requested with --with-pcap=snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support" "$LINENO" 5 + fi + + if test "$want_snf" = yes; then + as_fn_error $? "Myricom Sniffer support requested with --with-snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support" "$LINENO" 5 + fi + fi +fi + +# Check for Riverbed TurboCap support. + +# Check whether --with-turbocap was given. +if test ${with_turbocap+y} +then : + withval=$with_turbocap; + if test "$withval" = no + then + # User explicitly doesn't want TurboCap + want_turbocap=no + elif test "$withval" = yes + then + # User wants TurboCap support but hasn't specified a directory. + want_turbocap=yes + else + # User wants TurboCap support with a specified directory. + want_turbocap=yes + turbocap_root=$withval + fi + +else $as_nop + + if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want TurboCap support. + want_turbocap=no + else + # + # Use TurboCap API if present, otherwise don't + # + want_turbocap=ifpresent + fi + +fi + + +ac_cv_lbl_turbocap_api=no +if test "$want_turbocap" != no; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether TurboCap is supported" >&5 +printf %s "checking whether TurboCap is supported... " >&6; } + + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + if test ! -z "$turbocap_root"; then + TURBOCAP_CFLAGS="-I$turbocap_root/include" + TURBOCAP_LDFLAGS="-L$turbocap_root/lib" + CFLAGS="$CFLAGS $TURBOCAP_CFLAGS" + LDFLAGS="$LDFLAGS $TURBOCAP_LDFLAGS" + fi + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main (void) +{ + + TC_INSTANCE a; TC_PORT b; TC_BOARD c; + TC_INSTANCE i; + (void)TcInstanceCreateByName("foo", &i); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_lbl_turbocap_api=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + if test $ac_cv_lbl_turbocap_api = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + + MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c" + V_INCLS="$V_INCLS $TURBOCAP_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + LIBS_PRIVATE="$LIBS_PRIVATE $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + + +printf "%s\n" "#define HAVE_TC_API 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + if test "$want_turbocap" = yes; then + # User wanted Turbo support but we couldn't find it. + as_fn_error $? "TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support" "$LINENO" 5 + fi + fi +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable remote packet capture" >&5 +printf %s "checking whether to enable remote packet capture... " >&6; } +# Check whether --enable-remote was given. +if test ${enable_remote+y} +then : + enableval=$enable_remote; +else $as_nop + enableval=no +fi + +case "$enableval" in +yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Remote packet capture may expose libpcap-based applications" >&5 +printf "%s\n" "$as_me: WARNING: Remote packet capture may expose libpcap-based applications" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: to attacks by malicious remote capture servers!" >&5 +printf "%s\n" "$as_me: WARNING: to attacks by malicious remote capture servers!" >&2;} + # + # rpcapd requires pthreads on UN*X. + # + if test "$ac_lbl_have_pthreads" != "found"; then + as_fn_error $? "rpcapd requires pthreads, but we didn't find them" "$LINENO" 5 + fi + # + # It also requires crypt(). + # Do we have it in the system libraries? + # + ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt" +if test "x$ac_cv_func_crypt" = xyes +then : + +else $as_nop + + # + # No. Do we have it in -lcrypt? + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 +printf %s "checking for crypt in -lcrypt... " >&6; } +if test ${ac_cv_lib_crypt_crypt+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char crypt (); +int +main (void) +{ +return crypt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_crypt_crypt=yes +else $as_nop + ac_cv_lib_crypt_crypt=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 +printf "%s\n" "$ac_cv_lib_crypt_crypt" >&6; } +if test "x$ac_cv_lib_crypt_crypt" = xyes +then : + + # + # Yes; add -lcrypt to the libraries for rpcapd. + # + RPCAPD_LIBS="$RPCAPD_LIBS -lcrypt" + +else $as_nop + + as_fn_error $? "rpcapd requires crypt(), but we didn't find it" "$LINENO" 5 + +fi + + +fi + + + # + # OK, we have crypt(). Do we have getspnam()? + # + ac_fn_c_check_func "$LINENO" "getspnam" "ac_cv_func_getspnam" +if test "x$ac_cv_func_getspnam" = xyes +then : + printf "%s\n" "#define HAVE_GETSPNAM 1" >>confdefs.h + +fi + + + # + # Check for various members of struct msghdr. + # + ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" " + #include \"ftmacros.h\" + #include + +" +if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1" >>confdefs.h + + +fi + + ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_flags" "ac_cv_member_struct_msghdr_msg_flags" " + #include \"ftmacros.h\" + #include + +" +if test "x$ac_cv_member_struct_msghdr_msg_flags" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_MSGHDR_MSG_FLAGS 1" >>confdefs.h + + +fi + + + # + # Optionally, we may want to support SSL. + # Check for OpenSSL/libressl. + # + # First, try looking for it with pkg-config, if we have it. + # + # Homebrew's pkg-config does not, by default, look for + # pkg-config files for packages it has installed. + # Furthermore, at least for OpenSSL, they appear to be + # dumped in package-specific directories whose paths are + # not only package-specific but package-version-specific. + # + # So the only way to find openssl is to get the value of + # PKG_CONFIG_PATH from "brew --env openssl" and add that + # to PKG_CONFIG_PATH. (No, we can't just assume it's under + # /usr/local; Homebrew have conveniently chosen to put it + # under /opt/homebrew on ARM.) + # + # That's the nice thing about Homebrew - it makes things easier! + # Thanks! + # + save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" + if test -n "$BREW"; then + openssl_pkgconfig_dir=`$BREW --env --plain openssl | sed -n 's/PKG_CONFIG_PATH: //p'` + PKG_CONFIG_PATH="$openssl_pkgconfig_dir:$PKG_CONFIG_PATH" + fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl with pkg-config" >&5 +printf %s "checking for openssl with pkg-config... " >&6; } +if test -n "$PKG_CONFIG"; then + + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl\""; } >&5 + ($PKG_CONFIG --exists --print-errors "openssl") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # + # The package was found, so try to get its C flags and + # libraries. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + if test ! -n "$OPENSSL_CFLAGS"; then + OPENSSL_CFLAGS=`$PKG_CONFIG --cflags "openssl" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --cflags "openssl" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --cflags "openssl" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --cflags \"openssl\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$OPENSSL_LIBS"; then + OPENSSL_LIBS=`$PKG_CONFIG --libs "openssl" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs "openssl" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs "openssl" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs \"openssl\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$OPENSSL_LIBS_STATIC"; then + OPENSSL_LIBS_STATIC=`$PKG_CONFIG --libs --static "openssl" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs --static "openssl" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs --static "openssl" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs --static \"openssl\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + + # + # We found OpenSSL/libressl. + # + HAVE_OPENSSL=yes + REQUIRES_PRIVATE="$REQUIRES_PRIVATE openssl" + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + : + fi +else + # No pkg-config, so obviously not found with pkg-config. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: pkg-config not found" >&5 +printf "%s\n" "pkg-config not found" >&6; } + : +fi + + PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" + + # + # If it wasn't found, and we have Homebrew installed, see + # if it's in Homebrew. + # + if test "x$HAVE_OPENSSL" != "xyes" -a -n "$BREW"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openssl in Homebrew" >&5 +printf %s "checking for openssl in Homebrew... " >&6; } + # + # The brew man page lies when it speaks of + # $BREW --prefix --installed + # outputting nothing. In Homebrew 3.3.16, + # it produces output regardless of whether + # the formula is installed or not, so we + # send the standard output and error to + # the bit bucket. + # + if $BREW --prefix --installed openssl >/dev/null 2>&1; then + # + # Yes. Get the include directory and library + # directory. (No, we can't just assume it's + # under /usr/local; Homebrew have conveniently + # chosen to put it under /opt/homebrew on ARM.) + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_OPENSSL=yes + openssl_path=`$BREW --prefix openssl` + OPENSSL_CFLAGS="-I$openssl_path/include" + OPENSSL_LIBS="-L$openssl_path/lib -lssl -lcrypto" + OPENSSL_LIBS_STATIC="-L$openssl_path/lib -lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-L$openssl_path/lib -lssl -lcrypto" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + fi + + # + # If it wasn't found, and /usr/local/include and /usr/local/lib + # exist, check if it's in /usr/local. (We check whether they + # exist because, if they don't exist, the compiler will warn + # about that and then ignore the argument, so they test + # using just the system header files and libraries.) + # + # We include the standard include file to 1) make sure that + # it's installed (if it's just a shared library for the + # benefit of existing programs, that's not useful) and 2) + # because SSL_library_init() is a library routine in some + # versions and a #defined wrapper around OPENSSL_init_ssl() + # in others. + # + if test "x$HAVE_OPENSSL" != "xyes" -a -d "/usr/local/include" -a -d "/usr/local/lib"; then + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS -I/usr/local/include" + LIBS="$LIBS -L/usr/local/lib -lssl -lcrypto" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we have OpenSSL/libressl in /usr/local that we can use" >&5 +printf %s "checking whether we have OpenSSL/libressl in /usr/local that we can use... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main (void) +{ + +SSL_library_init(); +return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_OPENSSL=yes + OPENSSL_CFLAGS="-I/usr/local/include" + OPENSSL_LIBS="-L/usr/local/lib -lssl -lcrypto" + OPENSSL_LIBS_STATIC="-L/usr/local/lib -lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-L/usr/local/lib -lssl -lcrypto" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + fi + + # + # If it wasn't found, check if it's a system library. + # + # We include the standard include file to 1) make sure that + # it's installed (if it's just a shared library for the + # benefit of existing programs, that's not useful) and 2) + # because SSL_library_init() is a library routine in some + # versions and a #defined wrapper around OPENSSL_init_ssl() + # in others. + # + if test "x$HAVE_OPENSSL" != "xyes"; then + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + LIBS="$LIBS -lssl -lcrypto" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we have a system OpenSSL/libressl that we can use" >&5 +printf %s "checking whether we have a system OpenSSL/libressl that we can use... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main (void) +{ + +SSL_library_init(); +return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + HAVE_OPENSSL=yes + OPENSSL_LIBS="-lssl -lcrypto" + OPENSSL_LIBS_STATIC="-lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-lssl -lcrypto" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + fi + + # + # OK, did we find it? + # + if test "x$HAVE_OPENSSL" = "xyes"; then + +printf "%s\n" "#define HAVE_OPENSSL 1" >>confdefs.h + + V_INCLS="$V_INCLS $OPENSSL_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $OPENSSL_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $OPENSSL_LIBS_STATIC" + LIBS_PRIVATE="$LIBS_PRIVATE $OPENSSL_LIBS_PRIVATE" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE $OPENSSL_REQUIRES_PRIVATE" + REMOTE_C_SRC="$REMOTE_C_SRC sslutils.c" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OpenSSL not found" >&5 +printf "%s\n" "$as_me: OpenSSL not found" >&6;} + fi + + +printf "%s\n" "#define ENABLE_REMOTE /**/" >>confdefs.h + + REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c" + BUILD_RPCAPD=build-rpcapd + INSTALL_RPCAPD=install-rpcapd + ;; +*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; +esac + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build optimizer debugging code" >&5 +printf %s "checking whether to build optimizer debugging code... " >&6; } +# Check whether --enable-optimizer-dbg was given. +if test ${enable_optimizer_dbg+y} +then : + enableval=$enable_optimizer_dbg; +fi + +if test "$enable_optimizer_dbg" = "yes"; then + +printf "%s\n" "#define BDEBUG 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${enable_optimizer_dbg-no}" >&5 +printf "%s\n" "${enable_optimizer_dbg-no}" >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build parser debugging code" >&5 +printf %s "checking whether to build parser debugging code... " >&6; } +# Check whether --enable-yydebug was given. +if test ${enable_yydebug+y} +then : + enableval=$enable_yydebug; +fi + +if test "$enable_yydebug" = "yes"; then + +printf "%s\n" "#define YYDEBUG 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${enable_yydebug-no}" >&5 +printf "%s\n" "${enable_yydebug-no}" >&6; } + +# +# Look for {f}lex. +# +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LEX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_LEX="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +printf "%s\n" "$LEX" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + + if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%{ +#ifdef __cplusplus +extern "C" +#endif +int yywrap(void); +%} +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ +#ifdef __cplusplus + yyless ((yyinput () != 0)); +#else + yyless ((input () != 0)); +#endif + } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +yywrap (void) +{ + return 1; +} +int +main (void) +{ + return ! yylex (); +} +_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex output file root" >&5 +printf %s "checking for lex output file root... " >&6; } +if test ${ac_cv_prog_lex_root+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +ac_cv_prog_lex_root=unknown +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +printf "%s\n" "$ac_cv_prog_lex_root" >&6; } +if test "$ac_cv_prog_lex_root" = unknown +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot find output from $LEX; giving up on $LEX" >&5 +printf "%s\n" "$as_me: WARNING: cannot find output from $LEX; giving up on $LEX" >&2;} + LEX=: LEXLIB= +fi +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test ${LEXLIB+y} +then : + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lex library" >&5 +printf %s "checking for lex library... " >&6; } +if test ${ac_cv_lib_lex+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ac_save_LIBS="$LIBS" + ac_found=false + for ac_cv_lib_lex in 'none needed' -lfl -ll 'not found'; do + case $ac_cv_lib_lex in #( + 'none needed') : + ;; #( + 'not found') : + break ;; #( + *) : + LIBS="$ac_cv_lib_lex $ac_save_LIBS" ;; #( + *) : + ;; +esac + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_found=: +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if $ac_found; then + break + fi + done + LIBS="$ac_save_LIBS" + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +printf "%s\n" "$ac_cv_lib_lex" >&6; } + if test "$ac_cv_lib_lex" = 'not found' +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: required lex library not found; giving up on $LEX" >&5 +printf "%s\n" "$as_me: WARNING: required lex library not found; giving up on $LEX" >&2;} + LEX=: LEXLIB= +elif test "$ac_cv_lib_lex" = 'none needed' +then : + LEXLIB='' +else $as_nop + LEXLIB=$ac_cv_lib_lex +fi + ac_save_LIBS="$LIBS" + LIBS= + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing yywrap" >&5 +printf %s "checking for library containing yywrap... " >&6; } +if test ${ac_cv_search_yywrap+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char yywrap (); +int +main (void) +{ +return yywrap (); + ; + return 0; +} +_ACEOF +for ac_lib in '' fl l +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_yywrap=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_yywrap+y} +then : + break +fi +done +if test ${ac_cv_search_yywrap+y} +then : + +else $as_nop + ac_cv_search_yywrap=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_yywrap" >&5 +printf "%s\n" "$ac_cv_search_yywrap" >&6; } +ac_res=$ac_cv_search_yywrap +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + LEXLIB="$LIBS" +fi + + LIBS="$ac_save_LIBS" +fi + + +if test "$LEX" != : +then : + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +printf %s "checking whether yytext is a pointer... " >&6; } +if test ${ac_cv_prog_lex_yytext_pointer+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +printf "%s\n" "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +printf "%s\n" "#define YYTEXT_POINTER 1" >>confdefs.h + +fi + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +if test "$LEX" = ":"; then + as_fn_error $? "Neither flex nor lex was found." "$LINENO" 5 +fi + +# +# Make sure {f}lex supports the -P, --header-file, and --nounput flags +# and supports processing our scanner.l. +# +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for capable lex" >&5 +printf %s "checking for capable lex... " >&6; } +if test ${tcpdump_cv_capable_lex+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if $LEX -P pcap_ --header-file=/dev/null --nounput -t $srcdir/scanner.l > /dev/null 2>&1; then + tcpdump_cv_capable_lex=yes + else + tcpdump_cv_capable_lex=insufficient + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_lex" >&5 +printf "%s\n" "$tcpdump_cv_capable_lex" >&6; } +if test $tcpdump_cv_capable_lex = insufficient ; then + as_fn_error $? "$LEX is insufficient to compile libpcap. + libpcap requires Flex 2.5.31 or later, or a compatible version of lex. + If a suitable version of Lex/Flex is available as a non-standard command + and/or not in the PATH, you can specify it using the LEX environment + variable. That said, on some systems the error can mean that Flex/Lex is + actually acceptable, but m4 is not. Likewise, if a suitable version of + m4 (such as GNU M4) is available but has not been detected, you can + specify it using the M4 environment variable." "$LINENO" 5 +fi + +# +# Look for yacc/bison/byacc. +# If it's Bison, we do not want -y, as 1) we will be using -o to cause +# the output for XXX.y to be written to XXX.c and 2) we don't want +# it to issue warnings about stuff not supported by POSIX YACC - we +# want to use that stuff, and don't care whether plain YACC supports +# it or not, we require either Bison or Berkeley YACC. +# +BISON_BYACC="" +# +# Look for Bison. +# +for ac_prog in bison +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_BISON_BYACC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$BISON_BYACC"; then + ac_cv_prog_BISON_BYACC="$BISON_BYACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_BISON_BYACC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +BISON_BYACC=$ac_cv_prog_BISON_BYACC +if test -n "$BISON_BYACC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON_BYACC" >&5 +printf "%s\n" "$BISON_BYACC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$BISON_BYACC" && break +done + +if test x"$BISON_BYACC" != x; then + # + # We found Bison. + # + # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use + # "%pure-parser". + # + bison_major_version=`$BISON_BYACC -V | sed -n 's/.* \([1-9][0-9]*\)\.[0-9][0-9.]*/\1/p'` + bison_minor_version=`$BISON_BYACC -V | sed -n 's/.* [1-9][0-9]*\.\([0-9]+\).*/\1/p'` + if test "$bison_major_version" -lt 2 -o \ + \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \) + then + REENTRANT_PARSER="%pure-parser" + else + REENTRANT_PARSER="%define api.pure" + fi +else + # + # We didn't find Bison; check for Berkeley YACC, under the + # names byacc and yacc. + # + for ac_prog in byacc yacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_BISON_BYACC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$BISON_BYACC"; then + ac_cv_prog_BISON_BYACC="$BISON_BYACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_BISON_BYACC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +BISON_BYACC=$ac_cv_prog_BISON_BYACC +if test -n "$BISON_BYACC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON_BYACC" >&5 +printf "%s\n" "$BISON_BYACC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$BISON_BYACC" && break +done + + if test x"$BISON_BYACC" != x; then + # + # Make sure this is Berkeley YACC, not AT&T YACC; + # the latter doesn't support reentrant parsers. + # Run it with "-V"; that succeeds and reports the + # version number with Berkeley YACC, but will + # (probably) fail with various vendor flavors + # of AT&T YACC. + # + # Hopefully this also eliminates any versions + # of Berkeley YACC that don't support reentrant + # parsers, if there are any. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for capable yacc" >&5 +printf %s "checking for capable yacc... " >&6; } +if test ${tcpdump_cv_capable_yacc+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if $BISON_BYACC -V >/dev/null 2>&1; then + tcpdump_cv_capable_yacc=yes + else + tcpdump_cv_capable_yacc=insufficient + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcpdump_cv_capable_yacc" >&5 +printf "%s\n" "$tcpdump_cv_capable_yacc" >&6; } + if test $tcpdump_cv_capable_yacc = insufficient ; then + as_fn_error $? "$BISON_BYACC is insufficient to compile libpcap. + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them." "$LINENO" 5 + fi + else + # + # OK, we found neither byacc nor yacc. + # + as_fn_error $? "Neither bison, byacc, nor yacc was found. + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them." "$LINENO" 5 + fi + + # + # Berkeley YACC doesn't support "%define api.pure", so use + # "%pure-parser". + # + REENTRANT_PARSER="%pure-parser" +fi + + + +# +# Do various checks for various OSes and versions of those OSes. +# +# Assume, by default, no support for shared libraries and V7/BSD +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. +# +DYEXT="none" +MAN_DEVICES=4 +MAN_FILE_FORMATS=5 +MAN_MISC_INFO=7 +MAN_ADMIN_COMMANDS=8 +case "$host_os" in + +aix*) + +printf "%s\n" "#define _SUN 1" >>confdefs.h + + + # + # AIX makes it fun to build shared and static libraries, + # because they're *both* ".a" archive libraries. We + # build the static library for the benefit of the traditional + # scheme of building libpcap and tcpdump in subdirectories of + # the same directory, with tcpdump statically linked with the + # libpcap in question, but we also build a shared library as + # "libpcap.shareda" and install *it*, rather than the static + # library, as "libpcap.a". + # + DYEXT="shareda" + + case "$V_PCAP" in + + dlpi) + # + # If we're using DLPI, applications will need to + # use /lib/pse.exp if present, as we use the + # STREAMS routines. + # + pseexe="/lib/pse.exp" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $pseexe" >&5 +printf %s "checking for $pseexe... " >&6; } + if test -f $pseexe ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + LIBS="-I:$pseexe" + fi + ;; + + bpf) + # + # If we're using BPF, we need "-lodm" and "-lcfg", as + # we use them to load the BPF module. + # + LIBS="-lodm -lcfg" + ;; + esac + ;; + +darwin*) + DYEXT="dylib" + V_CCOPT="$V_CCOPT -fno-common" + # Check whether --enable-universal was given. +if test ${enable_universal+y} +then : + enableval=$enable_universal; +fi + + if test "$enable_universal" != "no"; then + case "$host_os" in + + darwin[0-7].*) + # + # Pre-Tiger. Build only for 32-bit PowerPC; no + # need for any special compiler or linker flags. + # + ;; + + darwin8.[0123]|darwin8.[0123].*) + # + # Tiger, prior to Intel support. Build + # libraries and executables for 32-bit PowerPC + # and 64-bit PowerPC, with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" + ;; + + darwin8.[456]|darwin8.[456].*) + # + # Tiger, subsequent to Intel support but prior + # to x86-64 support. Build libraries and + # executables for 32-bit PowerPC, 64-bit + # PowerPC, and 32-bit x86, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + ;; + + darwin8.*) + # + # All other Tiger, so subsequent to x86-64 + # support. Build libraries and executables for + # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first. (I'm + # guessing that's what Apple does.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin9.*) + # + # Leopard. Build libraries for 32-bit PowerPC, + # 64-bit PowerPC, 32-bit x86, and x86-64, with + # 32-bit PowerPC first, and build executables + # for 32-bit x86 and 32-bit PowerPC, with 32-bit + # x86 first. (That's what Apple does.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch i386 -arch ppc" + V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" + ;; + + darwin10.*) + # + # Snow Leopard. Build libraries for x86-64, + # 32-bit x86, and 32-bit PowerPC, with x86-64 + # first, and build executables for x86-64 and + # 32-bit x86, with x86-64 first. (That's what + # Apple does, even though Snow Leopard doesn't + # run on PPC, so PPC libpcap runs under Rosetta, + # and Rosetta doesn't support BPF ioctls, so PPC + # programs can't do live captures.) + # + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" + V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" + ;; + + darwin1[1-8]*) + # + # Post-Snow Leopard, pre-Catalina. Build + # libraries for x86-64 and 32-bit x86, with + # x86-64 first, and build executables only for + # x86-64. (That's what Apple does.) This + # requires no special flags for programs. + # + # We check whether we *can* build for i386 and, + # if not, suggest that the user install the + # /usr/include headers if they want to build + # fat. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether building for 32-bit x86 is supported" >&5 +printf %s "checking whether building for 32-bit x86 is supported... " >&6; } + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS -arch i386" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + + # + # OpenSSL installation on macOS seems + # to install only the libs for 64-bit + # x86 - at least that's what Brew does: + # only configure 32-bit builds if we + # don't have OpenSSL. + # + if test "$HAVE_OPENSSL" != yes; then + V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386" + V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + case "$host_os" in + + darwin18.*) + # + # Mojave; you need to install the + # /usr/include headers to get + # 32-bit x86 builds to work. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&5 +printf "%s\n" "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package" >&2;} + ;; + + *) + # + # Pre-Mojave; the command-line + # tools should be sufficient to + # enable 32-bit x86 builds. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&5 +printf "%s\n" "$as_me: WARNING: Compiling for 32-bit x86 gives an error; try installing the command-line tools" >&2;} + ;; + esac + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + ;; + + darwin19*) + # + # Catalina. Build libraries and executables + # only for x86-64. (That's what Apple does; + # 32-bit x86 binaries are not supported on + # Catalina.) + # + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + V_PROG_CCOPT_FAT="-arch x86_64" + V_PROG_LDFLAGS_FAT="-arch x86_64" + ;; + + darwin*) + # + # Post-Catalina. Build libraries and + # executables for x86-64 and ARM64. + # (That's what Apple does, except they + # build for arm64e, which may include + # some of the pointer-checking extensions.) + # + # If we're building with libssl, make sure + # we can build fat with it (i.e., that it + # was built fat); if we can't, don't set + # the target architectures, and just + # build for the host we're on. + # + # Otherwise, just add both of them. + # + if test "$HAVE_OPENSSL" = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether building fat with libssl is supported" >&5 +printf %s "checking whether building fat with libssl is supported... " >&6; } + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS -arch x86_64 -arch arm64" + LDFLAGS="$LDFLAGS $OPENSSL_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main (void) +{ + + SSL_library_init(); + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" + V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + else + V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" + V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" + fi + ;; + esac + fi + ;; + +hpux9*) + +printf "%s\n" "#define HAVE_HPUX9 1" >>confdefs.h + + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.0*) + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.1*) + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux*) + +printf "%s\n" "#define HAVE_HPUX10_20_OR_LATER 1" >>confdefs.h + + if test "`uname -m`" = "ia64"; then + DYEXT="so" + else + DYEXT="sl" + fi + + # + # "-b" builds a shared library; "+h" sets the soname. + # + SHLIB_OPT="-b" + SONAME_OPT="+h" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +irix*) + # + # Use IRIX conventions for man pages; they're the same as the + # System V conventions, except that they use section 8 for + # administrative commands and daemons. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*) + DYEXT="so" + ;; + +osf*) + DYEXT="so" + + # + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. + # Use Tru64 UNIX conventions for man pages; they're the same as + # the System V conventions except that they use section 8 for + # administrative commands and daemons. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + MAN_DEVICES=7 + ;; + +sinix*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if SINIX compiler defines sinix" >&5 +printf %s "checking if SINIX compiler defines sinix... " >&6; } + if test ${ac_cv_cc_sinix_defined+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +int i = sinix; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_cc_sinix_defined=yes +else $as_nop + ac_cv_cc_sinix_defined=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_sinix_defined" >&5 +printf "%s\n" "$ac_cv_cc_sinix_defined" >&6; } + if test $ac_cv_cc_sinix_defined = no ; then + +printf "%s\n" "#define sinix 1" >>confdefs.h + + fi + ;; + +solaris*) + +printf "%s\n" "#define HAVE_SOLARIS 1" >>confdefs.h + + + DYEXT="so" + + # + # Make sure errno is thread-safe, in case we're called in + # a multithreaded program. We don't guarantee that two + # threads can use the *same* pcap_t safely, but the + # current version does guarantee that you can use different + # pcap_t's in different threads, and even that pcap_compile() + # is thread-safe (it wasn't thread-safe in some older versions). + # + V_CCOPT="$V_CCOPT -D_TS_ERRNO" + + case "`uname -r`" in + + 5.12) + ;; + + *) + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + MAN_DEVICES=7D + esac + ;; +esac + + + + + + + + + + +# Check whether --enable-shared was given. +if test ${enable_shared+y} +then : + enableval=$enable_shared; +fi + +test "x$enable_shared" = "xno" && DYEXT="none" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +printf %s "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +printf "%s\n" "no, using $LN_S" >&6; } +fi + + + +rm -f os-proto.h + if test "${LBL_CFLAGS+set}" = set; then + V_CCOPT="$V_CCOPT ${LBL_CFLAGS}" + fi + if test -f .devel ; then + # + # Skip all the warning option stuff on some compilers. + # + if test "$ac_lbl_cc_dont_try_gcc_dashW" != yes; then + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -W option" >&5 +printf %s "checking whether the compiler supports the -W option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -W" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -W " >&5 +printf %s "checking whether -W ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -W" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wall option" >&5 +printf %s "checking whether the compiler supports the -Wall option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wall" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wall " >&5 +printf %s "checking whether -Wall ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wall" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wcomma option" >&5 +printf %s "checking whether the compiler supports the -Wcomma option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wcomma" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wcomma " >&5 +printf %s "checking whether -Wcomma ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wcomma" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + # Warns about safeguards added in case the enums are + # extended + # AC_LBL_CHECK_COMPILER_OPT(V_CCOPT, -Wcovered-switch-default) + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wdocumentation option" >&5 +printf %s "checking whether the compiler supports the -Wdocumentation option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wdocumentation" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wdocumentation " >&5 +printf %s "checking whether -Wdocumentation ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wdocumentation" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wformat-nonliteral option" >&5 +printf %s "checking whether the compiler supports the -Wformat-nonliteral option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wformat-nonliteral" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wformat-nonliteral " >&5 +printf %s "checking whether -Wformat-nonliteral ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wformat-nonliteral" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-noreturn option" >&5 +printf %s "checking whether the compiler supports the -Wmissing-noreturn option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wmissing-noreturn" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-noreturn " >&5 +printf %s "checking whether -Wmissing-noreturn ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-noreturn" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-prototypes option" >&5 +printf %s "checking whether the compiler supports the -Wmissing-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wmissing-prototypes" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-prototypes " >&5 +printf %s "checking whether -Wmissing-prototypes ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-prototypes" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wmissing-variable-declarations option" >&5 +printf %s "checking whether the compiler supports the -Wmissing-variable-declarations option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wmissing-variable-declarations" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wmissing-variable-declarations " >&5 +printf %s "checking whether -Wmissing-variable-declarations ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wmissing-variable-declarations" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wnull-pointer-subtraction option" >&5 +printf %s "checking whether the compiler supports the -Wnull-pointer-subtraction option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wnull-pointer-subtraction" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wnull-pointer-subtraction " >&5 +printf %s "checking whether -Wnull-pointer-subtraction ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wnull-pointer-subtraction" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-arith option" >&5 +printf %s "checking whether the compiler supports the -Wpointer-arith option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wpointer-arith" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-arith " >&5 +printf %s "checking whether -Wpointer-arith ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wpointer-arith" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wpointer-sign option" >&5 +printf %s "checking whether the compiler supports the -Wpointer-sign option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wpointer-sign" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wpointer-sign " >&5 +printf %s "checking whether -Wpointer-sign ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wpointer-sign" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshadow option" >&5 +printf %s "checking whether the compiler supports the -Wshadow option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wshadow" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wshadow " >&5 +printf %s "checking whether -Wshadow ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wshadow" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wshorten-64-to-32 option" >&5 +printf %s "checking whether the compiler supports the -Wshorten-64-to-32 option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wshorten-64-to-32" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wshorten-64-to-32 " >&5 +printf %s "checking whether -Wshorten-64-to-32 ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wshorten-64-to-32" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wsign-compare option" >&5 +printf %s "checking whether the compiler supports the -Wsign-compare option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wsign-compare" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wsign-compare " >&5 +printf %s "checking whether -Wsign-compare ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wsign-compare" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wstrict-prototypes option" >&5 +printf %s "checking whether the compiler supports the -Wstrict-prototypes option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wstrict-prototypes" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wstrict-prototypes " >&5 +printf %s "checking whether -Wstrict-prototypes ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wstrict-prototypes" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wundef option" >&5 +printf %s "checking whether the compiler supports the -Wundef option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wundef" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wundef " >&5 +printf %s "checking whether -Wundef ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wundef" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + # + # This can cause problems with ntohs(), ntohl(), + # htons(), and htonl() on some platforms, such + # as OpenBSD 6.3 with Clang 5.0.1. I guess the + # problem is that the macro that ultimately does + # the byte-swapping involves a conditional + # expression that tests whether the value being + # swapped is a compile-time constant or not, + # using __builtin_constant_p(), and, depending + # on whether it is, does a compile-time swap or + # a run-time swap; perhaps the compiler always + # considers one of the two results of the + # conditional expression is never evaluated, + # because the conditional check is done at + # compile time, and thus always says "that + # expression is never executed". + # + # (Perhaps there should be a way of flagging + # an expression that you *want* evaluated at + # compile time, so that the compiler 1) warns + # if it *can't* be evaluated at compile time + # and 2) *doesn't* warn that the true or false + # branch will never be reached.) + # + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunreachable-code option" >&5 +printf %s "checking whether the compiler supports the -Wunreachable-code option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wunreachable-code" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "xgenerates warnings from ntohs()" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wunreachable-code generates warnings from ntohs()" >&5 +printf %s "checking whether -Wunreachable-code generates warnings from ntohs()... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +unsigned short +testme(unsigned short a) +{ + return ntohs(a); +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunreachable-code" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-but-set-parameter option" >&5 +printf %s "checking whether the compiler supports the -Wunused-but-set-parameter option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wunused-but-set-parameter" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wunused-but-set-parameter " >&5 +printf %s "checking whether -Wunused-but-set-parameter ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunused-but-set-parameter" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-but-set-variable option" >&5 +printf %s "checking whether the compiler supports the -Wunused-but-set-variable option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wunused-but-set-variable" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wunused-but-set-variable " >&5 +printf %s "checking whether -Wunused-but-set-variable ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunused-but-set-variable" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wunused-parameter option" >&5 +printf %s "checking whether the compiler supports the -Wunused-parameter option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wunused-parameter" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wunused-parameter " >&5 +printf %s "checking whether -Wunused-parameter ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wunused-parameter" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the -Wused-but-marked-unused option" >&5 +printf %s "checking whether the compiler supports the -Wused-but-marked-unused option... " >&6; } + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wused-but-marked-unused" + # + # XXX - yes, this depends on the way AC_LANG_WERROR works, + # but no mechanism is provided to turn AC_LANG_WERROR on + # *and then turn it back off*, so that we *only* do it when + # testing compiler options - 15 years after somebody asked + # for it: + # + # https://autoconf.gnu.narkive.com/gTAVmfKD/how-to-cancel-flags-set-by-ac-lang-werror + # + save_ac_c_werror_flag="$ac_c_werror_flag" + ac_c_werror_flag=yes + # + # We use AC_LANG_SOURCE() so that we can control the complete + # content of the program being compiled. We do not, for example, + # want the default "int main()" that AC_LANG_PROGRAM() generates, + # as it will generate a warning with -Wold-style-definition, meaning + # that we would treat it as not working, as the test will fail if + # *any* error output, including a warning due to the flag we're + # testing, is generated; see + # + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # https://www.postgresql.org/message-id/2192993.1591682589%40sss.pgh.pa.us + # + # This may, as per those two messages, be fixed in autoconf 2.70, + # but we only require 2.69 or newer for now. + # + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=yes + # + # The compile supports this; do we have some C code for + # which the warning should *not* appear? + # We test the fourth argument because the third argument + # could contain quotes, breaking the test. + # + if test "x" != "x" + then + CFLAGS="$CFLAGS $ac_lbl_cc_force_warning_errors" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wused-but-marked-unused " >&5 +printf %s "checking whether -Wused-but-marked-unused ... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + # + # Not a problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +else $as_nop + + # + # A problem. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + can_add_to_cflags=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + CFLAGS="$save_CFLAGS" + if test x"$can_add_to_cflags" = "xyes" + then + V_CCOPT="$V_CCOPT -Wused-but-marked-unused" + fi + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + CFLAGS="$save_CFLAGS" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag="$save_ac_c_werror_flag" + + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports generating dependencies" >&5 +printf %s "checking whether the compiler supports generating dependencies... " >&6; } + if test "$GCC" = yes ; then + # + # GCC, or a compiler deemed to be GCC by AC_PROG_CC (even + # though it's not); we assume that, in this case, the flag + # would be -M. + # + ac_lbl_dependency_flag="-M" + else + # + # Not GCC or a compiler deemed to be GCC; what platform is + # this? (We're assuming that if the compiler isn't GCC + # it's the compiler from the vendor of the OS; that won't + # necessarily be true for x86 platforms, where it might be + # the Intel C compiler.) + # + case "$host_os" in + + irix*|osf*|darwin*) + # + # MIPS C for IRIX, DEC C, and clang all use -M. + # + ac_lbl_dependency_flag="-M" + ;; + + solaris*) + # + # Sun C uses -xM. + # + ac_lbl_dependency_flag="-xM" + ;; + + hpux*) + # + # HP's older C compilers don't support this. + # HP's newer C compilers support this with + # either +M or +Make; the older compilers + # interpret +M as something completely + # different, so we use +Make so we don't + # think it works with the older compilers. + # + ac_lbl_dependency_flag="+Make" + ;; + + *) + # + # Not one of the above; assume no support for + # generating dependencies. + # + ac_lbl_dependency_flag="" + ;; + esac + fi + + # + # Is ac_lbl_dependency_flag defined and, if so, does the compiler + # complain about it? + # + # Note: clang doesn't seem to exit with an error status when handed + # an unknown non-warning error, even if you pass it + # -Werror=unknown-warning-option. However, it always supports + # -M, so the fact that this test always succeeds with clang + # isn't an issue. + # + if test ! -z "$ac_lbl_dependency_flag"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: eval \"\$CC \$ac_lbl_dependency_flag conftest.c >/dev/null 2>&1\""; } >&5 + (eval "$CC $ac_lbl_dependency_flag conftest.c >/dev/null 2>&1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes, with $ac_lbl_dependency_flag" >&5 +printf "%s\n" "yes, with $ac_lbl_dependency_flag" >&6; } + DEPENDENCY_CFLAG="$ac_lbl_dependency_flag" + MKDEP='${top_srcdir}/mkdep' + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP='${top_srcdir}/nomkdep' + fi + rm -rf conftest* + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + # + # We can't run mkdep, so have "make depend" do + # nothing. + # + MKDEP='${top_srcdir}/nomkdep' + fi + + + + # + # We used to set -n32 for IRIX 6 when not using GCC (presumed + # to mean that we're using MIPS C or MIPSpro C); it specified + # the "new" faster 32-bit ABI, introduced in IRIX 6.2. I'm + # not sure why that would be something to do *only* with a + # .devel file; why should the ABI for which we produce code + # depend on .devel? + # + os=`echo $host_os | sed -e 's/\([0-9][0-9]*\)[^0-9].*$/\1/'` + name="lbl/os-$os.h" + if test -f $name ; then + ln -s $name os-proto.h + +printf "%s\n" "#define HAVE_OS_PROTO_H 1" >>confdefs.h + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find $name" >&5 +printf "%s\n" "$as_me: WARNING: can't find $name" >&2;} + fi + fi + +# +# Check to see if the sockaddr struct has the 4.4 BSD sa_len member. +# +ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " + #include + #include + +" +if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h + + +fi + + +# +# Check to see if there's a sockaddr_storage structure. +# +ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" " + #include + #include + +" +if test "x$ac_cv_type_struct_sockaddr_storage" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h + + +fi + + +# +# Check to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 +# dl_module_id_1 member. +# +# NOTE: any failure means we conclude that it doesn't have that member, +# so if we don't have DLPI, don't have a header, or +# have one that doesn't declare a dl_hp_ppa_info_t type, we conclude +# it doesn't have that member (which is OK, as either we won't be +# using code that would use that member, or we wouldn't compile in +# any case). +# +ac_fn_c_check_member "$LINENO" "dl_hp_ppa_info_t" "dl_module_id_1" "ac_cv_member_dl_hp_ppa_info_t_dl_module_id_1" " + #include + #include + #include + +" +if test "x$ac_cv_member_dl_hp_ppa_info_t_dl_module_id_1" = xyes +then : + +printf "%s\n" "#define HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1 1" >>confdefs.h + + +fi + + +# +# Various Linux-specific mechanisms. +# +# Check whether --enable-usb was given. +if test ${enable_usb+y} +then : + enableval=$enable_usb; +else $as_nop + enable_usb=yes +fi + + +# +# If somebody requested an XXX-only pcap, that doesn't include +# additional mechanisms. +# +if test "xxx_only" != yes; then + case "$host_os" in + linux*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Linux usbmon USB sniffing support" >&5 +printf %s "checking for Linux usbmon USB sniffing support... " >&6; } + if test "x$enable_usb" != "xno" ; then + +printf "%s\n" "#define PCAP_SUPPORT_LINUX_USBMON 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + # + # Note: if the directory for special files is *EVER* somewhere + # other than the UN*X standard of /dev (which will break any + # software that looks for /dev/null or /dev/tty, for example, + # so doing that is *REALLY* not a good idea), please provide + # some mechanism to determine that directory at *run time*, + # rather than *configure time*, so that it works when doing + # a cross-build, and that works with *multiple* distributions, + # with our without udev, and with multiple versions of udev, + # with udevinfo or udevadm or any other mechanism to get the + # special files directory. + # + # Do we have a version of available? + # If so, we might need it for . + # + ac_fn_c_check_header_compile "$LINENO" "linux/compiler.h" "ac_cv_header_linux_compiler_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_compiler_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_COMPILER_H 1" >>confdefs.h + +fi + + if test "$ac_cv_header_linux_compiler_h" = yes; then + # + # Yes - include it when testing for . + # + ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "#include +" +if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_USBDEVICE_FS_H 1" >>confdefs.h + +fi + + else + ac_fn_c_check_header_compile "$LINENO" "linux/usbdevice_fs.h" "ac_cv_header_linux_usbdevice_fs_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_usbdevice_fs_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_USBDEVICE_FS_H 1" >>confdefs.h + +fi + + fi + if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then + # + # OK, does it define bRequestType? Older versions of the kernel + # define fields with names like "requesttype, "request", and + # "value", rather than "bRequestType", "bRequest", and + # "wValue". + # + ac_fn_c_check_member "$LINENO" "struct usbdevfs_ctrltransfer" "bRequestType" "ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" " + $ac_includes_default + #ifdef HAVE_LINUX_COMPILER_H + #include + #endif + #include + +" +if test "x$ac_cv_member_struct_usbdevfs_ctrltransfer_bRequestType" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 1" >>confdefs.h + + +fi + + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + + # + # Life's too short to deal with trying to get this to compile + # if you don't get the right types defined with + # __KERNEL_STRICT_NAMES getting defined by some other include. + # + # Check whether the includes Just Work. If not, don't turn on + # netfilter support. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netfilter support" >&5 +printf %s "checking whether we can compile the netfilter support... " >&6; } + if test ${ac_cv_netfilter_can_compile+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#include +#include +#include + +#include +#include +#include +#include +#include +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_netfilter_can_compile=yes +else $as_nop + ac_cv_netfilter_can_compile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_netfilter_can_compile" >&5 +printf "%s\n" "$ac_cv_netfilter_can_compile" >&6; } + if test $ac_cv_netfilter_can_compile = yes ; then + +printf "%s\n" "#define PCAP_SUPPORT_NETFILTER 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c" + fi + ;; + esac +fi + + + +# Check whether --enable-netmap was given. +if test ${enable_netmap+y} +then : + enableval=$enable_netmap; +else $as_nop + enable_netmap=yes +fi + + +if test "x$enable_netmap" != "xno" ; then + # + # Check whether net/netmap_user.h is usable if NETMAP_WITH_LIBS is + # defined; it's not usable on DragonFly BSD 4.6 if NETMAP_WITH_LIBS + # is defined, for example, as it includes a nonexistent malloc.h + # header. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can compile the netmap support" >&5 +printf %s "checking whether we can compile the netmap support... " >&6; } + if test ${ac_cv_net_netmap_user_can_compile+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#define NETMAP_WITH_LIBS +#include +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_net_netmap_user_can_compile=yes +else $as_nop + ac_cv_net_netmap_user_can_compile=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_net_netmap_user_can_compile" >&5 +printf "%s\n" "$ac_cv_net_netmap_user_can_compile" >&6; } + if test $ac_cv_net_netmap_user_can_compile = yes ; then + +printf "%s\n" "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c" + fi + +fi + +# Check for DPDK support. + +# Check whether --with-dpdk was given. +if test ${with_dpdk+y} +then : + withval=$with_dpdk; + if test "$withval" = no + then + # User doesn't want DPDK support. + want_dpdk=no + elif test "$withval" = yes + then + # User wants DPDK support but hasn't specified a directory. + want_dpdk=yes + else + # User wants DPDK support and has specified a directory, + # so use the provided value. + want_dpdk=yes + dpdk_dir=$withval + fi + +else $as_nop + + if test "$V_PCAP" = dpdk; then + # User requested DPDK-only libpcap, so we'd better have + # the DPDK API. + want_dpdk=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want DPDK support. + want_dpdk=no + else + # + # Use DPDK API if present, otherwise don't + # + want_dpdk=ifpresent + fi + +fi + + +if test "$want_dpdk" != no; then + # + # The user didn't explicitly say they don't want DPDK, + # so see if we have it. + # + # We only try to find it using pkg-config; DPDK is *SO* + # complicated - DPDK 19.02, for example, has about 117(!) + # libraries, and the precise set of libraries required has + # changed over time - so attempting to guess which libraries + # you need, and hardcoding that in an attempt to find the + # libraries without DPDK, rather than relying on DPDK to + # tell you, with a .pc file, what libraries are needed, + # is *EXTREMELY* fragile and has caused some bug reports, + # so we're just not going to do it. + # + # If that causes a problem, the only thing we will do is + # accept an alternative way of finding the appropriate + # library set for the installed version of DPDK that is + # as robust as pkg-config (i.e., it had better work as well + # as pkg-config with *ALL* versions of DPDK that provide a + # libdpdk.pc file). + # + # If --with-dpdk={path} was specified, add {path}/pkgconfig + # to PKG_CONFIG_PATH, so we look for the .pc file there, + # first. + # + save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" + if test -n "$dpdk_dir"; then + PKG_CONFIG_PATH="$dpdk_dir:$PKG_CONFIG_PATH" + fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libdpdk with pkg-config" >&5 +printf %s "checking for libdpdk with pkg-config... " >&6; } +if test -n "$PKG_CONFIG"; then + + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdpdk\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libdpdk") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # + # The package was found, so try to get its C flags and + # libraries. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + if test ! -n "$DPDK_CFLAGS"; then + DPDK_CFLAGS=`$PKG_CONFIG --cflags "libdpdk" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --cflags "libdpdk" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --cflags "libdpdk" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --cflags \"libdpdk\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$DPDK_LIBS"; then + DPDK_LIBS=`$PKG_CONFIG --libs "libdpdk" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs "libdpdk" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs "libdpdk" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs \"libdpdk\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$DPDK_LIBS_STATIC"; then + DPDK_LIBS_STATIC=`$PKG_CONFIG --libs --static "libdpdk" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs --static "libdpdk" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs --static "libdpdk" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs --static \"libdpdk\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + + found_dpdk=yes + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + : + fi +else + # No pkg-config, so obviously not found with pkg-config. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: pkg-config not found" >&5 +printf "%s\n" "pkg-config not found" >&6; } + : +fi + + PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" + + # + # Did we find DPDK? + # + if test "$found_dpdk" = yes; then + # + # Found it. + # + # We call rte_eth_dev_count_avail(), and older versions + # of DPDK didn't have it, so check for it. + # + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS $DPDK_CFLAGS" + LIBS="$LIBS $DPDK_LIBS" + ac_fn_c_check_func "$LINENO" "rte_eth_dev_count_avail" "ac_cv_func_rte_eth_dev_count_avail" +if test "x$ac_cv_func_rte_eth_dev_count_avail" = xyes +then : + +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + fi + + if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then + # + # We found a usable DPDK. + # + # Check whether the rte_ether.h file defines + # struct ether_addr or struct rte_ether_addr. + # + # ("API compatibility? That's for losers!") + # + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS $DPDK_CFLAGS" + LIBS="$LIBS $DPDK_LIBS" + ac_fn_c_check_type "$LINENO" "struct rte_ether_addr" "ac_cv_type_struct_rte_ether_addr" " + #include + +" +if test "x$ac_cv_type_struct_rte_ether_addr" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_RTE_ETHER_ADDR 1" >>confdefs.h + + +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + + # + # We can build with DPDK. + # + V_INCLS="$V_INCLS $DPDK_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DPDK_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DPDK_LIBS_STATIC" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE libdpdk" + +printf "%s\n" "#define PCAP_SUPPORT_DPDK 1" >>confdefs.h + + if test $V_PCAP != dpdk ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c" + fi + else + # + # We didn't find a usable DPDK. + # If we required it (with --with-dpdk or --with-pcap=dpdk), + # fail with an appropriate message telling the user what + # the problem was, otherwise note the problem with a + # warning. + # + if test "$found_dpdk" != yes; then + # + # Not found with pkg-config. Note that we + # require that DPDK must be findable with + # pkg-config. + # + if test "$V_PCAP" = dpdk; then + # + # User requested DPDK-only capture support. + # + as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but +we couldn't find DPDK with pkg-config. Make sure that pkg-config is +installed, that DPDK 18.02.2 or later is installed, and that DPDK +provides a .pc file." "$LINENO" 5 + fi + + if test "$want_dpdk" = yes; then + # + # User requested that libpcap include + # DPDK capture support. + # + as_fn_error $? "DPDK support requested with --with-dpdk, but we +couldn't find DPDK with pkg-config. Make sure that pkg-config +is installed, that DPDK 18.02.2 or later is installed, and that +DPDK provides .pc file." "$LINENO" 5 + fi + + # + # User didn't indicate whether they wanted DPDK + # or not; just warn why we didn't find it. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: We couldn't find DPDK with pkg-config. If +you want DPDK support, make sure that pkg-config is installed, +that DPDK 18.02.2 or later is installed, and that DPDK provides a +.pc file." >&5 +printf "%s\n" "$as_me: WARNING: We couldn't find DPDK with pkg-config. If +you want DPDK support, make sure that pkg-config is installed, +that DPDK 18.02.2 or later is installed, and that DPDK provides a +.pc file." >&2;} + elif test "$ac_cv_func_rte_eth_dev_count_avail" != yes; then + # + # Found with pkg-config, but we couldn't compile + # a program that calls rte_eth_dev_count(); we + # probably have the developer package installed, + # but don't have a sufficiently recent version + # of DPDK. Note that we need a sufficiently + # recent version of DPDK. + # + if test "$V_PCAP" = dpdk; then + # + # User requested DPDK-only capture support. + # + as_fn_error $? "DPDK support requested with --with-pcap=dpdk, but we +can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later +is installed." "$LINENO" 5 + fi + + if test "$want_dpdk" = yes; then + # + # User requested that libpcap include + # DPDK capture support. + # + as_fn_error $? "DPDK support requested with --with-dpdk, but +we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 +or later is DPDK is installed." "$LINENO" 5 + fi + + # + # User didn't indicate whether they wanted DPDK + # or not; just warn why we didn't find it. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: DPDK was found, but we can't compile libpcap with it. +Make sure that DPDK 18.02.2 or later is installed." >&5 +printf "%s\n" "$as_me: WARNING: DPDK was found, but we can't compile libpcap with it. +Make sure that DPDK 18.02.2 or later is installed." >&2;} + fi + fi +fi + + +# Check whether --enable-bluetooth was given. +if test ${enable_bluetooth+y} +then : + enableval=$enable_bluetooth; +else $as_nop + enable_bluetooth=ifsupportavailable +fi + + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want Bluetooth support. + enable_bluetooth=no +fi + +if test "x$enable_bluetooth" != "xno" ; then + case "$host_os" in + linux*) + ac_fn_c_check_header_compile "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes +then : + + # + # We have bluetooth.h, so we support Bluetooth + # sniffing. + # + +printf "%s\n" "#define PCAP_SUPPORT_BT 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5 +printf "%s\n" "$as_me: Bluetooth sniffing is supported" >&6;} + ac_lbl_bluetooth_available=yes + + # + # OK, does struct sockaddr_hci have an hci_channel + # member? + # + ac_fn_c_check_member "$LINENO" "struct sockaddr_hci" "hci_channel" "ac_cv_member_struct_sockaddr_hci_hci_channel" " + #include + #include + +" +if test "x$ac_cv_member_struct_sockaddr_hci_hci_channel" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL 1" >>confdefs.h + + + # + # Yes; is HCI_CHANNEL_MONITOR defined? + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if HCI_CHANNEL_MONITOR is defined" >&5 +printf %s "checking if HCI_CHANNEL_MONITOR is defined... " >&6; } + if test ${ac_cv_lbl_hci_channel_monitor_is_defined+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main (void) +{ + + int i = HCI_CHANNEL_MONITOR; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define PCAP_SUPPORT_BT_MONITOR 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi + + +else $as_nop + + # + # We don't have bluetooth.h, so we don't support + # Bluetooth sniffing. + # + if test "x$enable_bluetooth" = "xyes" ; then + as_fn_error $? "Bluetooth sniffing is not supported; install bluez-lib devel to enable it" "$LINENO" 5 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&5 +printf "%s\n" "$as_me: Bluetooth sniffing is not supported; install bluez-lib devel to enable it" >&6;} + fi + +fi + + ;; + *) + if test "x$enable_bluetooth" = "xyes" ; then + as_fn_error $? "no Bluetooth sniffing support implemented for $host_os" "$LINENO" 5 + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: no Bluetooth sniffing support implemented for $host_os" >&5 +printf "%s\n" "$as_me: no Bluetooth sniffing support implemented for $host_os" >&6;} + fi + ;; + esac + +fi + +# Check whether --enable-dbus was given. +if test ${enable_dbus+y} +then : + enableval=$enable_dbus; +else $as_nop + enable_dbus=ifavailable +fi + + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want D-Bus support. + enable_dbus=no +fi + +if test "x$enable_dbus" != "xno"; then + if test "x$enable_dbus" = "xyes"; then + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on macOS; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user requested it, so fail. + # + as_fn_error $? "Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS" "$LINENO" 5 + esac + else + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on macOS; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user didn't explicitly request it, so just + # silently refuse to enable it. + # + enable_dbus="no" + ;; + esac + fi +fi + +if test "x$enable_dbus" != "xno"; then + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dbus-1 with pkg-config" >&5 +printf %s "checking for dbus-1 with pkg-config... " >&6; } +if test -n "$PKG_CONFIG"; then + + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # + # The package was found, so try to get its C flags and + # libraries. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + if test ! -n "$DBUS_CFLAGS"; then + DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --cflags "dbus-1" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --cflags "dbus-1" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --cflags \"dbus-1\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$DBUS_LIBS"; then + DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs "dbus-1" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs "dbus-1" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs \"dbus-1\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$DBUS_LIBS_STATIC"; then + DBUS_LIBS_STATIC=`$PKG_CONFIG --libs --static "dbus-1" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs --static "dbus-1" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs --static "dbus-1" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs --static \"dbus-1\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS $DBUS_CFLAGS" + LIBS="$LIBS $DBUS_LIBS" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the D-Bus library defines dbus_connection_read_write" >&5 +printf %s "checking whether the D-Bus library defines dbus_connection_read_write... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + + #include + #include + + #include +int +main (void) +{ +return dbus_connection_read_write(NULL, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define PCAP_SUPPORT_DBUS 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c" + V_INCLS="$V_INCLS $DBUS_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DBUS_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DBUS_LIBS_STATIC" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE dbus-1" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + if test "x$enable_dbus" = "xyes"; then + as_fn_error $? "--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()" "$LINENO" 5 + fi + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + + if test "x$enable_dbus" = "xyes"; then + as_fn_error $? "--enable-dbus was given, but the dbus-1 package is not installed" "$LINENO" 5 + fi + + fi +else + # No pkg-config, so obviously not found with pkg-config. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: pkg-config not found" >&5 +printf "%s\n" "pkg-config not found" >&6; } + + if test "x$enable_dbus" = "xyes"; then + as_fn_error $? "--enable-dbus was given, but the dbus-1 package is not installed" "$LINENO" 5 + fi + +fi + + +fi + +# Check whether --enable-rdma was given. +if test ${enable_rdma+y} +then : + enableval=$enable_rdma; +else $as_nop + enable_rdma=ifavailable +fi + + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want RDMA support. + enable_rdma=no +fi + +if test "x$enable_rdma" != "xno"; then + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libibverbs with pkg-config" >&5 +printf %s "checking for libibverbs with pkg-config... " >&6; } +if test -n "$PKG_CONFIG"; then + + if { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libibverbs\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libibverbs") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # + # The package was found, so try to get its C flags and + # libraries. + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 +printf "%s\n" "found" >&6; } + if test ! -n "$LIBIBVERBS_CFLAGS"; then + LIBIBVERBS_CFLAGS=`$PKG_CONFIG --cflags "libibverbs" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --cflags "libibverbs" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --cflags "libibverbs" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --cflags \"libibverbs\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$LIBIBVERBS_LIBS"; then + LIBIBVERBS_LIBS=`$PKG_CONFIG --libs "libibverbs" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs "libibverbs" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs "libibverbs" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs \"libibverbs\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + if test ! -n "$LIBIBVERBS_LIBS_STATIC"; then + LIBIBVERBS_LIBS_STATIC=`$PKG_CONFIG --libs --static "libibverbs" 2>/dev/null` + if test "x$?" != "x0"; then + # + # That failed - report an error. + # Re-run the command, telling pkg-config to print an error + # message, capture the error message, and report it. + # This causes the configuration script to fail, as it means + # the script is almost certainly doing something wrong. + # + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + _pkg_error_string=`$PKG_CONFIG --short-errors --print-errors --libs --static "libibverbs" 2>&1` + else + _pkg_error_string=`$PKG_CONFIG --print-errors --libs --static "libibverbs" 2>&1` + fi + as_fn_error $? "$PKG_CONFIG --libs --static \"libibverbs\" failed: $_pkg_error_string" "$LINENO" 5 + fi + fi + + found_libibverbs=yes + LIBIBVERBS_REQUIRES_PRIVATE="libibverbs" + + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + : + fi +else + # No pkg-config, so obviously not found with pkg-config. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: pkg-config not found" >&5 +printf "%s\n" "pkg-config not found" >&6; } + : +fi + + + if test "x$found_libibverbs" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ibv_get_device_list in -libverbs" >&5 +printf %s "checking for ibv_get_device_list in -libverbs... " >&6; } +if test ${ac_cv_lib_ibverbs_ibv_get_device_list+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-libverbs $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char ibv_get_device_list (); +int +main (void) +{ +return ibv_get_device_list (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ibverbs_ibv_get_device_list=yes +else $as_nop + ac_cv_lib_ibverbs_ibv_get_device_list=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ibverbs_ibv_get_device_list" >&5 +printf "%s\n" "$ac_cv_lib_ibverbs_ibv_get_device_list" >&6; } +if test "x$ac_cv_lib_ibverbs_ibv_get_device_list" = xyes +then : + + found_libibverbs=yes + LIBIBVERBS_CFLAGS="" + LIBIBVERBS_LIBS="-libverbs" + # XXX - at least on Ubuntu 20.04, there are many more + # libraries needed; is there any platform where + # libibverbs is available but where pkg-config isn't + # available or libibverbs doesn't use it? If not, + # we should only use pkg-config for it. + LIBIBVERBS_LIBS_STATIC="-libverbs" + LIBIBVERBS_LIBS_PRIVATE="-libverbs" + + +fi + + fi + + if test "x$found_libibverbs" = "xyes"; then + + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + + CFLAGS="$CFLAGS $LIBIBVERBS_CFLAGS" + LIBS="$LIBS $LIBIBVERBS_LIBS" + ac_fn_c_check_header_compile "$LINENO" "infiniband/verbs.h" "ac_cv_header_infiniband_verbs_h" "$ac_includes_default" +if test "x$ac_cv_header_infiniband_verbs_h" = xyes +then : + + # + # ibv_create_flow may be defined as a static inline + # function in infiniband/verbs.h, so we can't + # use AC_CHECK_LIB. + # + # Too bad autoconf has no AC_SYMBOL_EXISTS() + # macro that works like CMake's check_symbol_exists() + # function, to check do a compile check like + # this (they do a clever trick to avoid having + # to know the function's signature). + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether libibverbs defines ibv_create_flow" >&5 +printf %s "checking whether libibverbs defines ibv_create_flow... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main (void) +{ + + (void) ibv_create_flow((struct ibv_qp *) NULL, + (struct ibv_flow_attr *) NULL); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + found_usable_libibverbs=yes + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi + + + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + LDFLAGS="$save_LDFLAGS" + + fi + + if test "x$found_usable_libibverbs" = "xyes" + then + +printf "%s\n" "#define PCAP_SUPPORT_RDMASNIFF 1" >>confdefs.h + + MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c" + CFLAGS="$LIBIBVERBS_CFLAGS $CFLAGS" + ADDITIONAL_LIBS="$LIBIBVERBS_LIBS $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="$LIBIBVERBS_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" + LIBS_PRIVATE="$LIBIBVERBS_LIBS_PRIVATE $LIBS_PRIVATE" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE $LIBIBVERBS_REQUIRES_PRIVATE" + fi + +fi + +# +# If this is a platform where we need to have the .pc file and +# pcap-config script supply an rpath option to specify the directory +# in which the libpcap shared library is installed, and the install +# prefix /usr (meaning we're not installing a system library), provide +# the rpath option. +# +# (We must check $prefix, as $libdir isn't necessarily /usr/lib in this +# case - for example, Linux distributions for 64-bit platforms that +# also provide support for binaries for a 32-bit version of the +# platform may put the 64-bit libraries, the 32-bit libraries, or both +# in directories other than /usr/lib.) +# +# In AIX, do we have to do this? +# +# In Darwin-based OSes, the full paths of the shared libraries with +# which the program was linked are stored in the executable, so we don't +# need to provide an rpath option. +# +# With the HP-UX linker, directories specified with -L are, by default, +# added to the run-time search path, so we don't need to supply them. +# +# For Tru64 UNIX, "-rpath" works with DEC's^WCompaq's^WHP's C compiler +# for Alpha, but isn't documented as working with GCC, and no GCC- +# compatible option is documented as working with the DEC compiler. +# If anybody needs this on Tru64/Alpha, they're welcome to figure out a +# way to make it work. +# +# This must *not* depend on the compiler, as, on platforms where there's +# a GCC-compatible compiler and a vendor compiler, we need to work with +# both. +# +if test "$prefix" != "/usr"; then + case "$host_os" in + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|haiku*|midipix*|gnu*) + # + # Platforms where the "native" C compiler is GCC or + # accepts compatible command-line arguments, and the + # "native" linker is the GNU linker or accepts + # compatible command-line arguments. + # + RPATH="-Wl,-rpath,\${libdir}" + ;; + + solaris*) + # + # Sun/Oracle's linker, the GNU linker, and + # GNU-compatible linkers all support -R. + # + RPATH="-Wl,-R,\${libdir}" + ;; + esac +fi + + + # Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test ${ac_cv_path_install+y}; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +ac_config_headers="$ac_config_headers config.h" + + + + + + + + + + + + + + + + + +# +# We're done with configuration operations; add ADDITIONAL_LIBS and +# ADDITIONAL_LIBS_STATIC to LIBS and LIBS_STATIC, respectively. +# +LIBS="$ADDITIONAL_LIBS $LIBS" +LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $LIBS_STATIC" + +ac_config_commands="$ac_config_commands default-1" + +ac_config_files="$ac_config_files Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile testprogs/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else $as_nop + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + +# The user is always right. +if ${PATH_SEPARATOR+false} :; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else $as_nop + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else $as_nop + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by pcap $as_me 1.10.5, which was +generated by GNU Autoconf 2.71. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config='$ac_cs_config_escaped' +ac_cs_version="\\ +pcap config.status 1.10.5 +configured by $0, generated by GNU Autoconf 2.71, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2021 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + printf "%s\n" "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + printf "%s\n" "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + printf "%s\n" "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + printf "%s\n" "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "grammar.y") CONFIG_FILES="$CONFIG_FILES grammar.y" ;; + "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;; + "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;; + "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;; + "pcap-savefile.manfile") CONFIG_FILES="$CONFIG_FILES pcap-savefile.manfile" ;; + "pcap.3pcap") CONFIG_FILES="$CONFIG_FILES pcap.3pcap" ;; + "pcap_compile.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_compile.3pcap" ;; + "pcap_datalink.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_datalink.3pcap" ;; + "pcap_dump_open.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_dump_open.3pcap" ;; + "pcap_get_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_get_tstamp_precision.3pcap" ;; + "pcap_list_datalinks.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_datalinks.3pcap" ;; + "pcap_list_tstamp_types.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_tstamp_types.3pcap" ;; + "pcap_open_dead.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_dead.3pcap" ;; + "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;; + "pcap_set_immediate_mode.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_immediate_mode.3pcap" ;; + "pcap_set_tstamp_precision.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_precision.3pcap" ;; + "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;; + "rpcapd/Makefile") CONFIG_FILES="$CONFIG_FILES rpcapd/Makefile" ;; + "rpcapd/rpcapd.manadmin") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd.manadmin" ;; + "rpcapd/rpcapd-config.manfile") CONFIG_FILES="$CONFIG_FILES rpcapd/rpcapd-config.manfile" ;; + "testprogs/Makefile") CONFIG_FILES="$CONFIG_FILES testprogs/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers + test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`printf "%s\n" "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "default-1":C) if test -f .devel; then + echo timestamp > stamp-h + cat $srcdir/Makefile-devel-adds >> Makefile + make depend || exit 1 +fi ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + +exit 0 + diff --git a/src/libpcap-1.10.5/configure.ac b/src/libpcap-1.10.5/configure.ac new file mode 100644 index 0000000000..accb2589fa --- /dev/null +++ b/src/libpcap-1.10.5/configure.ac @@ -0,0 +1,3234 @@ +dnl +dnl Copyright (c) 1994, 1995, 1996, 1997 +dnl The Regents of the University of California. All rights reserved. +dnl +dnl Process this file with autoconf to produce a configure script. +dnl + +# +# See +# +# https://ftp.gnu.org/gnu/config/README +# +# for the URLs to use to fetch new versions of config.guess and +# config.sub. +# + +AC_PREREQ(2.69) + +AC_INIT(pcap, m4_esyscmd_s([cat VERSION])) +AC_CONFIG_SRCDIR(pcap.c) +AC_SUBST(PACKAGE_NAME) + +# +# These are the variables that are used in Makefile, pcap-config, and +# libpcap.pc. +# +# CFLAGS: inherited from the environment, not modified by us except +# for flags required for the platform for which we're building (and +# except temporarily during tests that involve compilation). Used only +# when compiling C source. +# +# LDFLAGS: inherited from the environment, not modified by us. +# +# LIBS: inherited from the environment; we add libraries required by +# libpcap. Libraries that the core libpcap code requires are added +# first; libraries required by additional pcap modules are first +# added to ADDITIONAL_LIBS, and only added to LIBS at the end, after +# we're finished doing configuration tests for the modules. +# +# LIBS_STATIC: libraries with which a program using the libpcap *static* +# library needs to be linked. This is a superset of LIBS, used in +# pcap-config, so that "pcap-config --libs --static" will report them. +# Initialized to LIBS. +# +# REQUIRES_PRIVATE: pkg-config package names for additional libraries +# with which a program using the libpcap *static* library needs to be +# linked and for which a .pc file exists. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them, and so that +# those libraries will be determined using the library's .pc file, not +# from our .pc file. Initialized to an empty string. +# +# V_CCOPT: additional compiler flags other than -I and -D flags +# needed when compiling libpcap. Used in Makefile for both C and +# C++ source. +# +# V_DEFS: additional -D compiler flags needed when compiling +# libpcap. Used in Makefile for both C and C++ source. +# +# V_INCLS: additional -I compiler flags needed when compiling +# libpcap. Used in Makefile for both C and C++ source. +# +# ADDITIONAL_LIBS: additional libraries with which the libpcap dynamic +# library needs to be linked. Used in Makefile; not used in pcap-config +# or libpcap.pc, as, in all platforms on which we run, if a dynamic +# library is linked with other dynamic libraries, a program using +# that dynamic library doesn't have to link with those libraries - +# they will be automatically loaded at run time. Initialized to an +# empty string. +# +# ADDITIONAL_LIBS_STATIC: additional libraries with which a program +# using the libpcap *static* library needs to be linked. This is used +# in pcap-config, so that "pcap-config --libs --static" will report +# them. Initialized to an empty string. +# +# REQUIRES_PRIVATE: pkg-config package names for additional libraries +# with which a program using the libpcap *static* library needs to be +# linked and for which a .pc file exists. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them, and so that +# those libraries will be determined using the library's .pc file, not +# from our .pc file. Initialized to an empty string. +# +# LIBS_PRIVATE: pkg-config package names for additional libraries with +# which a program using the libpcap *static* library needs to be linked +# and for which a .pc file does not exist. This is used in libpcap.pc, +# so that "pkg-config --libs --static" will report them (those libraries +# cannot be determined using the library's .pc file, as there is no such +# file, so it has to come from our .pc file. Initialized to an empty +# string. +# +LIBS_STATIC="" +REQUIRES_PRIVATE="" +LIBS_PRIVATE="" + +AC_SUBST(V_CCOPT) +AC_SUBST(V_DEFS) +AC_SUBST(V_INCLS) +AC_SUBST(LIBS_STATIC) +AC_SUBST(REQUIRES_PRIVATE) +AC_SUBST(LIBS_PRIVATE) + +AC_CANONICAL_SYSTEM + +AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS) +# +# We require C99 or later. +# Try to get it, which may involve adding compiler flags; +# if that fails, give up. +# +AC_PROG_CC_C99 +if test "$ac_cv_prog_cc_c99" = "no"; then + AC_MSG_ERROR([The C compiler does not support C99]) +fi + +# +# Get the size of a void *, to determine whether this is a 32-bit +# or 64-bit build. +# +AC_CHECK_SIZEOF([void *]) +ac_lbl_c_sizeof_void_p="$ac_cv_sizeof_void_p" + +# +# Get the size of a time_t, to know whether it's 32-bit or 64-bit. +# +AC_CHECK_SIZEOF([time_t],,[#include ]) + +AC_LBL_C_INIT(V_CCOPT, V_INCLS) +AC_LBL_SHLIBS_INIT +AC_LBL_C_INLINE +AC_PCAP_C___ATOMICS + +# +# Try to arrange for large file support. +# +AC_SYS_LARGEFILE +AC_FUNC_FSEEKO + +dnl +dnl Even if were, on all OSes that support BPF, fixed to +dnl include , and we were to drop support for older +dnl releases without that fix, so that pcap-bpf.c doesn't need to +dnl include , the test program in "AC_LBL_FIXINCLUDES" +dnl in "aclocal.m4" uses it, so we would still have to test for it +dnl and set "HAVE_SYS_IOCCOM_H" if we have it, otherwise +dnl "AC_LBL_FIXINCLUDES" wouldn't work on some platforms such as Solaris. +dnl +AC_CHECK_HEADERS(sys/ioccom.h sys/sockio.h) +AC_CHECK_HEADERS(netpacket/packet.h) + +# +# Check whether the platform for which we're compiling requires extra +# defines and libraries. If so, add them to CFLAGS and LIBS, as we want +# all subsequent tests to be done with those defines and libraries. +# +case "$host_os" in +haiku*) + # + # Haiku needs _BSD_SOURCE for the _IO* macros because it doesn't + # use them. + # + CFLAGS="$CFLAGS -D_BSD_SOURCE" + # + # Haiku has getpass in libbsd. + # + AC_CHECK_LIB(bsd, getpass) + ;; +esac + +AC_LBL_SAVE_CHECK_STATE +AC_LBL_FIXINCLUDES +AC_LBL_RESTORE_CHECK_STATE + +AC_CHECK_FUNC(strerror_r, + [ + # + # We have strerror_r; if we define _GNU_SOURCE, is it a + # POSIX-compliant strerror_r() or a GNU strerror_r()? + # + AC_MSG_CHECKING(whether strerror_r is GNU-style) + AC_COMPILE_IFELSE( + [ + AC_LANG_SOURCE( +#define _GNU_SOURCE +#include + +/* Define it GNU-style; that will cause an error if it's not GNU-style */ +extern char *strerror_r(int, char *, size_t); + +int +main(void) +{ + return 0; +} +) + ], + [ + # GNU-style + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GNU_STRERROR_R,, + [Define to 1 if you have a GNU-style `strerror_r' function.]) + ], + [ + AC_MSG_RESULT(no) + AC_DEFINE(HAVE_POSIX_STRERROR_R,, + [Define to 1 if you have a POSIX-style `strerror_r' function.]) + ]) + ], + [ + # + # We don't have strerror_r; do we have _wcserror_s? + # + AC_CHECK_FUNCS(_wcserror_s) + ]) + +# +# Thanks, IBM, for not providing vsyslog() in AIX! +# +AC_CHECK_FUNCS(vsyslog) + +# +# Make sure we have vsnprintf() and snprintf(); we require them. +# +AC_CHECK_FUNC(vsnprintf,, + AC_MSG_ERROR([vsnprintf() is required but wasn't found])) +AC_CHECK_FUNC(snprintf,, + AC_MSG_ERROR([snprintf() is required but wasn't found])) + +needasprintf=no +AC_CHECK_FUNCS(vasprintf asprintf,, + [needasprintf=yes]) +if test $needasprintf = yes; then + AC_LIBOBJ([asprintf]) +fi + +needstrlcat=no +AC_CHECK_FUNCS(strlcat,, + [needstrlcat=yes]) +if test $needstrlcat = yes; then + AC_LIBOBJ([strlcat]) +fi + +needstrlcpy=no +AC_CHECK_FUNCS(strlcpy,, + [needstrlcpy=yes]) +if test $needstrlcpy = yes; then + AC_LIBOBJ([strlcpy]) +fi + +needstrtok_r=no +AC_CHECK_FUNCS(strtok_r,, + [needstrtok_r=yes]) +if test $needstrtok_r = yes; then + AC_LIBOBJ([strtok_r]) +fi + +# +# Do we have ffs(), and is it declared in ? +# +AC_CHECK_FUNCS(ffs) +if test "$ac_cv_func_ffs" = yes; then + # + # We have ffs(); is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ffs(). + # + AC_CHECK_DECL(ffs, + [ + AC_DEFINE(STRINGS_H_DECLARES_FFS,, + [Define to 1 if strings.h declares `ffs']) + ],, + [ +#include + ]) +fi + +# +# Do this before checking for ether_hostton(), as it's a +# "getaddrinfo()-ish function". +# +AC_LBL_LIBRARY_NET + +# +# Check for reentrant versions of getnetbyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getnetbyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getnetbyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +AC_CHECK_DECL(getnetbyname_r, + [ + AC_MSG_CHECKING([for the Linux getnetbyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct netent netent_buf; + char buf[1024]; + struct netent *resultp; + int h_errnoval; + + return getnetbyname_r((const char *)0, &netent_buf, buf, sizeof buf, &resultp, &h_errnoval); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LINUX_GETNETBYNAME_R, 1, + [define if we have the Linux getnetbyname_r()]) + ], + [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([for Solaris/IRIX getnetbyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct netent netent_buf; + char buf[1024]; + + return getnetbyname_r((const char *)0, &netent_buf, buf, (int)sizeof buf) != NULL; + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOLARIS_IRIX_GETNETBYNAME_R, 1, + [define if we have the Solaris/IRIX getnetbyname_r()]) + ], + [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([for AIX getnetbyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct netent netent_buf; + struct netent_data net_data; + + return getnetbyname_r((const char *)0, &netent_buf, &net_data); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_AIX_GETNETBYNAME_R, 1, + [define if we have the AIX getnetbyname_r()]) + ], + [ + AC_MSG_RESULT(no) + ]) + ]) + ]) + ],,[#include ]) + +# +# Check for reentrant versions of getprotobyname_r(), as provided by +# Linux (glibc), Solaris/IRIX, and AIX (with three different APIs!). +# If we don't find one, we just use getprotobyname(), which uses +# thread-specific data on many platforms, but doesn't use it on +# NetBSD or OpenBSD, and may not use it on older versions of other +# platforms. +# +# Only do the check if we have a declaration of getprotobyname_r(); +# without it, we can't check which API it has. (We assume that +# if there's a declaration, it has a prototype, so that the API +# can be checked.) +# +AC_CHECK_DECL(getprotobyname_r, + [ + AC_MSG_CHECKING([for the Linux getprotobyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct protoent protoent_buf; + char buf[1024]; + struct protoent *resultp; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, sizeof buf, &resultp); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LINUX_GETPROTOBYNAME_R, 1, + [define if we have the Linux getprotobyname_r()]) + ], + [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([for Solaris/IRIX getprotobyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct protoent protoent_buf; + char buf[1024]; + + return getprotobyname_r((const char *)0, &protoent_buf, buf, (int)sizeof buf) != NULL; + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOLARIS_IRIX_GETPROTOBYNAME_R, 1, + [define if we have the Solaris/IRIX getprotobyname_r()]) + ], + [ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([for AIX getprotobyname_r()]) + AC_TRY_LINK( + [#include ], + [ + struct protoent protoent_buf; + struct protoent_data proto_data; + + return getprotobyname_r((const char *)0, &protoent_buf, &proto_data); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_AIX_GETPROTOBYNAME_R, 1, + [define if we have the AIX getprotobyname_r()]) + ], + [ + AC_MSG_RESULT(no) + ]) + ]) + ]) + ],,[#include ]) + +# +# You are in a twisty little maze of UN*Xes, all different. +# Some might not have ether_hostton(). +# Some might have it and declare it in . +# Some might have it and declare it in +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and declare it in . +# Some might have it and not declare it in any header file. +# +# Before you is a C compiler. +# +AC_CHECK_FUNCS(ether_hostton) +if test "$ac_cv_func_ether_hostton" = yes; then + # + # OK, we have ether_hostton(). Is it declared in ? + # + # This test fails if we don't have or if we do + # but it doesn't declare ether_hostton(). + # + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if net/ethernet.h declares `ether_hostton']) + ],, + [ +#include + ]) + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Linux? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if netinet/ether.h declares `ether_hostton']) + ],, + [ +#include + ]) + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as on Solaris 10 + # and later? + # + # This test fails if we don't have + # or if we do but it doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if sys/ethernet.h declares `ether_hostton']) + ],, + [ +#include + ]) + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about , as in AIX? + # + # This test fails if we don't have + # (if we have ether_hostton(), we should have + # networking, and if we have networking, we should + # have ) or if we do but it doesn't + # declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(ARPA_INET_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if arpa/inet.h declares `ether_hostton']) + ],, + [ +#include + ]) + fi + # + # Did that succeed? + # + if test "$ac_cv_have_decl_ether_hostton" != yes; then + # + # No, how about ? + # On some platforms, it requires and + # , and we always include it with + # both of them, so test it with both of them. + # + # This test fails if we don't have + # and the headers we include before it, or if we do but + # doesn't declare ether_hostton(). + # + # Unset ac_cv_have_decl_ether_hostton so we don't + # treat the previous failure as a cached value and + # suppress the next test. + # + unset ac_cv_have_decl_ether_hostton + AC_CHECK_DECL(ether_hostton, + [ + AC_DEFINE(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON,, + [Define to 1 if netinet/if_ether.h declares `ether_hostton']) + ],, + [ +#include +#include +#include +#include +#include + ]) + fi + # + # After all that, is ether_hostton() declared? + # + if test "$ac_cv_have_decl_ether_hostton" = yes; then + # + # Yes. + # + AC_DEFINE(HAVE_DECL_ETHER_HOSTTON, 1, + [Define to 1 if you have the declaration of `ether_hostton']) + else + # + # No, we'll have to declare it ourselves. + # Do we have "struct ether_addr" if we include + # ? + # + AC_CHECK_TYPES(struct ether_addr,,, + [ + #include + #include + #include + #include + #include + ]) + fi +fi + +# +# For various things that might use pthreads. +# +AC_CHECK_HEADER(pthread.h, + [ + # + # OK, we have pthread.h. Do we have pthread_create in the + # system libraries? + # + AC_CHECK_FUNC(pthread_create, + [ + # + # Yes. + # + ac_lbl_have_pthreads="found" + ], + [ + # + # No - do we have it in -lpthreads? + # + AC_CHECK_LIB(pthreads, pthread_create, + [ + # + # Yes - add -lpthreads. + # + ac_lbl_have_pthreads="found" + PTHREAD_LIBS="$PTHREAD_LIBS -lpthreads" + ], + [ + # + # No - do we have it in -lpthread? + # + AC_CHECK_LIB(pthread, pthread_create, + [ + # + # Yes - add -lpthread. + # + ac_lbl_have_pthreads="found" + PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" + ], + [ + # + # No. + # + ac_lbl_have_pthreads="not found" + ]) + ]) + ]) + ], + [ + # + # We didn't find pthread.h. + # + ac_lbl_have_pthreads="not found" + ] +) + +AC_MSG_CHECKING([whether to enable the instrument functions code]) +AC_ARG_ENABLE([instrument-functions], + [AS_HELP_STRING([--enable-instrument-functions], + [enable instrument functions code [default=no]])], + [], + [enableval=no]) +case "$enableval" in +yes) AC_MSG_RESULT(yes) + AC_DEFINE(ENABLE_INSTRUMENT_FUNCTIONS, 1, + [define if you want to build the instrument functions code]) + # Add '-finstrument-functions' instrumentation option to generate + # instrumentation calls for entry and exit to functions. + # Use '--enable-instrument-functions' also with tcpdump (or tcpslice) + # to see the output. See also https://www.tcpdump.org/faq.html#q17. + CFLAGS="$CFLAGS -O0 -ggdb -finstrument-functions" + ;; +*) AC_MSG_RESULT(no) + ;; +esac + +dnl to pacify those who hate protochain insn +AC_MSG_CHECKING(if --disable-protochain option is specified) +AC_ARG_ENABLE(protochain, +AS_HELP_STRING([--disable-protochain],[disable \"protochain\" insn])) +case "x$enable_protochain" in +xyes) enable_protochain=enabled ;; +xno) enable_protochain=disabled ;; +x) enable_protochain=enabled ;; +esac + +if test "$enable_protochain" = "disabled"; then + AC_DEFINE(NO_PROTOCHAIN,1,[do not use protochain]) +fi +AC_MSG_RESULT(${enable_protochain}) + +# +# valgrindtest directly uses the native capture mechanism, but +# only tests with BPF and PF_PACKET sockets; only enable it if +# we have BPF or PF_PACKET sockets. +# +VALGRINDTEST_SRC= + +AC_ARG_WITH(pcap, +AS_HELP_STRING([--with-pcap=TYPE],[use packet capture TYPE])) +if test ! -z "$with_pcap" ; then + V_PCAP="$withval" +else + # + # Check for a bunch of headers for various packet + # capture mechanisms. + # + AC_CHECK_HEADERS(net/bpf.h) + if test "$ac_cv_header_net_bpf_h" = yes; then + # + # Does it define BIOCSETIF? + # I.e., is it a header for an LBL/BSD-style capture + # mechanism, or is it just a header for a BPF filter + # engine? Some versions of Arch Linux, for example, + # have a net/bpf.h that doesn't define BIOCSETIF; + # as it's a Linux, it should use packet sockets, + # instead. + # + # We need: + # + # sys/types.h, because FreeBSD 10's net/bpf.h + # requires that various BSD-style integer types + # be defined; + # + # sys/time.h, because AIX 5.2 and 5.3's net/bpf.h + # doesn't include it but does use struct timeval + # in ioctl definitions; + # + # sys/ioctl.h and, if we have it, sys/ioccom.h, + # because net/bpf.h defines ioctls; + # + # net/if.h, because it defines some structures + # used in ioctls defined by net/bpf.h; + # + # sys/socket.h, because OpenBSD 5.9's net/bpf.h + # defines some structure fields as being + # struct sockaddrs; + # + # and net/bpf.h doesn't necessarily include all + # of those headers itself. + # + AC_MSG_CHECKING(if net/bpf.h defines BIOCSETIF) + AC_CACHE_VAL(ac_cv_lbl_bpf_h_defines_biocsetif, + AC_TRY_COMPILE( +[ +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include +#include +], + [u_int i = BIOCSETIF;], + ac_cv_lbl_bpf_h_defines_biocsetif=yes, + ac_cv_lbl_bpf_h_defines_biocsetif=no)) + AC_MSG_RESULT($ac_cv_lbl_bpf_h_defines_biocsetif) + fi + AC_CHECK_HEADERS(net/pfilt.h net/enet.h) + AC_CHECK_HEADERS(net/nit.h sys/net/nit.h) + AC_CHECK_HEADERS(linux/socket.h net/raw.h sys/dlpi.h) + AC_CHECK_HEADERS(config/HaikuConfig.h) + + if test "$ac_cv_lbl_bpf_h_defines_biocsetif" = yes; then + # + # BPF. + # Check this before DLPI, so that we pick BPF on + # Solaris 11 and later. + # + V_PCAP=bpf + + # + # We have BPF, so build valgrindtest with "make test" + # on macOS and FreeBSD (add your OS once there's a + # valgrind for it). + # + case "$host_os" in + + freebsd*|darwin*|linux*) + VALGRINDTEST_SRC=valgrindtest.c + ;; + esac + elif test "$ac_cv_header_linux_socket_h" = yes; then + # + # No prizes for guessing this one. + # + V_PCAP=linux + VALGRINDTEST_SRC=valgrindtest.c + elif test "$ac_cv_header_net_pfilt_h" = yes; then + # + # DEC OSF/1, Digital UNIX, Tru64 UNIX + # + V_PCAP=pf + elif test "$ac_cv_header_net_enet_h" = yes; then + # + # Stanford Enetfilter. + # + V_PCAP=enet + elif test "$ac_cv_header_net_nit_h" = yes; then + # + # SunOS 4.x STREAMS NIT. + # + V_PCAP=snit + elif test "$ac_cv_header_sys_net_nit_h" = yes; then + # + # Pre-SunOS 4.x non-STREAMS NIT. + # + V_PCAP=nit + elif test "$ac_cv_header_net_raw_h" = yes; then + # + # IRIX snoop. + # + V_PCAP=snoop + elif test "$ac_cv_header_sys_dlpi_h" = yes; then + # + # DLPI on pre-Solaris 11 SunOS 5, HP-UX, possibly others. + # + V_PCAP=dlpi + elif test "$ac_cv_header_config_HaikuConfig_h" = yes; then + # + # Haiku. + # + V_PCAP=haiku + else + # + # We don't have any capture type we know about. + # Report an error, and tell the user to configure with + # --with-pcap=null if they want a libpcap that can't + # capture but that can read capture files. That way, + # nobody gets surprised by getting a no-capture + # libpcap without asking for that. + # + AC_MSG_ERROR([No supported packet capture interface was found. + See the INSTALL.md file for information on packet capture support in + various operating systems. + If you want a libpcap that cannot capture packets but that can read + pcap and pcapng files, run configure with --with-pcap=null.]) + fi +fi +AC_MSG_CHECKING(packet capture type) +AC_MSG_RESULT($V_PCAP) +AC_SUBST(VALGRINDTEST_SRC) + +# +# Do we have pkg-config? +# +PKG_PROG_PKG_CONFIG + +# +# Do we have the brew command from Homebrew? +# +AC_PATH_PROG([BREW], [brew]) + +# +# Solaris pkg-config is annoying. For at least one package (D-Bus, I'm +# looking at *you*!), there are separate include files for 32-bit and +# 64-bit builds (I guess using "unsigned long long" as a 64-bit integer +# type on a 64-bit build is like crossing the beams or something), and +# there are two separate .pc files, so if we're doing a 32-bit build we +# should make sure we look in /usr/lib/pkgconfig for .pc files and if +# we're doing a 64-bit build we should make sure we look in +# /usr/lib/amd64/pkgconfig for .pc files. +# +case "$host_os" in + +solaris*) + if test "$ac_cv_sizeof_void_p" -eq 8; then + # + # 64-bit build. If the path is empty, set it to + # /usr/lib/amd64/pkgconfig; otherwise, if + # /usr/lib/pkgconfig appears in the path, prepend + # /usr/lib/amd64/pkgconfig to it; otherwise, put + # /usr/lib/amd64/pkgconfig at the end. + # + if test -z "$PKG_CONFIG_PATH"; then + # + # Not set, or empty. Set it to + # /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=/usr/lib/amd64/pkgconfig + elif test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/pkgconfig"`; then + # + # It contains /usr/lib/pkgconfig. Prepend + # /usr/lib/amd64/pkgconfig to /usr/lib/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/pkgconfig;/usr/lib/amd64/pkgconfig:/usr/lib/pkgconfig;"` + else + # + # Not empty, but doesn't contain /usr/lib/pkgconfig. + # Append /usr/lib/amd64/pkgconfig to it. + # + PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/lib/amd64/pkgconfig" + fi + export PKG_CONFIG_PATH + elif test "$ac_cv_sizeof_void_p" -eq 4; then + # + # 32-bit build. If /usr/amd64/lib/pkgconfig appears + # in the path, prepend /usr/lib/pkgconfig to it. + # + if test ! -z `echo "$PKG_CONFIG_PATH" | grep "/usr/lib/amd64/pkgconfig"`; then + # + # It contains /usr/lib/amd64/pkgconfig. Prepend + # /usr/lib/pkgconfig to /usr/lib/amd64/pkgconfig. + # + PKG_CONFIG_PATH=`echo "$PKG_CONFIG_PATH" | sed "s;/usr/lib/amd64/pkgconfig;/usr/lib/pkgconfig:/usr/lib/amd64/pkgconfig;"` + export PKG_CONFIG_PATH + fi + fi +esac + +# +# Handle each capture type. +# +case "$V_PCAP" in +dlpi) + # + # Checks for some header files. + # + AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) + + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LIBS -L/lib" + AC_CHECK_LIB(dlpi, dlpi_walk, + [ + LIBS="-ldlpi $LIBS" + LIBS_STATIC="-ldlpi $LIBS_STATIC" + LIBS_PRIVATE="-ldlpi $LIBS_PRIVATE" + V_PCAP=libdlpi + + # + # Capture module plus common code needed for + # common functions used by pcap-[dlpi,libdlpi].c + # + PLATFORM_C_SRC="pcap-libdlpi.c dlpisubs.c" + AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists]) + ], + [ + V_PCAP=dlpi + + # + # Capture module plus common code needed for + # common functions used by pcap-[dlpi,libdlpi].c + # + PLATFORM_C_SRC="pcap-dlpi.c dlpisubs.c" + ]) + LDFLAGS="$save_LDFLAGS" + + # + # Checks whether is usable, to catch weird SCO + # versions of DLPI. + # + AC_MSG_CHECKING(whether is usable) + AC_CACHE_VAL(ac_cv_sys_dlpi_usable, + AC_TRY_COMPILE( + [ + #include + #include + #include + ], + [int i = DL_PROMISC_PHYS;], + ac_cv_sys_dlpi_usable=yes, + ac_cv_sys_dlpi_usable=no)) + AC_MSG_RESULT($ac_cv_sys_dlpi_usable) + if test $ac_cv_sys_dlpi_usable = no ; then + AC_MSG_ERROR( is not usable on this system; it probably has a non-standard DLPI) + fi + + # + # Check to see if Solaris has the dl_passive_req_t struct defined + # in . + # This check is for DLPI support for passive modes. + # See dlpi(7P) for more details. + # + AC_CHECK_TYPES(dl_passive_req_t,,, + [ + #include + #include + ]) + ;; + +enet) + # + # Capture module + # + PLATFORM_C_SRC="pcap-enet.c" + ;; + +haiku) + # + # Capture module + # + PLATFORM_C_SRC="pcap-haiku.c" + + # + # Just for the sake of it. + # + AC_CHECK_HEADERS(net/if.h net/if_dl.h net/if_types.h) + ;; + +linux) + # + # Capture module + # + PLATFORM_C_SRC="pcap-linux.c" + + # + # Do we have the wireless extensions? + # + AC_CHECK_HEADERS(linux/wireless.h, [], [], + [ +#include +#include +#include + ]) + + # + # Do we have libnl? + # We only want version 3. Version 2 was, apparently, + # short-lived, and version 1 is source and binary + # incompatible with version 3, and it appears that, + # these days, everybody's using version 3. We're + # not supporting older versions of the Linux kernel; + # let's drop support for older versions of libnl, too. + # + AC_ARG_WITH(libnl, + AS_HELP_STRING([--without-libnl],[disable libnl support @<:@default=yes, on Linux, if present@:>@]), + with_libnl=$withval,with_libnl=if_available) + + if test x$with_libnl != xno ; then + # + # Check for libnl-genl-3.0 with pkg-config. + # + PKG_CHECK_MODULE(LIBNL, libnl-genl-3.0, + [ + pkg_config_found_libnl=yes + V_INCLS="$V_INCLS $LIBNL_CFLAGS" + ADDITIONAL_LIBS="$LIBNL_LIBS $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="$LIBNL_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" + REQUIRES_PRIVATE="libnl-genl-3.0 $REQUIRES_PRIVATE" + AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) + ]) + + if test x$pkg_config_found_libnl != xyes; then + # + # OK, either we don't have pkg-config or there + # wasn't a .pc file for it; Check for it directly. + # + case "$with_libnl" in + + yes|if_available) + incdir=-I/usr/include/libnl3 + libnldir= + ;; + + *) + if test -d $withval; then + libnldir=-L${withval}/lib + incdir=-I${withval}/include + fi + ;; + esac + + AC_CHECK_LIB(nl-3, nl_socket_alloc, + [ + # + # Yes, we have libnl 3.x. + # + ADDITIONAL_LIBS="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="${libnldir} -lnl-genl-3 -lnl-3 $ADDITIONAL_LIBS_STATIC" + LIBS_PRIVATE="${libnldir} -lnl-genl-3 -lnl-3 $LIBS_PRIVATE" + AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]) + V_INCLS="$V_INCLS ${incdir}" + ],[ + # + # No, we don't have libnl at all. + # Fail if the user explicitly requested + # it. + # + if test x$with_libnl = xyes ; then + AC_MSG_ERROR([libnl support requested but libnl not found]) + fi + ], ${incdir} ${libnldir} -lnl-genl-3 -lnl-3 ) + fi + fi + + # + # Check to see if the tpacket_auxdata struct has a tp_vlan_tci member. + # + # NOTE: any failure means we conclude that it doesn't have that + # member, so if we don't have tpacket_auxdata, we conclude it + # doesn't have that member (which is OK, as either we won't be + # using code that would use that member, or we wouldn't compile + # in any case). + AC_CHECK_MEMBERS([struct tpacket_auxdata.tp_vlan_tci],,, + [ + #include + #include + ]) + ;; + +bpf) + # + # Capture module + # + PLATFORM_C_SRC="pcap-bpf.c" + + # + # Check whether we have the *BSD-style ioctls. + # + AC_CHECK_HEADERS(net/if_media.h) + + # + # Check whether we have struct BPF_TIMEVAL. + # + AC_CHECK_TYPES(struct BPF_TIMEVAL,,, + [ + #include + #include + #ifdef HAVE_SYS_IOCCOM_H + #include + #endif + #include + ]) + + # + # Check whether there's a net/ipnet.h header and, + # if so, whether it defines IPNET_ANY_LINK - if so, + # we assume we have the "any" device (that's a + # Solaris header, and later versions of Solaris + # have an "any" device). + # + # Attempting to include it at compile time could + # be a pain, as it's a kernel header. + # + AC_MSG_CHECKING(whether the Solaris "any" device is supported) + if test -e /usr/include/inet/ipnet.h && + grep -q IPNET_ANY_LINK /usr/include/inet/ipnet.h; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOLARIS_ANY_DEVICE, 1, [target host supports Solaris "any" device]) + else + AC_MSG_RESULT(no) + fi + ;; + +pf) + # + # Capture module + # + PLATFORM_C_SRC="pcap-pf.c" + ;; + +snit) + # + # Capture module + # + PLATFORM_C_SRC="pcap-snit.c" + ;; + +snoop) + # + # Capture module + # + PLATFORM_C_SRC="pcap-snoop.c" + ;; + +dag) + # + # --with-pcap=dag is the only way to get here, and it means + # "DAG support but nothing else" + # + V_DEFS="$V_DEFS -DDAG_ONLY" + PLATFORM_C_SRC="pcap-dag.c" + xxx_only=yes + ;; + +dpdk) + # + # --with-pcap=dpdk is the only way to get here, and it means + # "DPDK support but nothing else" + # + V_DEFS="$V_DEFS -DDPDK_ONLY" + PLATFORM_C_SRC="pcap-dpdk.c" + xxx_only=yes + ;; + +septel) + # + # --with-pcap=septel is the only way to get here, and it means + # "Septel support but nothing else" + # + V_DEFS="$V_DEFS -DSEPTEL_ONLY" + PLATFORM_C_SRC="pcap-septel.c" + xxx_only=yes + ;; + +snf) + # + # --with-pcap=snf is the only way to get here, and it means + # "SNF support but nothing else" + # + V_DEFS="$V_DEFS -DSNF_ONLY" + PLATFORM_C_SRC="pcap-snf.c" + xxx_only=yes + ;; + +null) + # + # Capture module + # + PLATFORM_C_SRC="pcap-null.c" + ;; + +*) + AC_MSG_ERROR($V_PCAP is not a valid pcap type) + ;; +esac + +dnl +dnl Now figure out how we get a list of interfaces and addresses, +dnl if we support capturing. Don't bother if we don't support +dnl capturing. +dnl +if test "$V_PCAP" != null +then + AC_CHECK_FUNC(getifaddrs,[ + # + # We have "getifaddrs()"; make sure we have + # as well, just in case some platform is really weird. + # + AC_CHECK_HEADER(ifaddrs.h,[ + # + # We have the header, so we use "getifaddrs()" to + # get the list of interfaces. + # + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-getad.c" + ],[ + # + # We don't have the header - give up. + # XXX - we could also fall back on some other + # mechanism, but, for now, this'll catch this + # problem so that we can at least try to figure + # out something to do on systems with "getifaddrs()" + # but without "ifaddrs.h", if there is something + # we can do on those systems. + # + AC_MSG_ERROR([Your system has getifaddrs() but doesn't have a usable .]) + ]) + ],[ + # + # Well, we don't have "getifaddrs()", at least not with the + # libraries with which we've decided we need to link + # libpcap with, so we have to use some other mechanism. + # + # Note that this may happen on Solaris, which has + # getifaddrs(), but in -lsocket, not in -lxnet, so we + # won't find it if we link with -lxnet, which we want + # to do for other reasons. + # + # For now, we use either the SIOCGIFCONF ioctl or the + # SIOCGLIFCONF ioctl, preferring the latter if we have + # it; the latter is a Solarisism that first appeared + # in Solaris 8. (Solaris's getifaddrs() appears to + # be built atop SIOCGLIFCONF; using it directly + # avoids a not-all-that-useful middleman.) + # + AC_MSG_CHECKING(whether we have SIOCGLIFCONF) + AC_CACHE_VAL(ac_cv_lbl_have_siocglifconf, + AC_TRY_COMPILE( + [#include + #include + #include + #include + #include ], + [ioctl(0, SIOCGLIFCONF, (char *)0);], + ac_cv_lbl_have_siocglifconf=yes, + ac_cv_lbl_have_siocglifconf=no)) + AC_MSG_RESULT($ac_cv_lbl_have_siocglifconf) + if test $ac_cv_lbl_have_siocglifconf = yes ; then + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-glifc.c" + else + PLATFORM_C_SRC="$PLATFORM_C_SRC fad-gifc.c" + fi + ]) +fi + +dnl check for hardware timestamp support +case "$host_os" in +linux*) + AC_CHECK_HEADERS([linux/net_tstamp.h]) + ;; +*) + AC_MSG_NOTICE(no hardware timestamp support implemented for $host_os) + ;; +esac + +# +# Check for socklen_t. +# +AC_CHECK_TYPES(socklen_t,,, + [ + #include + #include + ]) + +AC_ARG_ENABLE(ipv6, +AS_HELP_STRING([--enable-ipv6],[build IPv6-capable version @<:@default=yes@:>@]), + [], + [enable_ipv6=yes]) +if test "$enable_ipv6" != "no"; then + # + # We've already made sure we have getaddrinfo above in + # AC_LBL_LIBRARY_NET. + # + AC_DEFINE(INET6,1,[IPv6]) +fi + +# Check for Endace DAG card support. +AC_ARG_WITH([dag], +AS_HELP_STRING([--with-dag@<:@=DIR@:>@],[include Endace DAG support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), +[ + if test "$withval" = no + then + # User doesn't want DAG support. + want_dag=no + elif test "$withval" = yes + then + # User wants DAG support but hasn't specified a directory. + want_dag=yes + else + # User wants DAG support and has specified a directory, so use the provided value. + want_dag=yes + dag_root=$withval + fi +],[ + if test "$V_PCAP" = dag; then + # User requested DAG-only libpcap, so we'd better have + # the DAG API. + want_dag=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want DAG support. + want_dag=no + else + # + # Use DAG API if present, otherwise don't + # + want_dag=ifpresent + fi +]) + +AC_ARG_WITH([dag-includes], +AS_HELP_STRING([--with-dag-includes=IDIR],[Endace DAG include directory, if not DIR/include]), +[ + # User wants DAG support and has specified a header directory, so use the provided value. + want_dag=yes + dag_include_dir=$withval +],[]) + +AC_ARG_WITH([dag-libraries], +AS_HELP_STRING([--with-dag-libraries=LDIR],[Endace DAG library directory, if not DIR/lib]), +[ + # User wants DAG support and has specified a library directory, so use the provided value. + want_dag=yes + dag_lib_dir=$withval +],[]) + +if test "$want_dag" != no; then + + # If necessary, set default paths for DAG API headers and libraries. + if test -z "$dag_root"; then + dag_root=/usr/local + fi + + if test -z "$dag_include_dir"; then + dag_include_dir="$dag_root/include" + fi + + if test -z "$dag_lib_dir"; then + dag_lib_dir="$dag_root/lib" + # + # Handle multiarch systems. + # + if test -d "$dag_lib_dir/$host" + then + dag_lib_dir="$dag_lib_dir/$host" + fi + fi + + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS -I$dag_include_dir" + AC_CHECK_HEADERS([dagapi.h]) + AC_LBL_RESTORE_CHECK_STATE + + if test "$ac_cv_header_dagapi_h" = yes; then + + V_INCLS="$V_INCLS -I$dag_include_dir" + + if test $V_PCAP != dag ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-dag.c" + fi + + # Check for various DAG API functions. + # Don't need to save and restore LIBS to prevent -ldag being + # included if there's a found-action (arg 3). + AC_LBL_SAVE_CHECK_STATE + LDFLAGS="-L$dag_lib_dir" + AC_CHECK_LIB([dag], [dag_attach_stream], + [ + # + # We assume that if we have libdag we have + # libdagconf, as they're installed at the + # same time from the same package. + # + ADDITIONAL_LIBS="-L$dag_lib_dir $ADDITIONAL_LIBS -ldag -ldagconf" + ADDITIONAL_LIBS_STATIC="-L$dag_lib_dir $ADDITIONAL_LIBS_STATIC -ldag -ldagconf" + LIBS_PRIVATE="-L$dag_lib_dir $LIBS_PRIVATE -ldag -ldagconf" + ], + [AC_MSG_ERROR(DAG library lacks streams support)]) + AC_CHECK_LIB([dag], [dag_attach_stream64], [dag_large_streams="1"], [dag_large_streams="0"]) + AC_CHECK_LIB([dag],[dag_get_erf_types], [ + AC_DEFINE(HAVE_DAG_GET_ERF_TYPES, 1, [define if you have dag_get_erf_types()])]) + AC_CHECK_LIB([dag],[dag_get_stream_erf_types], [ + AC_DEFINE(HAVE_DAG_GET_STREAM_ERF_TYPES, 1, [define if you have dag_get_stream_erf_types()])]) + AC_LBL_RESTORE_CHECK_STATE + + # + # We assume that if we have libdag we have libdagconf, + # as they're installed at the same time from the same + # package. + # + if test "$dag_large_streams" = 1; then + AC_DEFINE(HAVE_DAG_LARGE_STREAMS_API, 1, [define if you have large streams capable DAG API]) + AC_LBL_SAVE_CHECK_STATE + LIBS="$LIBS -ldag -ldagconf" + LDFLAGS="$LDFLAGS -L$dag_lib_dir" + AC_CHECK_LIB([vdag],[vdag_set_device_info], [ac_dag_have_vdag="1"], [ac_dag_have_vdag="0"]) + AC_LBL_RESTORE_CHECK_STATE + if test "$ac_dag_have_vdag" = 1; then + AC_DEFINE(HAVE_DAG_VDAG, 1, [define if you have vdag_set_device_info()]) + if test "$ac_lbl_have_pthreads" != "found"; then + AC_MSG_ERROR([DAG requires pthreads, but we didn't find them]) + fi + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $PTHREAD_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $PTHREAD_LIBS" + LIBS_PRIVATE="$LIBS_PRIVATE $PTHREAD_LIBS" + fi + fi + + AC_DEFINE(HAVE_DAG_API, 1, [define if you have the DAG API]) + else + if test "$V_PCAP" = dag; then + # User requested "dag" capture type but we couldn't + # find the DAG API support. + AC_MSG_ERROR([DAG support requested with --with-pcap=dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) + fi + + if test "$want_dag" = yes; then + # User wanted DAG support but we couldn't find it. + AC_MSG_ERROR([DAG support requested with --with-dag, but the DAG headers weren't found at $dag_include_dir: make sure the DAG support is installed, specify a different path or paths if necessary, or don't request DAG support]) + fi + fi + CFLAGS="$save_CFLAGS" +fi + +AC_ARG_WITH(septel, +AS_HELP_STRING([--with-septel@<:@=DIR@:>@],[include Septel support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), +[ + if test "$withval" = no + then + want_septel=no + elif test "$withval" = yes + then + want_septel=yes + septel_root= + else + want_septel=yes + septel_root=$withval + fi +],[ + if test "$V_PCAP" = septel; then + # User requested Septel-only libpcap, so we'd better have + # the Septel API. + want_septel=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want Septel support. + want_septel=no + else + # + # Use Septel API if present, otherwise don't + # + want_septel=ifpresent + fi +]) + +ac_cv_lbl_septel_api=no +if test "$with_septel" != no; then + + AC_MSG_CHECKING([whether we have Septel API headers]) + + # If necessary, set default paths for Septel API headers and libraries. + if test -z "$septel_root"; then + septel_root=$srcdir/../septel + fi + + septel_tools_dir="$septel_root" + septel_include_dir="$septel_root/INC" + + if test -r "$septel_include_dir/msg.h"; then + ac_cv_lbl_septel_api=yes + fi + + if test "$ac_cv_lbl_septel_api" = yes; then + AC_MSG_RESULT([yes ($septel_include_dir)]) + + V_INCLS="$V_INCLS -I$septel_include_dir" + ADDLOBJS="$ADDLOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + ADDLARCHIVEOBJS="$ADDLARCHIVEOBJS $septel_tools_dir/asciibin.o $septel_tools_dir/bit2byte.o $septel_tools_dir/confirm.o $septel_tools_dir/fmtmsg.o $septel_tools_dir/gct_unix.o $septel_tools_dir/hqueue.o $septel_tools_dir/ident.o $septel_tools_dir/mem.o $septel_tools_dir/pack.o $septel_tools_dir/parse.o $septel_tools_dir/pool.o $septel_tools_dir/sdlsig.o $septel_tools_dir/strtonum.o $septel_tools_dir/timer.o $septel_tools_dir/trace.o" + + if test "$V_PCAP" != septel ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-septel.c" + fi + + AC_DEFINE(HAVE_SEPTEL_API, 1, [define if you have the Septel API]) + else + AC_MSG_RESULT(no) + + if test "$V_PCAP" = septel; then + # User requested "septel" capture type but + # we couldn't find the Septel API support. + AC_MSG_ERROR([Septel support requested with --with-pcap=septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) + fi + + if test "$want_septel" = yes; then + # User wanted Septel support but we couldn't find it. + AC_MSG_ERROR([Septel support requested with --with-septel, but the Septel headers weren't found at $septel_include_dir: make sure the Septel support is installed, specify a different path or paths if necessary, or don't request Septel support]) + fi + fi +fi + +# Check for Myricom SNF support. +AC_ARG_WITH([snf], +AS_HELP_STRING([--with-snf@<:@=DIR@:>@],[include Myricom SNF support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), +[ + if test "$withval" = no + then + # User explicitly doesn't want SNF + want_snf=no + elif test "$withval" = yes + then + # User wants SNF support but hasn't specified a directory. + want_snf=yes + else + # User wants SNF support with a specified directory. + want_snf=yes + snf_root=$withval + fi +],[ + if test "$V_PCAP" = snf; then + # User requested Sniffer-only libpcap, so we'd better have + # the Sniffer API. + want_snf=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want SNF support. + want_snf=no + else + # + # Use Sniffer API if present, otherwise don't + # + want_snf=ifpresent + fi +]) + +AC_ARG_WITH([snf-includes], +AS_HELP_STRING([--with-snf-includes=IDIR],[Myricom SNF include directory, if not DIR/include]), +[ + # User wants SNF with specific header directory + want_snf=yes + snf_include_dir=$withval +],[]) + +AC_ARG_WITH([snf-libraries], +AS_HELP_STRING([--with-snf-libraries=LDIR],[Myricom SNF library directory, if not DIR/lib]), +[ + # User wants SNF with specific lib directory + want_snf=yes + snf_lib_dir=$withval +],[]) + +ac_cv_lbl_snf_api=no +if test "$with_snf" != no; then + + AC_MSG_CHECKING(whether we have Myricom Sniffer API) + + # If necessary, set default paths for Sniffer headers and libraries. + if test -z "$snf_root"; then + snf_root=/opt/snf + fi + + if test -z "$snf_include_dir"; then + snf_include_dir="$snf_root/include" + fi + + if test -z "$snf_lib_dir"; then + snf_lib_dir="$snf_root/lib" + # + # Handle multiarch systems. + # + if test -d "$snf_lib_dir/$host" + then + snf_lib_dir="$snf_lib_dir/$host" + fi + fi + + if test -f "$snf_include_dir/snf.h"; then + # We found a header; make sure we can link with the library + AC_LBL_SAVE_CHECK_STATE + LDFLAGS="$LDFLAGS -L$snf_lib_dir" + AC_CHECK_LIB([snf], [snf_init], [ac_cv_lbl_snf_api="yes"]) + AC_LBL_RESTORE_CHECK_STATE + if test "$ac_cv_lbl_snf_api" = no; then + AC_MSG_ERROR(SNF API cannot correctly be linked; check config.log) + fi + fi + + if test "$ac_cv_lbl_snf_api" = yes; then + AC_MSG_RESULT([yes ($snf_root)]) + + V_INCLS="$V_INCLS -I$snf_include_dir" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS -L$snf_lib_dir -lsnf" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC -L$snf_lib_dir -lsnf" + LIBS_PRIVATE="$LIBS_PRIVATE -L$snf_lib_dir -lsnf" + + if test "$V_PCAP" != snf ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-snf.c" + fi + + AC_DEFINE(HAVE_SNF_API, 1, [define if you have the Myricom SNF API]) + else + AC_MSG_RESULT(no) + + if test "$want_snf" = yes; then + # User requested "snf" capture type but + # we couldn't find the Sniffer API support. + AC_MSG_ERROR([Myricom Sniffer support requested with --with-pcap=snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) + fi + + if test "$want_snf" = yes; then + AC_MSG_ERROR([Myricom Sniffer support requested with --with-snf, but the Sniffer headers weren't found at $snf_include_dir: make sure the Sniffer support is installed, specify a different path or paths if necessary, or don't request Sniffer support]) + fi + fi +fi + +# Check for Riverbed TurboCap support. +AC_ARG_WITH([turbocap], +AS_HELP_STRING([--with-turbocap@<:@=DIR@:>@],[include Riverbed TurboCap support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), +[ + if test "$withval" = no + then + # User explicitly doesn't want TurboCap + want_turbocap=no + elif test "$withval" = yes + then + # User wants TurboCap support but hasn't specified a directory. + want_turbocap=yes + else + # User wants TurboCap support with a specified directory. + want_turbocap=yes + turbocap_root=$withval + fi +],[ + if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want TurboCap support. + want_turbocap=no + else + # + # Use TurboCap API if present, otherwise don't + # + want_turbocap=ifpresent + fi +]) + +ac_cv_lbl_turbocap_api=no +if test "$want_turbocap" != no; then + + AC_MSG_CHECKING(whether TurboCap is supported) + + AC_LBL_SAVE_CHECK_STATE + if test ! -z "$turbocap_root"; then + TURBOCAP_CFLAGS="-I$turbocap_root/include" + TURBOCAP_LDFLAGS="-L$turbocap_root/lib" + CFLAGS="$CFLAGS $TURBOCAP_CFLAGS" + LDFLAGS="$LDFLAGS $TURBOCAP_LDFLAGS" + fi + + AC_TRY_COMPILE( + [ + #include + ], + [ + TC_INSTANCE a; TC_PORT b; TC_BOARD c; + TC_INSTANCE i; + (void)TcInstanceCreateByName("foo", &i); + ], + ac_cv_lbl_turbocap_api=yes) + + AC_LBL_RESTORE_CHECK_STATE + if test $ac_cv_lbl_turbocap_api = yes; then + AC_MSG_RESULT(yes) + + MODULE_C_SRC="$MODULE_C_SRC pcap-tc.c" + V_INCLS="$V_INCLS $TURBOCAP_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + LIBS_PRIVATE="$LIBS_PRIVATE $TURBOCAP_LDFLAGS -lTcApi -lpthread -lstdc++" + + AC_DEFINE(HAVE_TC_API, 1, [define if you have the TurboCap API]) + else + AC_MSG_RESULT(no) + + if test "$want_turbocap" = yes; then + # User wanted Turbo support but we couldn't find it. + AC_MSG_ERROR([TurboCap support requested with --with-turbocap, but the TurboCap headers weren't found: make sure the TurboCap support is installed or don't request TurboCap support]) + fi + fi +fi + +dnl +dnl Allow the user to enable remote capture. +dnl It's off by default, as that increases the attack surface of +dnl libpcap, exposing it to malicious servers. +dnl +AC_MSG_CHECKING([whether to enable remote packet capture]) +AC_ARG_ENABLE([remote], + [AS_HELP_STRING([--enable-remote], + [enable remote packet capture @<:@default=no@:>@])], + [], + [enableval=no]) +case "$enableval" in +yes) AC_MSG_RESULT(yes) + AC_WARN([Remote packet capture may expose libpcap-based applications]) + AC_WARN([to attacks by malicious remote capture servers!]) + # + # rpcapd requires pthreads on UN*X. + # + if test "$ac_lbl_have_pthreads" != "found"; then + AC_MSG_ERROR([rpcapd requires pthreads, but we didn't find them]) + fi + # + # It also requires crypt(). + # Do we have it in the system libraries? + # + AC_CHECK_FUNC(crypt,, + [ + # + # No. Do we have it in -lcrypt? + # + AC_CHECK_LIB(crypt, crypt, + [ + # + # Yes; add -lcrypt to the libraries for rpcapd. + # + RPCAPD_LIBS="$RPCAPD_LIBS -lcrypt" + ], + [ + AC_MSG_ERROR([rpcapd requires crypt(), but we didn't find it]) + ]) + ]) + + # + # OK, we have crypt(). Do we have getspnam()? + # + AC_CHECK_FUNCS(getspnam) + + # + # Check for various members of struct msghdr. + # + AC_CHECK_MEMBERS([struct msghdr.msg_control],,, + [ + #include "ftmacros.h" + #include + ]) + AC_CHECK_MEMBERS([struct msghdr.msg_flags],,, + [ + #include "ftmacros.h" + #include + ]) + + # + # Optionally, we may want to support SSL. + # Check for OpenSSL/libressl. + # + # First, try looking for it with pkg-config, if we have it. + # + # Homebrew's pkg-config does not, by default, look for + # pkg-config files for packages it has installed. + # Furthermore, at least for OpenSSL, they appear to be + # dumped in package-specific directories whose paths are + # not only package-specific but package-version-specific. + # + # So the only way to find openssl is to get the value of + # PKG_CONFIG_PATH from "brew --env openssl" and add that + # to PKG_CONFIG_PATH. (No, we can't just assume it's under + # /usr/local; Homebrew have conveniently chosen to put it + # under /opt/homebrew on ARM.) + # + # That's the nice thing about Homebrew - it makes things easier! + # Thanks! + # + save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" + if test -n "$BREW"; then + openssl_pkgconfig_dir=`$BREW --env --plain openssl | sed -n 's/PKG_CONFIG_PATH: //p'` + PKG_CONFIG_PATH="$openssl_pkgconfig_dir:$PKG_CONFIG_PATH" + fi + PKG_CHECK_MODULE(OPENSSL, openssl, + [ + # + # We found OpenSSL/libressl. + # + HAVE_OPENSSL=yes + REQUIRES_PRIVATE="$REQUIRES_PRIVATE openssl" + ]) + PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" + + # + # If it wasn't found, and we have Homebrew installed, see + # if it's in Homebrew. + # + if test "x$HAVE_OPENSSL" != "xyes" -a -n "$BREW"; then + AC_MSG_CHECKING(for openssl in Homebrew) + # + # The brew man page lies when it speaks of + # $BREW --prefix --installed + # outputting nothing. In Homebrew 3.3.16, + # it produces output regardless of whether + # the formula is installed or not, so we + # send the standard output and error to + # the bit bucket. + # + if $BREW --prefix --installed openssl >/dev/null 2>&1; then + # + # Yes. Get the include directory and library + # directory. (No, we can't just assume it's + # under /usr/local; Homebrew have conveniently + # chosen to put it under /opt/homebrew on ARM.) + # + AC_MSG_RESULT(yes) + HAVE_OPENSSL=yes + openssl_path=`$BREW --prefix openssl` + OPENSSL_CFLAGS="-I$openssl_path/include" + OPENSSL_LIBS="-L$openssl_path/lib -lssl -lcrypto" + OPENSSL_LIBS_STATIC="-L$openssl_path/lib -lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-L$openssl_path/lib -lssl -lcrypto" + else + AC_MSG_RESULT(no) + fi + fi + + # + # If it wasn't found, and /usr/local/include and /usr/local/lib + # exist, check if it's in /usr/local. (We check whether they + # exist because, if they don't exist, the compiler will warn + # about that and then ignore the argument, so they test + # using just the system header files and libraries.) + # + # We include the standard include file to 1) make sure that + # it's installed (if it's just a shared library for the + # benefit of existing programs, that's not useful) and 2) + # because SSL_library_init() is a library routine in some + # versions and a #defined wrapper around OPENSSL_init_ssl() + # in others. + # + if test "x$HAVE_OPENSSL" != "xyes" -a -d "/usr/local/include" -a -d "/usr/local/lib"; then + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS -I/usr/local/include" + LIBS="$LIBS -L/usr/local/lib -lssl -lcrypto" + AC_MSG_CHECKING(whether we have OpenSSL/libressl in /usr/local that we can use) + AC_TRY_LINK( + [ +#include + ], + [ +SSL_library_init(); +return 0; + ], + [ + AC_MSG_RESULT(yes) + HAVE_OPENSSL=yes + OPENSSL_CFLAGS="-I/usr/local/include" + OPENSSL_LIBS="-L/usr/local/lib -lssl -lcrypto" + OPENSSL_LIBS_STATIC="-L/usr/local/lib -lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-L/usr/local/lib -lssl -lcrypto" + ], + AC_MSG_RESULT(no)) + AC_LBL_RESTORE_CHECK_STATE + fi + + # + # If it wasn't found, check if it's a system library. + # + # We include the standard include file to 1) make sure that + # it's installed (if it's just a shared library for the + # benefit of existing programs, that's not useful) and 2) + # because SSL_library_init() is a library routine in some + # versions and a #defined wrapper around OPENSSL_init_ssl() + # in others. + # + if test "x$HAVE_OPENSSL" != "xyes"; then + AC_LBL_SAVE_CHECK_STATE + LIBS="$LIBS -lssl -lcrypto" + AC_MSG_CHECKING(whether we have a system OpenSSL/libressl that we can use) + AC_TRY_LINK( + [ +#include + ], + [ +SSL_library_init(); +return 0; + ], + [ + AC_MSG_RESULT(yes) + HAVE_OPENSSL=yes + OPENSSL_LIBS="-lssl -lcrypto" + OPENSSL_LIBS_STATIC="-lssl -lcrypto" + OPENSSL_LIBS_PRIVATE="-lssl -lcrypto" + ], + AC_MSG_RESULT(no)) + AC_LBL_RESTORE_CHECK_STATE + fi + + # + # OK, did we find it? + # + if test "x$HAVE_OPENSSL" = "xyes"; then + AC_DEFINE([HAVE_OPENSSL], [1], [Use OpenSSL]) + V_INCLS="$V_INCLS $OPENSSL_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $OPENSSL_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $OPENSSL_LIBS_STATIC" + LIBS_PRIVATE="$LIBS_PRIVATE $OPENSSL_LIBS_PRIVATE" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE $OPENSSL_REQUIRES_PRIVATE" + REMOTE_C_SRC="$REMOTE_C_SRC sslutils.c" + else + AC_MSG_NOTICE(OpenSSL not found) + fi + + AC_DEFINE(ENABLE_REMOTE,, + [Define to 1 if remote packet capture is to be supported]) + REMOTE_C_SRC="$REMOTE_C_SRC pcap-new.c pcap-rpcap.c rpcap-protocol.c sockutils.c" + BUILD_RPCAPD=build-rpcapd + INSTALL_RPCAPD=install-rpcapd + ;; +*) AC_MSG_RESULT(no) + ;; +esac + +AC_MSG_CHECKING(whether to build optimizer debugging code) +AC_ARG_ENABLE(optimizer-dbg, +AS_HELP_STRING([--enable-optimizer-dbg],[build optimizer debugging code])) +if test "$enable_optimizer_dbg" = "yes"; then + AC_DEFINE(BDEBUG,1,[Enable optimizer debugging]) +fi +AC_MSG_RESULT(${enable_optimizer_dbg-no}) + +AC_MSG_CHECKING(whether to build parser debugging code) +AC_ARG_ENABLE(yydebug, +AS_HELP_STRING([--enable-yydebug],[build parser debugging code])) +if test "$enable_yydebug" = "yes"; then + AC_DEFINE(YYDEBUG,1,[Enable parser debugging]) +fi +AC_MSG_RESULT(${enable_yydebug-no}) + +# +# Look for {f}lex. +# +AC_PROG_LEX +if test "$LEX" = ":"; then + AC_MSG_ERROR([Neither flex nor lex was found.]) +fi + +# +# Make sure {f}lex supports the -P, --header-file, and --nounput flags +# and supports processing our scanner.l. +# +AC_CACHE_CHECK([for capable lex], tcpdump_cv_capable_lex, + if $LEX -P pcap_ --header-file=/dev/null --nounput -t $srcdir/scanner.l > /dev/null 2>&1; then + tcpdump_cv_capable_lex=yes + else + tcpdump_cv_capable_lex=insufficient + fi) +if test $tcpdump_cv_capable_lex = insufficient ; then + AC_MSG_ERROR([$LEX is insufficient to compile libpcap. + libpcap requires Flex 2.5.31 or later, or a compatible version of lex. + If a suitable version of Lex/Flex is available as a non-standard command + and/or not in the PATH, you can specify it using the LEX environment + variable. That said, on some systems the error can mean that Flex/Lex is + actually acceptable, but m4 is not. Likewise, if a suitable version of + m4 (such as GNU M4) is available but has not been detected, you can + specify it using the M4 environment variable.]) +fi + +# +# Look for yacc/bison/byacc. +# If it's Bison, we do not want -y, as 1) we will be using -o to cause +# the output for XXX.y to be written to XXX.c and 2) we don't want +# it to issue warnings about stuff not supported by POSIX YACC - we +# want to use that stuff, and don't care whether plain YACC supports +# it or not, we require either Bison or Berkeley YACC. +# +BISON_BYACC="" +# +# Look for Bison. +# +AC_CHECK_PROGS(BISON_BYACC, bison) +if test x"$BISON_BYACC" != x; then + # + # We found Bison. + # + # Bison prior to 2.4(.1) doesn't support "%define api.pure", so use + # "%pure-parser". + # + bison_major_version=`$BISON_BYACC -V | sed -n 's/.* \(@<:@1-9@:>@@<:@0-9@:>@*\)\.@<:@0-9@:>@@<:@0-9.@:>@*/\1/p'` + bison_minor_version=`$BISON_BYACC -V | sed -n 's/.* @<:@1-9@:>@@<:@0-9@:>@*\.\(@<:@0-9@:>@+\).*/\1/p'` + if test "$bison_major_version" -lt 2 -o \ + \( "$bison_major_version" -eq 2 -a "$bison_major_version" -lt 4 \) + then + REENTRANT_PARSER="%pure-parser" + else + REENTRANT_PARSER="%define api.pure" + fi +else + # + # We didn't find Bison; check for Berkeley YACC, under the + # names byacc and yacc. + # + AC_CHECK_PROGS(BISON_BYACC, byacc yacc) + if test x"$BISON_BYACC" != x; then + # + # Make sure this is Berkeley YACC, not AT&T YACC; + # the latter doesn't support reentrant parsers. + # Run it with "-V"; that succeeds and reports the + # version number with Berkeley YACC, but will + # (probably) fail with various vendor flavors + # of AT&T YACC. + # + # Hopefully this also eliminates any versions + # of Berkeley YACC that don't support reentrant + # parsers, if there are any. + # + AC_CACHE_CHECK([for capable yacc], tcpdump_cv_capable_yacc, + if $BISON_BYACC -V >/dev/null 2>&1; then + tcpdump_cv_capable_yacc=yes + else + tcpdump_cv_capable_yacc=insufficient + fi) + if test $tcpdump_cv_capable_yacc = insufficient ; then + AC_MSG_ERROR([$BISON_BYACC is insufficient to compile libpcap. + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them.]) + fi + else + # + # OK, we found neither byacc nor yacc. + # + AC_MSG_ERROR([Neither bison, byacc, nor yacc was found. + libpcap requires Bison, a newer version of Berkeley YACC with support + for reentrant parsers, or another YACC compatible with them.]) + fi + + # + # Berkeley YACC doesn't support "%define api.pure", so use + # "%pure-parser". + # + REENTRANT_PARSER="%pure-parser" +fi +AC_SUBST(BISON_BYACC) +AC_SUBST(REENTRANT_PARSER) + +# +# Do various checks for various OSes and versions of those OSes. +# +# Assume, by default, no support for shared libraries and V7/BSD +# convention for man pages (devices in section 4, file formats in +# section 5, miscellaneous info in section 7, administrative commands +# and daemons in section 8). Individual cases can override this. +# +DYEXT="none" +MAN_DEVICES=4 +MAN_FILE_FORMATS=5 +MAN_MISC_INFO=7 +MAN_ADMIN_COMMANDS=8 +case "$host_os" in + +aix*) + dnl Workaround to enable certain features + AC_DEFINE(_SUN,1,[define on AIX to get certain functions]) + + # + # AIX makes it fun to build shared and static libraries, + # because they're *both* ".a" archive libraries. We + # build the static library for the benefit of the traditional + # scheme of building libpcap and tcpdump in subdirectories of + # the same directory, with tcpdump statically linked with the + # libpcap in question, but we also build a shared library as + # "libpcap.shareda" and install *it*, rather than the static + # library, as "libpcap.a". + # + DYEXT="shareda" + + case "$V_PCAP" in + + dlpi) + # + # If we're using DLPI, applications will need to + # use /lib/pse.exp if present, as we use the + # STREAMS routines. + # + pseexe="/lib/pse.exp" + AC_MSG_CHECKING(for $pseexe) + if test -f $pseexe ; then + AC_MSG_RESULT(yes) + LIBS="-I:$pseexe" + fi + ;; + + bpf) + # + # If we're using BPF, we need "-lodm" and "-lcfg", as + # we use them to load the BPF module. + # + LIBS="-lodm -lcfg" + ;; + esac + ;; + +darwin*) + DYEXT="dylib" + V_CCOPT="$V_CCOPT -fno-common" + AC_ARG_ENABLE(universal, + AS_HELP_STRING([--disable-universal],[don't build universal on macOS])) + if test "$enable_universal" != "no"; then + case "$host_os" in + + darwin[[0-7]].*) + # + # Pre-Tiger. Build only for 32-bit PowerPC; no + # need for any special compiler or linker flags. + # + ;; + + darwin8.[[0123]]|darwin8.[[0123]].*) + # + # Tiger, prior to Intel support. Build + # libraries and executables for 32-bit PowerPC + # and 64-bit PowerPC, with 32-bit PowerPC first. + # (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64" + ;; + + darwin8.[[456]]|darwin8.[[456]].*) + # + # Tiger, subsequent to Intel support but prior + # to x86-64 support. Build libraries and + # executables for 32-bit PowerPC, 64-bit + # PowerPC, and 32-bit x86, with 32-bit PowerPC + # first. (I'm guessing that's what Apple does.) + # + # (The double brackets are needed because + # autotools/m4 use brackets as a quoting + # character; the double brackets turn into + # single brackets in the generated configure + # file.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386" + ;; + + darwin8.*) + # + # All other Tiger, so subsequent to x86-64 + # support. Build libraries and executables for + # 32-bit PowerPC, 64-bit PowerPC, 32-bit x86, + # and x86-64, with 32-bit PowerPC first. (I'm + # guessing that's what Apple does.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + ;; + + darwin9.*) + # + # Leopard. Build libraries for 32-bit PowerPC, + # 64-bit PowerPC, 32-bit x86, and x86-64, with + # 32-bit PowerPC first, and build executables + # for 32-bit x86 and 32-bit PowerPC, with 32-bit + # x86 first. (That's what Apple does.) + # + V_LIB_CCOPT_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_LIB_LDFLAGS_FAT="-arch ppc -arch ppc64 -arch i386 -arch x86_64" + V_PROG_CCOPT_FAT="-arch i386 -arch ppc" + V_PROG_LDFLAGS_FAT="-arch i386 -arch ppc" + ;; + + darwin10.*) + # + # Snow Leopard. Build libraries for x86-64, + # 32-bit x86, and 32-bit PowerPC, with x86-64 + # first, and build executables for x86-64 and + # 32-bit x86, with x86-64 first. (That's what + # Apple does, even though Snow Leopard doesn't + # run on PPC, so PPC libpcap runs under Rosetta, + # and Rosetta doesn't support BPF ioctls, so PPC + # programs can't do live captures.) + # + V_LIB_CCOPT_FAT="-arch x86_64 -arch i386 -arch ppc" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch i386 -arch ppc" + V_PROG_CCOPT_FAT="-arch x86_64 -arch i386" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch i386" + ;; + + darwin1[[1-8]]*) + # + # Post-Snow Leopard, pre-Catalina. Build + # libraries for x86-64 and 32-bit x86, with + # x86-64 first, and build executables only for + # x86-64. (That's what Apple does.) This + # requires no special flags for programs. + # + # We check whether we *can* build for i386 and, + # if not, suggest that the user install the + # /usr/include headers if they want to build + # fat. + # + AC_MSG_CHECKING(whether building for 32-bit x86 is supported) + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS -arch i386" + AC_TRY_LINK( + [], + [return 0;], + [ + AC_MSG_RESULT(yes) + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + + # + # OpenSSL installation on macOS seems + # to install only the libs for 64-bit + # x86 - at least that's what Brew does: + # only configure 32-bit builds if we + # don't have OpenSSL. + # + if test "$HAVE_OPENSSL" != yes; then + V_LIB_CCOPT_FAT="$V_LIB_CCOPT_FAT -arch i386" + V_LIB_LDFLAGS_FAT="$V_LIB_LDFLAGS_FAT -arch i386" + fi + ], + [ + AC_MSG_RESULT(no) + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + case "$host_os" in + + darwin18.*) + # + # Mojave; you need to install the + # /usr/include headers to get + # 32-bit x86 builds to work. + # + AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools and, after that, installing the /usr/include headers from the /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg package]) + ;; + + *) + # + # Pre-Mojave; the command-line + # tools should be sufficient to + # enable 32-bit x86 builds. + # + AC_MSG_WARN([Compiling for 32-bit x86 gives an error; try installing the command-line tools]) + ;; + esac + ]) + AC_LBL_RESTORE_CHECK_STATE + ;; + + darwin19*) + # + # Catalina. Build libraries and executables + # only for x86-64. (That's what Apple does; + # 32-bit x86 binaries are not supported on + # Catalina.) + # + V_LIB_CCOPT_FAT="-arch x86_64" + V_LIB_LDFLAGS_FAT="-arch x86_64" + V_PROG_CCOPT_FAT="-arch x86_64" + V_PROG_LDFLAGS_FAT="-arch x86_64" + ;; + + darwin*) + # + # Post-Catalina. Build libraries and + # executables for x86-64 and ARM64. + # (That's what Apple does, except they + # build for arm64e, which may include + # some of the pointer-checking extensions.) + # + # If we're building with libssl, make sure + # we can build fat with it (i.e., that it + # was built fat); if we can't, don't set + # the target architectures, and just + # build for the host we're on. + # + # Otherwise, just add both of them. + # + if test "$HAVE_OPENSSL" = yes; then + AC_MSG_CHECKING(whether building fat with libssl is supported) + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS -arch x86_64 -arch arm64" + LDFLAGS="$LDFLAGS $OPENSSL_LIBS" + AC_TRY_LINK( + [ + #include + ], + [ + SSL_library_init(); + return 0; + ], + [ + AC_MSG_RESULT(yes) + V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" + V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" + ], + [AC_MSG_RESULT(no)] + ) + AC_LBL_RESTORE_CHECK_STATE + else + V_LIB_CCOPT_FAT="-arch x86_64 -arch arm64" + V_LIB_LDFLAGS_FAT="-arch x86_64 -arch arm64" + V_PROG_CCOPT_FAT="-arch x86_64 -arch arm64" + V_PROG_LDFLAGS_FAT="-arch x86_64 -arch arm64" + fi + ;; + esac + fi + ;; + +hpux9*) + AC_DEFINE(HAVE_HPUX9,1,[on HP-UX 9.x]) + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.0*) + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux10.1*) + + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +hpux*) + dnl HPUX 10.20 and above is similar to HPUX 9, but + dnl not the same.... + dnl + dnl XXX - DYEXT should be set to "sl" if this is building + dnl for 32-bit PA-RISC, but should be left as "so" for + dnl 64-bit PA-RISC or, I suspect, IA-64. + AC_DEFINE(HAVE_HPUX10_20_OR_LATER,1,[on HP-UX 10.20 or later]) + if test "`uname -m`" = "ia64"; then + DYEXT="so" + else + DYEXT="sl" + fi + + # + # "-b" builds a shared library; "+h" sets the soname. + # + SHLIB_OPT="-b" + SONAME_OPT="+h" + + # + # Use System V conventions for man pages. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +irix*) + # + # Use IRIX conventions for man pages; they're the same as the + # System V conventions, except that they use section 8 for + # administrative commands and daemons. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + ;; + +linux*|freebsd*|netbsd*|openbsd*|dragonfly*|kfreebsd*|gnu*|haiku*|midipix*) + DYEXT="so" + ;; + +osf*) + DYEXT="so" + + # + # DEC OSF/1, a/k/a Digital UNIX, a/k/a Tru64 UNIX. + # Use Tru64 UNIX conventions for man pages; they're the same as + # the System V conventions except that they use section 8 for + # administrative commands and daemons. + # + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + MAN_DEVICES=7 + ;; + +sinix*) + AC_MSG_CHECKING(if SINIX compiler defines sinix) + AC_CACHE_VAL(ac_cv_cc_sinix_defined, + AC_TRY_COMPILE( + [], + [int i = sinix;], + ac_cv_cc_sinix_defined=yes, + ac_cv_cc_sinix_defined=no)) + AC_MSG_RESULT($ac_cv_cc_sinix_defined) + if test $ac_cv_cc_sinix_defined = no ; then + AC_DEFINE(sinix,1,[on sinix]) + fi + ;; + +solaris*) + AC_DEFINE(HAVE_SOLARIS,1,[On solaris]) + + DYEXT="so" + + # + # Make sure errno is thread-safe, in case we're called in + # a multithreaded program. We don't guarantee that two + # threads can use the *same* pcap_t safely, but the + # current version does guarantee that you can use different + # pcap_t's in different threads, and even that pcap_compile() + # is thread-safe (it wasn't thread-safe in some older versions). + # + V_CCOPT="$V_CCOPT -D_TS_ERRNO" + + case "`uname -r`" in + + 5.12) + ;; + + *) + # + # Use System V conventions for man pages. + # + MAN_ADMIN_COMMANDS=1m + MAN_FILE_FORMATS=4 + MAN_MISC_INFO=5 + MAN_DEVICES=7D + esac + ;; +esac +AC_SUBST(V_LIB_CCOPT_FAT) +AC_SUBST(V_LIB_LDFLAGS_FAT) +AC_SUBST(V_PROG_CCOPT_FAT) +AC_SUBST(V_PROG_LDFLAGS_FAT) +AC_SUBST(DYEXT) +AC_SUBST(MAN_DEVICES) +AC_SUBST(MAN_FILE_FORMATS) +AC_SUBST(MAN_MISC_INFO) +AC_SUBST(MAN_ADMIN_COMMANDS) + +AC_ARG_ENABLE(shared, +AS_HELP_STRING([--enable-shared],[build shared libraries @<:@default=yes, if support available@:>@])) +test "x$enable_shared" = "xno" && DYEXT="none" + +AC_PROG_RANLIB +AC_CHECK_TOOL([AR], [ar]) + +AC_PROG_LN_S +AC_SUBST(LN_S) + +AC_LBL_DEVEL(V_CCOPT) + +# +# Check to see if the sockaddr struct has the 4.4 BSD sa_len member. +# +AC_CHECK_MEMBERS([struct sockaddr.sa_len],,, + [ + #include + #include + ]) + +# +# Check to see if there's a sockaddr_storage structure. +# +AC_CHECK_TYPES(struct sockaddr_storage,,, + [ + #include + #include + ]) + +# +# Check to see if the dl_hp_ppa_info_t struct has the HP-UX 11.00 +# dl_module_id_1 member. +# +# NOTE: any failure means we conclude that it doesn't have that member, +# so if we don't have DLPI, don't have a header, or +# have one that doesn't declare a dl_hp_ppa_info_t type, we conclude +# it doesn't have that member (which is OK, as either we won't be +# using code that would use that member, or we wouldn't compile in +# any case). +# +AC_CHECK_MEMBERS([dl_hp_ppa_info_t.dl_module_id_1],,, + [ + #include + #include + #include + ]) + +# +# Various Linux-specific mechanisms. +# +AC_ARG_ENABLE([usb], +[AS_HELP_STRING([--enable-usb],[enable Linux usbmon USB capture support @<:@default=yes, if support available@:>@])], + [], + [enable_usb=yes]) + +# +# If somebody requested an XXX-only pcap, that doesn't include +# additional mechanisms. +# +if test "xxx_only" != yes; then + case "$host_os" in + linux*) + dnl check for USB sniffing support + AC_MSG_CHECKING(for Linux usbmon USB sniffing support) + if test "x$enable_usb" != "xno" ; then + AC_DEFINE(PCAP_SUPPORT_LINUX_USBMON, 1, [target host supports Linux usbmon for USB sniffing]) + MODULE_C_SRC="$MODULE_C_SRC pcap-usb-linux.c" + AC_MSG_RESULT(yes) + # + # Note: if the directory for special files is *EVER* somewhere + # other than the UN*X standard of /dev (which will break any + # software that looks for /dev/null or /dev/tty, for example, + # so doing that is *REALLY* not a good idea), please provide + # some mechanism to determine that directory at *run time*, + # rather than *configure time*, so that it works when doing + # a cross-build, and that works with *multiple* distributions, + # with our without udev, and with multiple versions of udev, + # with udevinfo or udevadm or any other mechanism to get the + # special files directory. + # + # Do we have a version of available? + # If so, we might need it for . + # + AC_CHECK_HEADERS(linux/compiler.h) + if test "$ac_cv_header_linux_compiler_h" = yes; then + # + # Yes - include it when testing for . + # + AC_CHECK_HEADERS(linux/usbdevice_fs.h,,,[#include ]) + else + AC_CHECK_HEADERS(linux/usbdevice_fs.h) + fi + if test "$ac_cv_header_linux_usbdevice_fs_h" = yes; then + # + # OK, does it define bRequestType? Older versions of the kernel + # define fields with names like "requesttype, "request", and + # "value", rather than "bRequestType", "bRequest", and + # "wValue". + # + AC_CHECK_MEMBERS([struct usbdevfs_ctrltransfer.bRequestType],,, + [ + AC_INCLUDES_DEFAULT + #ifdef HAVE_LINUX_COMPILER_H + #include + #endif + #include + ]) + fi + else + AC_MSG_RESULT(no) + fi + + # + # Life's too short to deal with trying to get this to compile + # if you don't get the right types defined with + # __KERNEL_STRICT_NAMES getting defined by some other include. + # + # Check whether the includes Just Work. If not, don't turn on + # netfilter support. + # + AC_MSG_CHECKING(whether we can compile the netfilter support) + AC_CACHE_VAL(ac_cv_netfilter_can_compile, + AC_TRY_COMPILE([ +AC_INCLUDES_DEFAULT +#include +#include +#include + +#include +#include +#include +#include +#include ], + [], + ac_cv_netfilter_can_compile=yes, + ac_cv_netfilter_can_compile=no)) + AC_MSG_RESULT($ac_cv_netfilter_can_compile) + if test $ac_cv_netfilter_can_compile = yes ; then + AC_DEFINE(PCAP_SUPPORT_NETFILTER, 1, + [target host supports netfilter sniffing]) + MODULE_C_SRC="$MODULE_C_SRC pcap-netfilter-linux.c" + fi + ;; + esac +fi +AC_SUBST(PCAP_SUPPORT_LINUX_USBMON) +AC_SUBST(PCAP_SUPPORT_NETFILTER) + +AC_ARG_ENABLE([netmap], +[AS_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])], + [], + [enable_netmap=yes]) + +if test "x$enable_netmap" != "xno" ; then + # + # Check whether net/netmap_user.h is usable if NETMAP_WITH_LIBS is + # defined; it's not usable on DragonFly BSD 4.6 if NETMAP_WITH_LIBS + # is defined, for example, as it includes a nonexistent malloc.h + # header. + # + AC_MSG_CHECKING(whether we can compile the netmap support) + AC_CACHE_VAL(ac_cv_net_netmap_user_can_compile, + AC_TRY_COMPILE([ +AC_INCLUDES_DEFAULT +#define NETMAP_WITH_LIBS +#include ], + [], + ac_cv_net_netmap_user_can_compile=yes, + ac_cv_net_netmap_user_can_compile=no)) + AC_MSG_RESULT($ac_cv_net_netmap_user_can_compile) + if test $ac_cv_net_netmap_user_can_compile = yes ; then + AC_DEFINE(PCAP_SUPPORT_NETMAP, 1, + [target host supports netmap]) + MODULE_C_SRC="$MODULE_C_SRC pcap-netmap.c" + fi + AC_SUBST(PCAP_SUPPORT_NETMAP) +fi + +# Check for DPDK support. +AC_ARG_WITH([dpdk], +AS_HELP_STRING([--with-dpdk@<:@=DIR@:>@],[include DPDK support (located in directory DIR, if supplied). @<:@default=yes, if present@:>@]), +[ + if test "$withval" = no + then + # User doesn't want DPDK support. + want_dpdk=no + elif test "$withval" = yes + then + # User wants DPDK support but hasn't specified a directory. + want_dpdk=yes + else + # User wants DPDK support and has specified a directory, + # so use the provided value. + want_dpdk=yes + dpdk_dir=$withval + fi +],[ + if test "$V_PCAP" = dpdk; then + # User requested DPDK-only libpcap, so we'd better have + # the DPDK API. + want_dpdk=yes + elif test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want DPDK support. + want_dpdk=no + else + # + # Use DPDK API if present, otherwise don't + # + want_dpdk=ifpresent + fi +]) + +if test "$want_dpdk" != no; then + # + # The user didn't explicitly say they don't want DPDK, + # so see if we have it. + # + # We only try to find it using pkg-config; DPDK is *SO* + # complicated - DPDK 19.02, for example, has about 117(!) + # libraries, and the precise set of libraries required has + # changed over time - so attempting to guess which libraries + # you need, and hardcoding that in an attempt to find the + # libraries without DPDK, rather than relying on DPDK to + # tell you, with a .pc file, what libraries are needed, + # is *EXTREMELY* fragile and has caused some bug reports, + # so we're just not going to do it. + # + # If that causes a problem, the only thing we will do is + # accept an alternative way of finding the appropriate + # library set for the installed version of DPDK that is + # as robust as pkg-config (i.e., it had better work as well + # as pkg-config with *ALL* versions of DPDK that provide a + # libdpdk.pc file). + # + # If --with-dpdk={path} was specified, add {path}/pkgconfig + # to PKG_CONFIG_PATH, so we look for the .pc file there, + # first. + # + save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" + if test -n "$dpdk_dir"; then + PKG_CONFIG_PATH="$dpdk_dir:$PKG_CONFIG_PATH" + fi + PKG_CHECK_MODULE(DPDK, libdpdk, + [ + found_dpdk=yes + ]) + PKG_CONFIG_PATH="$save_PKG_CONFIG_PATH" + + # + # Did we find DPDK? + # + if test "$found_dpdk" = yes; then + # + # Found it. + # + # We call rte_eth_dev_count_avail(), and older versions + # of DPDK didn't have it, so check for it. + # + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS $DPDK_CFLAGS" + LIBS="$LIBS $DPDK_LIBS" + AC_CHECK_FUNC(rte_eth_dev_count_avail) + AC_LBL_RESTORE_CHECK_STATE + fi + + if test "$ac_cv_func_rte_eth_dev_count_avail" = yes; then + # + # We found a usable DPDK. + # + # Check whether the rte_ether.h file defines + # struct ether_addr or struct rte_ether_addr. + # + # ("API compatibility? That's for losers!") + # + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS $DPDK_CFLAGS" + LIBS="$LIBS $DPDK_LIBS" + AC_CHECK_TYPES(struct rte_ether_addr,,, + [ + #include + ]) + AC_LBL_RESTORE_CHECK_STATE + + # + # We can build with DPDK. + # + V_INCLS="$V_INCLS $DPDK_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DPDK_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DPDK_LIBS_STATIC" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE libdpdk" + AC_DEFINE(PCAP_SUPPORT_DPDK, 1, [target host supports DPDK]) + if test $V_PCAP != dpdk ; then + MODULE_C_SRC="$MODULE_C_SRC pcap-dpdk.c" + fi + else + # + # We didn't find a usable DPDK. + # If we required it (with --with-dpdk or --with-pcap=dpdk), + # fail with an appropriate message telling the user what + # the problem was, otherwise note the problem with a + # warning. + # + if test "$found_dpdk" != yes; then + # + # Not found with pkg-config. Note that we + # require that DPDK must be findable with + # pkg-config. + # + if test "$V_PCAP" = dpdk; then + # + # User requested DPDK-only capture support. + # + AC_MSG_ERROR( +[DPDK support requested with --with-pcap=dpdk, but +we couldn't find DPDK with pkg-config. Make sure that pkg-config is +installed, that DPDK 18.02.2 or later is installed, and that DPDK +provides a .pc file.]) + fi + + if test "$want_dpdk" = yes; then + # + # User requested that libpcap include + # DPDK capture support. + # + AC_MSG_ERROR( +[DPDK support requested with --with-dpdk, but we +couldn't find DPDK with pkg-config. Make sure that pkg-config +is installed, that DPDK 18.02.2 or later is installed, and that +DPDK provides .pc file.]) + fi + + # + # User didn't indicate whether they wanted DPDK + # or not; just warn why we didn't find it. + # + AC_MSG_WARN( +[We couldn't find DPDK with pkg-config. If +you want DPDK support, make sure that pkg-config is installed, +that DPDK 18.02.2 or later is installed, and that DPDK provides a +.pc file.]) + elif test "$ac_cv_func_rte_eth_dev_count_avail" != yes; then + # + # Found with pkg-config, but we couldn't compile + # a program that calls rte_eth_dev_count(); we + # probably have the developer package installed, + # but don't have a sufficiently recent version + # of DPDK. Note that we need a sufficiently + # recent version of DPDK. + # + if test "$V_PCAP" = dpdk; then + # + # User requested DPDK-only capture support. + # + AC_MSG_ERROR( +[DPDK support requested with --with-pcap=dpdk, but we +can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 or later +is installed.]) + fi + + if test "$want_dpdk" = yes; then + # + # User requested that libpcap include + # DPDK capture support. + # + AC_MSG_ERROR( +[DPDK support requested with --with-dpdk, but +we can't compile libpcap with DPDK. Make sure that DPDK 18.02.2 +or later is DPDK is installed.]) + fi + + # + # User didn't indicate whether they wanted DPDK + # or not; just warn why we didn't find it. + # + AC_MSG_WARN( +[DPDK was found, but we can't compile libpcap with it. +Make sure that DPDK 18.02.2 or later is installed.]) + fi + fi +fi +AC_SUBST(PCAP_SUPPORT_DPDK) + +AC_ARG_ENABLE([bluetooth], +[AS_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])], + [], + [enable_bluetooth=ifsupportavailable]) + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want Bluetooth support. + enable_bluetooth=no +fi + +if test "x$enable_bluetooth" != "xno" ; then + dnl check for Bluetooth sniffing support + case "$host_os" in + linux*) + AC_CHECK_HEADER(bluetooth/bluetooth.h, + [ + # + # We have bluetooth.h, so we support Bluetooth + # sniffing. + # + AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing]) + MODULE_C_SRC="$MODULE_C_SRC pcap-bt-linux.c" + AC_MSG_NOTICE(Bluetooth sniffing is supported) + ac_lbl_bluetooth_available=yes + + # + # OK, does struct sockaddr_hci have an hci_channel + # member? + # + AC_CHECK_MEMBERS([struct sockaddr_hci.hci_channel], + [ + # + # Yes; is HCI_CHANNEL_MONITOR defined? + # + AC_MSG_CHECKING(if HCI_CHANNEL_MONITOR is defined) + AC_CACHE_VAL(ac_cv_lbl_hci_channel_monitor_is_defined, + AC_TRY_COMPILE( + [ + #include + #include + ], + [ + int i = HCI_CHANNEL_MONITOR; + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(PCAP_SUPPORT_BT_MONITOR, 1, + [target host supports Bluetooth Monitor]) + MODULE_C_SRC="$MODULE_C_SRC pcap-bt-monitor-linux.c" + ], + [ + AC_MSG_RESULT(no) + ])) + ],, + [ + #include + #include + ]) + ], + [ + # + # We don't have bluetooth.h, so we don't support + # Bluetooth sniffing. + # + if test "x$enable_bluetooth" = "xyes" ; then + AC_MSG_ERROR(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) + else + AC_MSG_NOTICE(Bluetooth sniffing is not supported; install bluez-lib devel to enable it) + fi + ]) + ;; + *) + if test "x$enable_bluetooth" = "xyes" ; then + AC_MSG_ERROR(no Bluetooth sniffing support implemented for $host_os) + else + AC_MSG_NOTICE(no Bluetooth sniffing support implemented for $host_os) + fi + ;; + esac + AC_SUBST(PCAP_SUPPORT_BT) +fi + +AC_ARG_ENABLE([dbus], +[AS_HELP_STRING([--enable-dbus],[enable D-Bus capture support @<:@default=yes, if support available@:>@])], + [], + [enable_dbus=ifavailable]) + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want D-Bus support. + enable_dbus=no +fi + +if test "x$enable_dbus" != "xno"; then + if test "x$enable_dbus" = "xyes"; then + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on macOS; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user requested it, so fail. + # + AC_MSG_ERROR([Due to freedesktop.org bug 74029, D-Bus capture support is not available on macOS]) + esac + else + case "$host_os" in + + darwin*) + # + # We don't support D-Bus sniffing on macOS; see + # + # https://bugs.freedesktop.org/show_bug.cgi?id=74029 + # + # The user didn't explicitly request it, so just + # silently refuse to enable it. + # + enable_dbus="no" + ;; + esac + fi +fi + +if test "x$enable_dbus" != "xno"; then + PKG_CHECK_MODULE(DBUS, dbus-1, + [ + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS $DBUS_CFLAGS" + LIBS="$LIBS $DBUS_LIBS" + AC_MSG_CHECKING(whether the D-Bus library defines dbus_connection_read_write) + AC_TRY_LINK( + [#include + + #include + #include + + #include ], + [return dbus_connection_read_write(NULL, 0);], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE(PCAP_SUPPORT_DBUS, 1, [support D-Bus sniffing]) + MODULE_C_SRC="$MODULE_C_SRC pcap-dbus.c" + V_INCLS="$V_INCLS $DBUS_CFLAGS" + ADDITIONAL_LIBS="$ADDITIONAL_LIBS $DBUS_LIBS" + ADDITIONAL_LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $DBUS_LIBS_STATIC" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE dbus-1" + ], + [ + AC_MSG_RESULT([no]) + if test "x$enable_dbus" = "xyes"; then + AC_MSG_ERROR([--enable-dbus was given, but the D-Bus library doesn't define dbus_connection_read_write()]) + fi + ]) + AC_LBL_RESTORE_CHECK_STATE + ], + [ + if test "x$enable_dbus" = "xyes"; then + AC_MSG_ERROR([--enable-dbus was given, but the dbus-1 package is not installed]) + fi + ]) + AC_SUBST(PCAP_SUPPORT_DBUS) +fi + +AC_ARG_ENABLE([rdma], +[AS_HELP_STRING([--enable-rdma],[enable RDMA capture support @<:@default=yes, if support available@:>@])], + [], + [enable_rdma=ifavailable]) + +if test "xxx_only" = yes; then + # User requested something-else-only pcap, so they don't + # want RDMA support. + enable_rdma=no +fi + +if test "x$enable_rdma" != "xno"; then + PKG_CHECK_MODULE(LIBIBVERBS, libibverbs, + [ + found_libibverbs=yes + LIBIBVERBS_REQUIRES_PRIVATE="libibverbs" + ]) + + if test "x$found_libibverbs" != "xyes"; then + AC_CHECK_LIB(ibverbs, ibv_get_device_list, + [ + found_libibverbs=yes + LIBIBVERBS_CFLAGS="" + LIBIBVERBS_LIBS="-libverbs" + # XXX - at least on Ubuntu 20.04, there are many more + # libraries needed; is there any platform where + # libibverbs is available but where pkg-config isn't + # available or libibverbs doesn't use it? If not, + # we should only use pkg-config for it. + LIBIBVERBS_LIBS_STATIC="-libverbs" + LIBIBVERBS_LIBS_PRIVATE="-libverbs" + ] + ) + fi + + if test "x$found_libibverbs" = "xyes"; then + AC_LBL_SAVE_CHECK_STATE + CFLAGS="$CFLAGS $LIBIBVERBS_CFLAGS" + LIBS="$LIBS $LIBIBVERBS_LIBS" + AC_CHECK_HEADER(infiniband/verbs.h, [ + # + # ibv_create_flow may be defined as a static inline + # function in infiniband/verbs.h, so we can't + # use AC_CHECK_LIB. + # + # Too bad autoconf has no AC_SYMBOL_EXISTS() + # macro that works like CMake's check_symbol_exists() + # function, to check do a compile check like + # this (they do a clever trick to avoid having + # to know the function's signature). + # + AC_MSG_CHECKING(whether libibverbs defines ibv_create_flow) + AC_TRY_LINK( + [ + #include + ], + [ + (void) ibv_create_flow((struct ibv_qp *) NULL, + (struct ibv_flow_attr *) NULL); + ], + [ + AC_MSG_RESULT([yes]) + found_usable_libibverbs=yes + ], + [ + AC_MSG_RESULT([no]) + ] + ) + ]) + AC_LBL_RESTORE_CHECK_STATE + fi + + if test "x$found_usable_libibverbs" = "xyes" + then + AC_DEFINE(PCAP_SUPPORT_RDMASNIFF, 1, [target host supports RDMA sniffing]) + MODULE_C_SRC="$MODULE_C_SRC pcap-rdmasniff.c" + CFLAGS="$LIBIBVERBS_CFLAGS $CFLAGS" + ADDITIONAL_LIBS="$LIBIBVERBS_LIBS $ADDITIONAL_LIBS" + ADDITIONAL_LIBS_STATIC="$LIBIBVERBS_LIBS_STATIC $ADDITIONAL_LIBS_STATIC" + LIBS_PRIVATE="$LIBIBVERBS_LIBS_PRIVATE $LIBS_PRIVATE" + REQUIRES_PRIVATE="$REQUIRES_PRIVATE $LIBIBVERBS_REQUIRES_PRIVATE" + fi + AC_SUBST(PCAP_SUPPORT_RDMASNIFF) +fi + +# +# If this is a platform where we need to have the .pc file and +# pcap-config script supply an rpath option to specify the directory +# in which the libpcap shared library is installed, and the install +# prefix /usr (meaning we're not installing a system library), provide +# the rpath option. +# +# (We must check $prefix, as $libdir isn't necessarily /usr/lib in this +# case - for example, Linux distributions for 64-bit platforms that +# also provide support for binaries for a 32-bit version of the +# platform may put the 64-bit libraries, the 32-bit libraries, or both +# in directories other than /usr/lib.) +# +# In AIX, do we have to do this? +# +# In Darwin-based OSes, the full paths of the shared libraries with +# which the program was linked are stored in the executable, so we don't +# need to provide an rpath option. +# +# With the HP-UX linker, directories specified with -L are, by default, +# added to the run-time search path, so we don't need to supply them. +# +# For Tru64 UNIX, "-rpath" works with DEC's^WCompaq's^WHP's C compiler +# for Alpha, but isn't documented as working with GCC, and no GCC- +# compatible option is documented as working with the DEC compiler. +# If anybody needs this on Tru64/Alpha, they're welcome to figure out a +# way to make it work. +# +# This must *not* depend on the compiler, as, on platforms where there's +# a GCC-compatible compiler and a vendor compiler, we need to work with +# both. +# +if test "$prefix" != "/usr"; then + case "$host_os" in + + freebsd*|netbsd*|openbsd*|dragonfly*|linux*|haiku*|midipix*|gnu*) + # + # Platforms where the "native" C compiler is GCC or + # accepts compatible command-line arguments, and the + # "native" linker is the GNU linker or accepts + # compatible command-line arguments. + # + RPATH="-Wl,-rpath,\${libdir}" + ;; + + solaris*) + # + # Sun/Oracle's linker, the GNU linker, and + # GNU-compatible linkers all support -R. + # + RPATH="-Wl,-R,\${libdir}" + ;; + esac +fi + +AC_PROG_INSTALL + +AC_CONFIG_HEADER(config.h) + +AC_SUBST(V_SHLIB_CCOPT) +AC_SUBST(V_SHLIB_CMD) +AC_SUBST(V_SHLIB_OPT) +AC_SUBST(V_SONAME_OPT) +AC_SUBST(RPATH) +AC_SUBST(ADDLOBJS) +AC_SUBST(ADDLARCHIVEOBJS) +AC_SUBST(PLATFORM_C_SRC) +AC_SUBST(MODULE_C_SRC) +AC_SUBST(REMOTE_C_SRC) +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(BUILD_RPCAPD) +AC_SUBST(INSTALL_RPCAPD) +AC_SUBST(RPCAPD_LIBS) + +# +# We're done with configuration operations; add ADDITIONAL_LIBS and +# ADDITIONAL_LIBS_STATIC to LIBS and LIBS_STATIC, respectively. +# +LIBS="$ADDITIONAL_LIBS $LIBS" +LIBS_STATIC="$ADDITIONAL_LIBS_STATIC $LIBS_STATIC" + +AC_OUTPUT_COMMANDS([if test -f .devel; then + echo timestamp > stamp-h + cat $srcdir/Makefile-devel-adds >> Makefile + make depend || exit 1 +fi]) +AC_OUTPUT(Makefile grammar.y pcap-filter.manmisc pcap-linktype.manmisc + pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap + pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap + pcap_get_tstamp_precision.3pcap pcap_list_datalinks.3pcap + pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap + pcap_open_offline.3pcap pcap_set_immediate_mode.3pcap + pcap_set_tstamp_precision.3pcap pcap_set_tstamp_type.3pcap + rpcapd/Makefile rpcapd/rpcapd.manadmin rpcapd/rpcapd-config.manfile + testprogs/Makefile) +exit 0 diff --git a/src/libpcap-1.10.5/diag-control.h b/src/libpcap-1.10.5/diag-control.h new file mode 100644 index 0000000000..d38f04caac --- /dev/null +++ b/src/libpcap-1.10.5/diag-control.h @@ -0,0 +1,430 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _diag_control_h +#define _diag_control_h + +#include "pcap/compiler-tests.h" + +#if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) || \ + PCAP_IS_AT_LEAST_GNUC_VERSION(4,6) || \ + PCAP_IS_AT_LEAST_SUNC_VERSION(5,5) + /* + * All these compilers support this way of putting pragmas into #defines. + * We use it only if we have a compiler that supports it; see below + * for the code that uses it and the #defines that control whether + * that code is used. + */ + #define PCAP_DO_PRAGMA(x) _Pragma (#x) +#endif + +/* + * Suppress "enum value not explicitly handled in switch" warnings. + * We may have to build on multiple different Windows SDKs, so we + * may not be able to include all enum values in a switch, as they + * won't necessarily be defined on all the SDKs, and, unlike + * #defines, there's no easy way to test whether a given enum has + * a given value. It *could* be done by the configure script or + * CMake tests. + */ +#if defined(_MSC_VER) + #define DIAG_OFF_ENUM_SWITCH \ + __pragma(warning(push)) \ + __pragma(warning(disable:4061)) + #define DIAG_ON_ENUM_SWITCH \ + __pragma(warning(pop)) +#endif + +/* + * Suppress "switch statement has only a default case" warnings. + * There's a switch in bpf_filter.c that only has additional + * cases on Linux. + */ +#if defined(_MSC_VER) + #define DIAG_OFF_DEFAULT_ONLY_SWITCH \ + __pragma(warning(push)) \ + __pragma(warning(disable:4065)) + #define DIAG_ON_DEFAULT_ONLY_SWITCH \ + __pragma(warning(pop)) +#endif + +/* + * Suppress Flex, narrowing, and deprecation warnings. + */ +#if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) + /* + * This is Clang 2.8 or later; we can use "clang diagnostic + * ignored -Wxxx" and "clang diagnostic push/pop". + * + * Suppress -Wdocumentation warnings; GCC doesn't support -Wdocumentation, + * at least according to the GCC 7.3 documentation. Apparently, Flex + * generates code that upsets at least some versions of Clang's + * -Wdocumentation. + * + * (This could be clang-cl, which defines _MSC_VER, so test this + * before testing _MSC_VER.) + */ + #define DIAG_OFF_FLEX \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wsign-compare") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdocumentation") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wmissing-noreturn") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunused-parameter") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code") + #define DIAG_ON_FLEX \ + PCAP_DO_PRAGMA(clang diagnostic pop) + + /* + * Suppress the only narrowing warnings you get from Clang. + */ + #define DIAG_OFF_NARROWING \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshorten-64-to-32") + + #define DIAG_ON_NARROWING \ + PCAP_DO_PRAGMA(clang diagnostic pop) + + /* + * Suppress deprecation warnings. + */ + #define DIAG_OFF_DEPRECATION \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdeprecated-declarations") + #define DIAG_ON_DEPRECATION \ + PCAP_DO_PRAGMA(clang diagnostic pop) + + /* + * When Clang correctly detects an old-style function prototype after + * preprocessing, the warning can be irrelevant to this source tree because + * the prototype comes from a system header macro. + */ + #if PCAP_IS_AT_LEAST_CLANG_VERSION(5,0) + #define DIAG_OFF_STRICT_PROTOTYPES \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wstrict-prototypes") + #define DIAG_ON_STRICT_PROTOTYPES \ + PCAP_DO_PRAGMA(clang diagnostic pop) + #endif + + #define DIAG_OFF_DOCUMENTATION \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wdocumentation") + #define DIAG_ON_DOCUMENTATION \ + PCAP_DO_PRAGMA(clang diagnostic pop) + + #define DIAG_OFF_SIGN_COMPARE \ + PCAP_DO_PRAGMA(clang diagnostic push) \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wsign-compare") + #define DIAG_ON_SIGN_COMPARE \ + PCAP_DO_PRAGMA(clang diagnostic pop) +#elif defined(_MSC_VER) + /* + * This is Microsoft Visual Studio; we can use __pragma(warning(disable:XXXX)) + * and __pragma(warning(push/pop)). + * + * Suppress signed-vs-unsigned comparison, narrowing, and unreachable + * code warnings. + */ + #define DIAG_OFF_FLEX \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + __pragma(warning(disable:4242)) \ + __pragma(warning(disable:4244)) \ + __pragma(warning(disable:4702)) + #define DIAG_ON_FLEX \ + __pragma(warning(pop)) + + /* + * Suppress narrowing warnings. + */ + #define DIAG_OFF_NARROWING \ + __pragma(warning(push)) \ + __pragma(warning(disable:4242)) \ + __pragma(warning(disable:4311)) + #define DIAG_ON_NARROWING \ + __pragma(warning(pop)) + + /* + * Suppress deprecation warnings. + */ + #define DIAG_OFF_DEPRECATION \ + __pragma(warning(push)) \ + __pragma(warning(disable:4996)) + #define DIAG_ON_DEPRECATION \ + __pragma(warning(pop)) +#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6) + /* + * This is GCC 4.6 or later, or a compiler claiming to be that. + * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2) + * and "GCC diagnostic push/pop" (introduced in 4.6). + */ + #define DIAG_OFF_FLEX \ + PCAP_DO_PRAGMA(GCC diagnostic push) \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wsign-compare") \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunused-parameter") \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code") + #define DIAG_ON_FLEX \ + PCAP_DO_PRAGMA(GCC diagnostic pop) + + /* + * GCC currently doesn't issue any narrowing warnings. + */ + + /* + * Suppress deprecation warnings. + */ + #define DIAG_OFF_DEPRECATION \ + PCAP_DO_PRAGMA(GCC diagnostic push) \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") + #define DIAG_ON_DEPRECATION \ + PCAP_DO_PRAGMA(GCC diagnostic pop) + + /* + * Suppress format-truncation= warnings. + * GCC 7.1 had introduced this warning option. Earlier versions (at least + * one particular copy of GCC 4.6.4) treat the request as a warning. + */ + #if PCAP_IS_AT_LEAST_GNUC_VERSION(7,1) + #define DIAG_OFF_FORMAT_TRUNCATION \ + PCAP_DO_PRAGMA(GCC diagnostic push) \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wformat-truncation=") + #define DIAG_ON_FORMAT_TRUNCATION \ + PCAP_DO_PRAGMA(GCC diagnostic pop) + #endif +#elif PCAP_IS_AT_LEAST_SUNC_VERSION(5,5) + /* + * Sun C compiler version 5.5 (Studio version 8) and later supports "#pragma + * error_messages()". + */ + #define DIAG_OFF_FLEX \ + PCAP_DO_PRAGMA(error_messages(off,E_STATEMENT_NOT_REACHED)) + #define DIAG_ON_FLEX \ + PCAP_DO_PRAGMA(error_messages(default,E_STATEMENT_NOT_REACHED)) +#endif + +#ifdef YYBYACC + /* + * Berkeley YACC. + * + * It generates a global declaration of yylval, or the appropriately + * prefixed version of yylval, in grammar.h, *even though it's been + * told to generate a pure parser, meaning it doesn't have any global + * variables*. Bison doesn't do this. + * + * That causes a warning due to the local declaration in the parser + * shadowing the global declaration. + * + * So, if the compiler warns about that, we turn off -Wshadow warnings. + * + * In addition, the generated code may have functions with unreachable + * code, so suppress warnings about those. + */ + #if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) + /* + * This is Clang 2.8 or later (including clang-cl, so test this + * before _MSC_VER); we can use "clang diagnostic ignored -Wxxx". + */ + #define DIAG_OFF_BISON_BYACC \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wshadow") \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code") + #elif defined(_MSC_VER) + /* + * This is Microsoft Visual Studio; we can use + * __pragma(warning(disable:XXXX)). + */ + #define DIAG_OFF_BISON_BYACC \ + __pragma(warning(disable:4702)) + #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6) + /* + * This is GCC 4.6 or later, or a compiler claiming to be that. + * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2, + * but it may not actually work very well prior to 4.6). + */ + #define DIAG_OFF_BISON_BYACC \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wshadow") \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code") + #endif +#else + /* + * Bison. + * + * The generated code may have functions with unreachable code and + * switches with only a default case, so suppress warnings about those. + */ + #if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) + /* + * This is Clang 2.8 or later (including clang-cl, so test this + * before _MSC_VER); we can use "clang diagnostic ignored -Wxxx". + */ + #define DIAG_OFF_BISON_BYACC \ + PCAP_DO_PRAGMA(clang diagnostic ignored "-Wunreachable-code") + #elif defined(_MSC_VER) + /* + * This is Microsoft Visual Studio; we can use + * __pragma(warning(disable:XXXX)). + * + * Suppress some /Wall warnings. + */ + #define DIAG_OFF_BISON_BYACC \ + __pragma(warning(disable:4065)) \ + __pragma(warning(disable:4127)) \ + __pragma(warning(disable:4242)) \ + __pragma(warning(disable:4244)) \ + __pragma(warning(disable:4702)) + #elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,6) + /* + * This is GCC 4.6 or later, or a compiler claiming to be that. + * We can use "GCC diagnostic ignored -Wxxx" (introduced in 4.2, + * but it may not actually work very well prior to 4.6). + */ + #define DIAG_OFF_BISON_BYACC \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunreachable-code") + #elif PCAP_IS_AT_LEAST_SUNC_VERSION(5,5) + /* + * Same as for DIAG_OFF_FLEX above. + */ + #define DIAG_OFF_BISON_BYACC \ + PCAP_DO_PRAGMA(error_messages(off,E_STATEMENT_NOT_REACHED)) + #endif +#endif + +#if PCAP_IS_AT_LEAST_CLANG_VERSION(2,8) + /* + * Clang appears to let you ignore a result without a warning by + * casting the function result to void, so we don't appear to + * need this for Clang. + */ +#elif PCAP_IS_AT_LEAST_GNUC_VERSION(4,5) + /* + * GCC warns about unused return values if a function is marked as + * "warn about ignoring this function's return value". + */ + #define DIAG_OFF_WARN_UNUSED_RESULT \ + PCAP_DO_PRAGMA(GCC diagnostic push) \ + PCAP_DO_PRAGMA(GCC diagnostic ignored "-Wunused-result") + #define DIAG_ON_WARN_UNUSED_RESULT \ + PCAP_DO_PRAGMA(GCC diagnostic pop) + + /* + * GCC does not currently generate any -Wstrict-prototypes warnings that + * would need silencing as is done for Clang above. + */ +#endif + +/* + * GCC needs this on AIX for longjmp(). + */ +#if PCAP_IS_AT_LEAST_GNUC_VERSION(5,1) + /* + * Beware that the effect of this builtin is more than just squelching the + * warning! GCC trusts it enough for the process to segfault if the control + * flow reaches the builtin (an infinite empty loop in the same context would + * squelch the warning and ruin the process too, albeit in a different way). + * So please remember to use this very carefully. + */ + #define PCAP_UNREACHABLE __builtin_unreachable(); +#endif + +#ifndef DIAG_OFF_ENUM_SWITCH +#define DIAG_OFF_ENUM_SWITCH +#endif +#ifndef DIAG_ON_ENUM_SWITCH +#define DIAG_ON_ENUM_SWITCH +#endif +#ifndef DIAG_OFF_DEFAULT_ONLY_SWITCH +#define DIAG_OFF_DEFAULT_ONLY_SWITCH +#endif +#ifndef DIAG_ON_DEFAULT_ONLY_SWITCH +#define DIAG_ON_DEFAULT_ONLY_SWITCH +#endif +#ifndef DIAG_OFF_FLEX +#define DIAG_OFF_FLEX +#endif +#ifndef DIAG_ON_FLEX +#define DIAG_ON_FLEX +#endif +#ifndef DIAG_OFF_NARROWING +#define DIAG_OFF_NARROWING +#endif +#ifndef DIAG_ON_NARROWING +#define DIAG_ON_NARROWING +#endif +#ifndef DIAG_OFF_DEPRECATION +#define DIAG_OFF_DEPRECATION +#endif +#ifndef DIAG_ON_DEPRECATION +#define DIAG_ON_DEPRECATION +#endif +#ifndef DIAG_OFF_FORMAT_TRUNCATION +#define DIAG_OFF_FORMAT_TRUNCATION +#endif +#ifndef DIAG_ON_FORMAT_TRUNCATION +#define DIAG_ON_FORMAT_TRUNCATION +#endif +#ifndef DIAG_OFF_BISON_BYACC +#define DIAG_OFF_BISON_BYACC +#endif +// +// DIAG_ON_BISON_BYACC does not need to be defined. +// +#ifndef DIAG_OFF_WARN_UNUSED_RESULT +#define DIAG_OFF_WARN_UNUSED_RESULT +#endif +#ifndef DIAG_ON_WARN_UNUSED_RESULT +#define DIAG_ON_WARN_UNUSED_RESULT +#endif +#ifndef DIAG_OFF_STRICT_PROTOTYPES +#define DIAG_OFF_STRICT_PROTOTYPES +#endif +#ifndef DIAG_ON_STRICT_PROTOTYPES +#define DIAG_ON_STRICT_PROTOTYPES +#endif +#ifndef DIAG_OFF_DOCUMENTATION +#define DIAG_OFF_DOCUMENTATION +#endif +#ifndef DIAG_ON_DOCUMENTATION +#define DIAG_ON_DOCUMENTATION +#endif +#ifndef DIAG_OFF_SIGN_COMPARE +#define DIAG_OFF_SIGN_COMPARE +#endif +#ifndef DIAG_ON_SIGN_COMPARE +#define DIAG_ON_SIGN_COMPARE +#endif +#ifndef PCAP_UNREACHABLE +#define PCAP_UNREACHABLE +#endif + +#endif /* _diag_control_h */ diff --git a/src/libpcap-1.10.5/dlpisubs.c b/src/libpcap-1.10.5/dlpisubs.c new file mode 100644 index 0000000000..e1a64492d4 --- /dev/null +++ b/src/libpcap-1.10.5/dlpisubs.c @@ -0,0 +1,415 @@ +/* + * This code is derived from code formerly in pcap-dlpi.c, originally + * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College + * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), + * Mark Pizzolato , + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya . + */ + +/* + * This file contains dlpi/libdlpi related common functions used + * by pcap-[dlpi,libdlpi].c. + */ + +#include + +#ifndef DL_IPATM +#define DL_IPATM 0x12 /* ATM Classical IP interface */ +#endif + +#ifdef HAVE_SYS_BUFMOD_H + /* + * Size of a bufmod chunk to pass upstream; that appears to be the + * biggest value to which you can set it, and setting it to that value + * (which is bigger than what appears to be the Solaris default of 8192) + * reduces the number of packet drops. + */ +#define CHUNKSIZE 65536 + + /* + * Size of the buffer to allocate for packet data we read; it must be + * large enough to hold a chunk. + */ +#define PKTBUFSIZE CHUNKSIZE + +#else /* HAVE_SYS_BUFMOD_H */ + + /* + * Size of the buffer to allocate for packet data we read; this is + * what the value used to be - there's no particular reason why it + * should be tied to MAXDLBUF, but we'll leave it as this for now. + */ +#define MAXDLBUF 8192 +#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) + +#endif + +#include +#include +#ifdef HAVE_SYS_BUFMOD_H +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBDLPI +#include +#endif + +#include "pcap-int.h" +#include "dlpisubs.h" + +#ifdef HAVE_SYS_BUFMOD_H +static void pcap_stream_err(const char *, int, char *); +#endif + +/* + * Get the packet statistics. + */ +int +pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_dlpi *pd = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this would not include packets dropped because we ran out + * of buffer space; in order to make this more like other + * platforms (Linux 2.4 and later, BSDs with BPF), where the + * "packets received" count includes packets received but dropped + * due to running out of buffer space, and to keep from confusing + * applications that, for example, compute packet drop percentages, + * we also make it count packets dropped by "bufmod" (otherwise we + * might run the risk of the packet drop count being bigger than + * the received-packet count). + * + * "ps_drop" counts packets dropped by "bufmod" because of + * flow control requirements or resource exhaustion; it doesn't + * count packets dropped by the interface driver, or packets + * dropped upstream. As filtering is done in userland, it counts + * packets regardless of whether they would've passed the filter. + * + * These statistics don't include packets not yet read from + * the kernel by libpcap, but they may include packets not + * yet read from libpcap by the application. + */ + *ps = pd->stat; + + /* + * Add in the drop count, as per the above comment. + */ + ps->ps_recv += ps->ps_drop; + return (0); +} + +/* + * Does the processor for which we're compiling this support aligned loads? + */ +#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \ + (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \ + (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \ + (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \ + (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) + /* Yes, it does. */ +#else + /* No, it doesn't. */ + #define REQUIRE_ALIGNMENT +#endif + +/* + * Loop through the packets and call the callback for each packet. + * Return the number of packets read. + */ +int +pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, + int count, u_char *bufp, int len) +{ + struct pcap_dlpi *pd = p->priv; + int n, caplen, origlen; + u_char *ep, *pk; + struct pcap_pkthdr pkthdr; +#ifdef HAVE_SYS_BUFMOD_H + struct sb_hdr *sbp; +#ifdef REQUIRE_ALIGNMENT + struct sb_hdr sbhdr; +#endif +#endif + + /* + * Loop through packets. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ + ep = bufp + len; + n = 0; + +#ifdef HAVE_SYS_BUFMOD_H + while (bufp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bufp; + p->cc = ep - bufp; + return (n); + } + } +#ifdef REQUIRE_ALIGNMENT + if ((long)bufp & 3) { + sbp = &sbhdr; + memcpy(sbp, bufp, sizeof(*sbp)); + } else +#endif + sbp = (struct sb_hdr *)bufp; + pd->stat.ps_drop = sbp->sbh_drops; + pk = bufp + sizeof(*sbp); + bufp += sbp->sbh_totlen; + origlen = sbp->sbh_origlen; + caplen = sbp->sbh_msglen; +#else + origlen = len; + caplen = min(p->snapshot, len); + pk = bufp; + bufp += caplen; +#endif + ++pd->stat.ps_recv; + if (pcapint_filter(p->fcode.bf_insns, pk, origlen, caplen)) { +#ifdef HAVE_SYS_BUFMOD_H + pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; + pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; +#else + (void) gettimeofday(&pkthdr.ts, NULL); +#endif + pkthdr.len = origlen; + pkthdr.caplen = caplen; + /* Insure caplen does not exceed snapshot */ + if (pkthdr.caplen > (bpf_u_int32)p->snapshot) + pkthdr.caplen = (bpf_u_int32)p->snapshot; + (*callback)(user, &pkthdr, pk); + if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { + p->cc = ep - bufp; + p->bp = bufp; + return (n); + } + } +#ifdef HAVE_SYS_BUFMOD_H + } +#endif + p->cc = 0; + return (n); +} + +/* + * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. + */ +int +pcap_process_mactype(pcap_t *p, u_int mactype) +{ + int retv = 0; + + switch (mactype) { + + case DL_CSMACD: + case DL_ETHER: + p->linktype = DLT_EN10MB; + p->offset = 2; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + break; + + case DL_FDDI: + p->linktype = DLT_FDDI; + p->offset = 3; + break; + + case DL_TPR: + /* XXX - what about DL_TPB? Is that Token Bus? */ + p->linktype = DLT_IEEE802; + p->offset = 2; + break; + +#ifdef HAVE_SOLARIS + case DL_IPATM: + p->linktype = DLT_SUNATM; + p->offset = 0; /* works for LANE and LLC encapsulation */ + break; +#endif + +#ifdef DL_IPV4 + case DL_IPV4: + p->linktype = DLT_IPV4; + p->offset = 0; + break; +#endif + +#ifdef DL_IPV6 + case DL_IPV6: + p->linktype = DLT_IPV6; + p->offset = 0; + break; +#endif + +#ifdef DL_IPNET + case DL_IPNET: + /* + * XXX - DL_IPNET devices default to "raw IP" rather than + * "IPNET header"; see + * + * https://seclists.org/tcpdump/2009/q1/202 + * + * We'd have to do DL_IOC_IPNET_INFO to enable getting + * the IPNET header. + */ + p->linktype = DLT_RAW; + p->offset = 0; + break; +#endif + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x", + mactype); + retv = -1; + } + + return (retv); +} + +#ifdef HAVE_SYS_BUFMOD_H +/* + * Push and configure the buffer module. Returns -1 for error, otherwise 0. + */ +int +pcap_conf_bufmod(pcap_t *p, int snaplen) +{ + struct timeval to; + bpf_u_int32 ss, chunksize; + + /* Non-standard call to get the data nicely buffered. */ + if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { + pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); + return (-1); + } + + ss = snaplen; + if (ss > 0 && + strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { + pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); + return (-1); + } + + if (p->opt.immediate) { + /* Set the timeout to zero, for immediate delivery. */ + to.tv_sec = 0; + to.tv_usec = 0; + if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { + pcap_stream_err("SBIOCSTIME", errno, p->errbuf); + return (-1); + } + } else { + /* Set up the bufmod timeout. */ + if (p->opt.timeout != 0) { + to.tv_sec = p->opt.timeout / 1000; + to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { + pcap_stream_err("SBIOCSTIME", errno, p->errbuf); + return (-1); + } + } + + /* Set the chunk length. */ + chunksize = CHUNKSIZE; + if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) + != 0) { + pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); + return (-1); + } + } + + return (0); +} +#endif /* HAVE_SYS_BUFMOD_H */ + +/* + * Allocate data buffer. Returns -1 if memory allocation fails, else 0. + */ +int +pcap_alloc_databuf(pcap_t *p) +{ + p->bufsize = PKTBUFSIZE; + p->buffer = malloc(p->bufsize + p->offset); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + + return (0); +} + +/* + * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise + * length of returned data on success. + */ +int +strioctl(int fd, int cmd, int len, char *dp) +{ + struct strioctl str; + int retv; + + str.ic_cmd = cmd; + str.ic_timout = -1; + str.ic_len = len; + str.ic_dp = dp; + if ((retv = ioctl(fd, I_STR, &str)) < 0) + return (retv); + + return (str.ic_len); +} + +#ifdef HAVE_SYS_BUFMOD_H +/* + * Write stream error message to errbuf. + */ +static void +pcap_stream_err(const char *func, int err, char *errbuf) +{ + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, err, "%s", func); +} +#endif diff --git a/src/libpcap-1.10.5/dlpisubs.h b/src/libpcap-1.10.5/dlpisubs.h new file mode 100644 index 0000000000..cdc531c1f6 --- /dev/null +++ b/src/libpcap-1.10.5/dlpisubs.h @@ -0,0 +1,38 @@ +#ifndef dlpisubs_h +#define dlpisubs_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Private data for capturing on DLPI devices. + */ +struct pcap_dlpi { +#ifdef HAVE_LIBDLPI + dlpi_handle_t dlpi_hd; +#endif /* HAVE_LIBDLPI */ +#ifdef DL_HP_RAWDLS + int send_fd; +#endif /* DL_HP_RAWDLS */ + + struct pcap_stat stat; +}; + +/* + * Functions defined by dlpisubs.c. + */ +int pcap_stats_dlpi(pcap_t *, struct pcap_stat *); +int pcap_process_pkts(pcap_t *, pcap_handler, u_char *, int, u_char *, int); +int pcap_process_mactype(pcap_t *, u_int); +#ifdef HAVE_SYS_BUFMOD_H +int pcap_conf_bufmod(pcap_t *, int); +#endif +int pcap_alloc_databuf(pcap_t *); +int strioctl(int, int, int, char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpcap-1.10.5/doc/README.aix b/src/libpcap-1.10.5/doc/README.aix new file mode 100644 index 0000000000..868999476a --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.aix @@ -0,0 +1,110 @@ +# Compiling libpcap on AIX + +* Autoconf is expected to work everywhere. +* Neither AIX lex nor AIX yacc nor AIX m4 are suitable. + +## AIX 7.1 + +* libpcap build fails with rpcapd enabled. +* GNU M4 1.4.17 works. +* flex 2.6.4 and GNU Bison 3.5.1 work. +* CMake 3.16.0 works. +* GCC 8.3.0 works, XL C 12.1.0 works. + +## AIX 7.2 + +* libpcap build fails with rpcapd enabled. +* GNU M4 1.4.17 works. +* flex 2.5.35 and GNU Bison 3.0.4 work. +* GCC 7.2.0 works, XL C 13.1.3 works. + +## Other AIX-related information + +Using BPF: + +(1) AIX 4.x's version of BPF is undocumented and somewhat unstandard; the + current BPF support code includes changes that should work around + that; it appears to compile and work on at least one AIX 4.3.3 + machine. + + Note that the BPF driver and the "/dev/bpf" devices might not exist + on your machine; AIX's tcpdump loads the driver and creates the + devices if they don't already exist. Our libpcap should do the + same, and the configure script should detect that it's on an AIX + system and choose BPF even if the devices aren't there. + + Also note that tcpdump _binary_ compiled on AIX 4 may have a problem + doing the initial loading of the BPF driver if copied to AIX 5 and + run there (GH #52). tcpdump binary natively compiled on AIX 5 should + not have this issue. + +(2) If libpcap doesn't compile on your machine when configured to use + BPF, or if the workarounds fail to make it work correctly, you + should send to tcpdump-workers@lists.tcpdump.org a detailed bug + report (if the compile fails, send us the compile error messages; + if it compiles but fails to work correctly, send us as detailed as + possible a description of the symptoms, including indications of the + network link-layer type being wrong or time stamps being wrong). + + If you fix the problems yourself, please submit a patch by forking + the branch at + + https://github.com/the-tcpdump-group/libpcap/tree/master + + and issuing a pull request, so we can incorporate the fixes into the + next release. + + If you don't fix the problems yourself, you can, as a workaround, + make libpcap use DLPI instead of BPF. + + This can be done by specifying the flag: + + --with-pcap=dlpi + + to the "configure" script for libpcap. + +If you use DLPI: + +(1) It is a good idea to have the latest version of the DLPI driver on + your system, since certain versions may be buggy and cause your AIX + system to crash. DLPI is included in the fileset bos.rte.tty. I + found that the DLPI driver that came with AIX 4.3.2 was buggy, and + had to upgrade to bos.rte.tty 4.3.2.4: + + lslpp -l bos.rte.tty + + bos.rte.tty 4.3.2.4 COMMITTED Base TTY Support and Commands + + Updates for AIX filesets can be obtained from: + ftp://service.software.ibm.com/aix/fixes/ + + These updates can be installed with the smit program. + +(2) After compiling libpcap, you need to make sure that the DLPI driver + is loaded. Type: + + strload -q -d dlpi + + If the result is: + + dlpi: yes + + then the DLPI driver is loaded correctly. + + If it is: + + dlpi: no + + Then you need to type: + + strload -f /etc/dlpi.conf + + Check again with strload -q -d dlpi that the dlpi driver is loaded. + + Alternatively, you can uncomment the lines for DLPI in + /etc/pse.conf and reboot the machine; this way DLPI will always + be loaded when you boot your system. + +(3) There appears to be a problem in the DLPI code in some versions of + AIX, causing a warning about DL_PROMISC_MULTI failing; this might + be responsible for DLPI not being able to capture outgoing packets. diff --git a/src/libpcap-1.10.5/doc/README.dag b/src/libpcap-1.10.5/doc/README.dag new file mode 100644 index 0000000000..fd2c4b741b --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.dag @@ -0,0 +1,122 @@ + +The following instructions apply if you have a Linux or FreeBSD platform and +want libpcap to support the DAG range of passive network monitoring cards from +Endace (https://www.endace.com, see below for further contact details). + +1) Install and build the DAG software distribution by following the +instructions supplied with that package. Current Endace customers can download +the DAG software distribution from https://www.endace.com + +2) Configure libcap. To allow the 'configure' script to locate the DAG +software distribution use the '--with-dag' option: + + ./configure --with-dag=DIR + +Where DIR is the root of the DAG software distribution, for example +/var/src/dag. If the DAG software is correctly detected 'configure' will +report: + + checking whether we have DAG API... yes + +If 'configure' reports that there is no DAG API, the directory may have been +incorrectly specified or the DAG software was not built before configuring +libpcap. + +See also the libpcap INSTALL.md file for further libpcap configuration +options. + +Building libpcap at this stage will include support for both the native packet +capture stream (linux or bpf) and for capturing from DAG cards. To build +libpcap with only DAG support specify the capture type as 'dag' when +configuring libpcap: + + ./configure --with-dag=DIR --with-pcap=dag + +Applications built with libpcap configured in this way will only detect DAG +cards and will not capture from the native OS packet stream. + +---------------------------------------------------------------------- + +Libpcap when built for DAG cards against dag-2.5.1 or later releases: + +Timeouts are supported. pcap_dispatch() will return after to_ms milliseconds +regardless of how many packets are received. If to_ms is zero pcap_dispatch() +will block waiting for data indefinitely. + +pcap_dispatch() will block on and process a minimum of 64kB of data (before +filtering) for efficiency. This can introduce high latencies on quiet +interfaces unless a timeout value is set. The timeout expiring will override +the 64kB minimum causing pcap_dispatch() to process any available data and +return. + +pcap_setnonblock is supported. When nonblock is set, pcap_dispatch() will +check once for available data, process any data available up to count, then +return immediately. + +pcap_findalldevs() is supported, e.g. dag0, dag1... + +Some DAG cards can provide more than one 'stream' of received data. +This can be data from different physical ports, or separated by filtering +or load balancing mechanisms. Receive streams have even numbers, e.g. +dag0:0, dag0:2 etc. Specifying transmit streams for capture is not supported. + +pcap_setfilter() is supported, BPF programs run in userspace. + +pcap_setdirection() is not supported. Only received traffic is captured. +DAG cards normally do not have IP or link layer addresses assigned as +they are used to passively monitor links. + +pcap_breakloop() is supported. + +pcap_datalink() and pcap_list_datalinks() are supported. The DAG card does +not attempt to set the correct datalink type automatically where more than +one type is possible. + +pcap_stats() is supported. ps_drop is the number of packets dropped due to +RX stream buffer overflow, this count is before filters are applied (it will +include packets that would have been dropped by the filter). The RX stream +buffer size is user configurable outside libpcap, typically 16-512MB. + +pcap_get_selectable_fd() is not supported, as DAG cards do not support +poll/select methods. + +pcap_inject() and pcap_sendpacket() are not supported. + +Some DAG cards now support capturing to multiple virtual interfaces, called +streams. Capture streams have even numbers. These are available via libpcap +as separate interfaces, e.g. dag0:0, dag0:2, dag0:4 etc. dag0:0 is the same +as dag0. These are visible via pcap_findalldevs(). + +libpcap now does NOT set the card's hardware snaplen (slen). This must now be +set using the appropriate DAG configuration program, e.g. dagthree, dagfour, +dagsix, dagconfig. This is because the snaplen is currently shared between +all of the streams. In future this may change if per-stream slen is +implemented. + +DAG cards by default capture entire packets including the L2 +CRC/FCS. If the card is not configured to discard the CRC/FCS, this +can confuse applications that use libpcap if they're not prepared for +packets to have an FCS. + +Libpcap now reads the environment variable ERF_FCS_BITS to determine +how many bits of CRC/FCS to strip from the end of the captured +frame. This defaults to 32 for use with Ethernet. If the card is +configured to strip the CRC/FCS, then set ERF_FCS_BITS=0. If used with +a HDLC/PoS/PPP/Frame Relay link with 16 bit CRC/FCS, then set +ERF_FCS_BITS=16. + +If you wish to create a pcap file that DOES contain the Ethernet FCS, +specify the environment variable ERF_DONT_STRIP_FCS. This will cause +the existing FCS to be captured into the pcap file. Note some +applications may incorrectly report capture errors or oversize packets +when reading these files. + +---------------------------------------------------------------------- + +Please submit bug reports via . + +Please also visit our Web site at: + + https://www.endace.com/ + +For more information about Endace DAG cards contact . diff --git a/src/libpcap-1.10.5/doc/README.haiku.md b/src/libpcap-1.10.5/doc/README.haiku.md new file mode 100644 index 0000000000..b9b062bdf5 --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.haiku.md @@ -0,0 +1,57 @@ +# Compiling and using libpcap on Haiku + +Haiku R1/beta4 and earlier versions do not support packet capture on the +loopback interface. Using this version of libpcap, loopback capture works +since Haiku revision hrev57585 and is expected to work in Haiku R1/beta5 when +the latter becomes available. Packet timestamping and filtering always occur +in userland. Wireless monitor mode is not supported. The "any" +pseudo-interface is not supported. +[**pcap_set_buffer_size**](https://www.tcpdump.org/manpages/pcap_set_buffer_size.3pcap.html)(3PCAP) +has no effect. +[**pcap_setdirection**](https://www.tcpdump.org/manpages/pcap_setdirection.3pcap.html)(3PCAP) +is not supported. +[**pcap_inject**](https://www.tcpdump.org/manpages/pcap_inject.3pcap.html)(3PCAP) +is not supported. + +The statistics reported by +[**pcap_stats**](https://www.tcpdump.org/manpages/pcap_stats.3pcap.html)(3PCAP) +on Haiku are as follows: +* `ps_recv` is the number of packets successfully delivered by the kernel, + before libpcap applies a filter. +* `ps_drop` is the number of packets rejected by the filter. +* `ps_ifdrop` is the number of packets dropped by the network interface (as + seen via `SIOCGIFSTATS`) since the capture handle became active. + +## 64-bit x86 R1/beta4 + +* Autoconf 2.71 works. +* CMake 3.28.3 works. +* GCC 13.2.0 works. +* Clang 12.0.1 works with the latest llvm12_clang-12.0.1-5 version. +* flex 2.6.4 works. +* bison 3.8.2 works. + +The following command will install respective non-default packages: +``` +pkgman install cmake llvm12_clang +``` + +For reference, the tests were done using a system installed from +`haiku-r1beta4-x86_64-anyboot.iso`. + +## 32-bit x86 R1/beta4 + +* Autoconf 2.71 works. +* CMake 3.24.2 works. +* GCC 11.2.0 works. +* Clang does not work. +* flex 2.6.4 works. +* bison 3.0.5 works. + +The following command will install respective non-default packages: +``` +pkgman install cmake_x86 +``` + +For reference, the tests were done using a system installed from +`haiku-r1beta4-x86_gcc2h-anyboot.iso`. diff --git a/src/libpcap-1.10.5/doc/README.hpux b/src/libpcap-1.10.5/doc/README.hpux new file mode 100644 index 0000000000..bf291f7aec --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.hpux @@ -0,0 +1,254 @@ +For HP-UX 11i (11.11) and later, there are no known issues with +promiscuous mode under HP-UX. If you are using a earlier version of +HP-UX and cannot upgrade, please continue reading. + +HP-UX patches to fix packet capture problems + +Note that packet-capture programs such as tcpdump may, on HP-UX, not be +able to see packets sent from the machine on which they're running. +Some articles on groups.google.com discussing this are: + + https://groups.google.com/groups?selm=82ld3v%2480i%241%40mamenchi.zrz.TU-Berlin.DE + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: Did someone made tcpdump working on 10.20 ? + Date: 12/08/1999 + From: Lutz Jaenicke + + In article <82ks5i$5vc$1@news1.dti.ne.jp>, mtsat + wrote: + >Hello, + > + >I downloaded and compiled tcpdump3.4 a couple of week ago. I tried to use + >it, but I can only see incoming data, never outgoing. + >Someone (raj) explained me that a patch was missing, and that this patch + >must me "patched" (poked) in order to see outbound data in promiscuous mode. + >Many things to do .... So the question is : did someone has already this + >"ready to use" PHNE_**** patch ? + + Two things: + 1. You do need a late "LAN products cumulative patch" (e.g. PHNE_18173 + for s700/10.20). + 2. You must use +echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem + You can insert this e.g. into /sbin/init.d/lan + + Best regards, + Lutz + +and + + http://groups.google.com/groups?selm=88cf4t%24p03%241%40web1.cup.hp.com + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump only shows incoming packets + Date: 02/15/2000 + From: Rick Jones + + Harald Skotnes wrote: + > I am running HPUX 11.0 on a C200 hanging on a 100Mb switch. I have + > compiled libpcap-0.4 an tcpdump-3.4 and it seems to work. But at a + > closer look I only get to see the incoming packets not the + > outgoing. I have tried tcpflow-0.12 which also uses libpcap and the + > same thing happens. Could someone please give me a hint on how to + > get this right? + + Search/Read the archives ?-) + + What you are seeing is expected, un-patched, behaviour for an HP-UX + system. On 11.00, you need to install the latest lancommon/DLPI + patches, and then the latest driver patch for the interface(s) in use. + At that point, a miracle happens and you should start seeing outbound + traffic. + +[That article also mentions the patch that appears below.] + +and + + https://groups.google.com/groups?selm=38AA973E.96BE7DF7%40cc.uit.no + +which says: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump only shows incoming packets + Date: 02/16/2000 + From: Harald Skotnes + + Rick Jones wrote: + + ... + + > What you are seeing is expected, un-patched, behaviour for an HP-UX + > system. On 11.00, you need to install the latest lancommon/DLPI + > patches, and then the latest driver patch for the interface(s) in + > use. At that point, a miracle happens and you should start seeing + > outbound traffic. + + Thanks a lot. I have this problem on several machines running HPUX + 10.20 and 11.00. The machines where patched up before y2k so did not + know what to think. Anyway I have now installed PHNE_19766, + PHNE_19826, PHNE_20008, PHNE_20735 on the C200 and now I can see the + outbound traffic too. Thanks again. + +(although those patches may not be the ones to install - there may be +later patches). + +And another message to tcpdump-workers@tcpdump.org, from Rick Jones: + + Date: Mon, 29 Apr 2002 15:59:55 -0700 + From: Rick Jones + To: tcpdump-workers@tcpdump.org + Subject: Re: [tcpdump-workers] I Can't Capture the Outbound Traffic + + ... + + http://itrc.hp.com/ would be one place to start in a search for the most + up-to-date patches for DLPI and the lan driver(s) used on your system (I + cannot guess because 9000/800 is too generic - one hs to use the "model" + command these days and/or an ioscan command (see manpage) to guess what + the drivers (btlan[3456], gelan, etc) might be involved in addition to + DLPI. + + Another option is to upgrade to 11i as outbound promiscuous mode support + is there in the base OS, no patches required. + +Another posting: + + https://groups.google.com/groups?selm=7d6gvn%24b3%241%40ocean.cup.hp.com + +indicates that you need to install the optional STREAMS product to do +captures on HP-UX 9.x: + + Newsgroups: comp.sys.hp.hpux + Subject: Re: tcpdump HP/UX 9.x + Date: 03/22/1999 + From: Rick Jones + + Dave Barr (barr@cis.ohio-state.edu) wrote: + : Has anyone ported tcpdump (or something similar) to HP/UX 9.x? + + I'm reasonably confident that any port of tcpdump to 9.X would require + the (then optional) STREAMS product. This would bring DLPI, which is + what one uses to access interfaces in promiscuous mode. + + I'm not sure that HP even sells the 9.X STREAMS product any longer, + since HP-UX 9.X is off the pricelist (well, maybe 9.10 for the old 68K + devices). + + Your best bet is to be up on 10.20 or better if that is at all + possible. If your hardware is supported by it, I'd go with HP-UX 11. + If you want to see the system's own outbound traffic, you'll never get + that functionality on 9.X, but it might happen at some point for 10.20 + and 11.X. + + rick jones + +(as per other messages cited here, the ability to see the system's own +outbound traffic did happen). + +Rick Jones reports that HP-UX 11i needs no patches for outbound +promiscuous mode support. + +An additional note, from Jost Martin, for HP-UX 10.20: + + Q: How do I get [Wireshark] on HPUX to capture the _outgoing_ packets + of an interface + A: You need to get PHNE_20892,PHNE_20725 and PHCO_10947 (or + newer, this is as of 4.4.00) and its dependencies. Then you can + enable the feature as described below: + + Patch Name: PHNE_20892 + Patch Description: s700 10.20 PCI 100Base-T cumulative patch + To trace the outbound packets, please do the following + to turn on a global promiscuous switch before running + the promiscuous applications like snoop or tcpdump: + + adb -w /stand/vmunix /dev/mem + lanc_outbound_promisc_flag/W 1 + (adb will echo the result showing that the flag has + been changed) + $quit + (Thanks for this part to HP-support, Ratingen) + + The attached hack does this and some security-related stuff + (thanks to hildeb@www.stahl.bau.tu-bs.de (Ralf Hildebrandt) who + posted the security-part some time ago) + + <> + + (Don't switch IP-forwarding off, if you need it !) + Install the hack as /sbin/init.d/hacl_ip_stack (adjust + permissions !) and make a sequencing-symlink + /sbin/rc2.d/S350hack_ip_stack pointing to this script. + Now all this is done on every reboot. + +According to Rick Jones, the global promiscuous switch also has to be +turned on for HP-UX 11.00, but not for 11i - and, in fact, the switch +doesn't even exist on 11i. + +Here's the "hack_ip_stack" script: + +-----------------------------------Cut Here------------------------------------- +#!/sbin/sh +# +# nettune: hack kernel params for safety + +OKAY=0 +ERROR=-1 + +# /usr/contrib/bin fuer nettune auf Pfad +PATH=/sbin:/usr/sbin:/usr/bin:/usr/contrib/bin +export PATH + + +########## +# main # +########## + +case $1 in + start_msg) + print "Tune IP-Stack for security" + exit $OKAY + ;; + + stop_msg) + print "This action is not applicable" + exit $OKAY + ;; + + stop) + exit $OKAY + ;; + + start) + ;; # fall through + + *) + print "USAGE: $0 {start_msg | stop_msg | start | stop}" >&2 + exit $ERROR + ;; + esac + +########### +# start # +########### + +# +# tcp-Sequence-Numbers nicht mehr inkrementieren sondern random +# Syn-Flood-Protection an +# ip_forwarding aus +# Source-Routing aus +# Ausgehende Packets an ethereal/tcpdump etc. + +/usr/contrib/bin/nettune -s tcp_random_seq 2 || exit $ERROR +/usr/contrib/bin/nettune -s hp_syn_protect 1 || exit $ERROR +/usr/contrib/bin/nettune -s ip_forwarding 0 || exit $ERROR +echo 'ip_block_source_routed/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem || exit $ERROR +echo 'lanc_outbound_promisc_flag/W 1' | adb -w /stand/vmunix /dev/mem || exit $ERROR + +exit $OKAY +-----------------------------------Cut Here------------------------------------- diff --git a/src/libpcap-1.10.5/doc/README.linux b/src/libpcap-1.10.5/doc/README.linux new file mode 100644 index 0000000000..eba43aeb16 --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.linux @@ -0,0 +1,36 @@ +Currently, libpcap supports packet capturing on Linux 2.6.27 and later; +earlier versions are not supported. + +You must configure 2.6.x kernels with the CONFIG_PACKET_MMAP option for +this protocol. 3.x and later kernels do not require that. + +Note that, by default, libpcap will, if libnl is present, build with it; +it uses libnl to support monitor mode on mac80211 devices. There is a +configuration option to disable building with libnl, but, if that option +is chosen, the monitor-mode APIs (as used by tcpdump's "-I" flag, and as +will probably be used by other applications in the future) won't work +properly on mac80211 devices. + +Linux's run-time linker allows shared libraries to be linked with other +shared libraries, which means that if an older version of a shared +library doesn't require routines from some other shared library, and a +later version of the shared library does require those routines, the +later version of the shared library can be linked with that other shared +library and, if it's otherwise binary-compatible with the older version, +can replace that older version without breaking applications built with +the older version, and without breaking configure scripts or the build +procedure for applications whose configure script doesn't use the +pcap-config script if they build with the shared library. (The build +procedure for applications whose configure scripts use the pcap-config +script if present will not break even if they build with the static +library.) + +Statistics: +Statistics reported by pcap are platform specific. The statistics +reported by pcap_stats on Linux are as follows: + +ps_recv Number of packets that were accepted by the pcap filter +ps_drop Number of packets that had passed filtering but were not + passed on to pcap due to things like buffer shortage, etc. + This is useful because these are packets you are interested in + but won't be reported by, for example, tcpdump output. diff --git a/src/libpcap-1.10.5/doc/README.macos b/src/libpcap-1.10.5/doc/README.macos new file mode 100644 index 0000000000..3cceb23329 --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.macos @@ -0,0 +1,74 @@ +As with other systems using BPF, macOS allows users with read access to +the BPF devices to capture packets with libpcap and allows users with +write access to the BPF devices to send packets with libpcap. + +On some systems that use BPF, the BPF devices live on the root file +system, and the permissions and/or ownership on those devices can be +changed to give users other than root permission to read or write those +devices. + +On newer versions of FreeBSD, the BPF devices live on devfs, and devfs +can be configured to set the permissions and/or ownership of those +devices to give users other than root permission to read or write those +devices. + +On macOS, the BPF devices live on devfs, but the macOS version of devfs +is based on an older (non-default) FreeBSD devfs, and that version of +devfs cannot be configured to set the permissions and/or ownership of +those devices. + +Therefore, we supply: + + a "startup item" for older versions of macOS; + + a launchd daemon for Tiger and later versions of macOS; + +Both of them will change the ownership of the BPF devices so that the +"admin" group owns them, and will change the permission of the BPF +devices to rw-rw----, so that all users in the "admin" group - i.e., all +users with "Allow user to administer this computer" turned on - have +both read and write access to them. + +The startup item is in the ChmodBPF directory in the source tree. A +/Library/StartupItems directory should be created if it doesn't already +exist, and the ChmodBPF directory should be copied to the +/Library/StartupItems directory (copy the entire directory, so that +there's a /Library/StartupItems/ChmodBPF directory, containing all the +files in the source tree's ChmodBPF directory; don't copy the individual +items in that directory to /Library/StartupItems). The ChmodBPF +directory, and all files under it, must be owned by root. Installing +the files won't immediately cause the startup item to be executed; it +will be executed on the next reboot. To change the permissions before +the reboot, run + + sudo SystemStarter start ChmodBPF + +The launchd daemon is the chmod_bpf script, plus the +org.tcpdump.chmod_bpf.plist launchd plist file. chmod_bpf should be +installed in /usr/local/bin/chmod_bpf, and org.tcpdump.chmod_bpf.plist +should be installed in /Library/LaunchDaemons. chmod_bpf, and +org.tcpdump.chmod_bpf.plist, must be owned by root. Installing the +script and plist file won't immediately cause the script to be executed; +it will be executed on the next reboot. To change the permissions +before the reboot, run + + sudo /usr/local/bin/chmod_bpf + +or + + sudo launchctl load /Library/LaunchDaemons/org.tcpdump.chmod_bpf.plist + +If you want to give a particular user permission to access the BPF +devices, rather than giving all administrative users permission to +access them, you can have the ChmodBPF/ChmodBPF script change the +ownership of /dev/bpf* without changing the permissions. If you want to +give a particular user permission to read and write the BPF devices and +give the administrative users permission to read but not write the BPF +devices, you can have the script change the owner to that user, the +group to "admin", and the permissions to rw-r-----. Other possibilities +are left as an exercise for the reader. + +(NOTE: due to a bug in Snow Leopard, if you change the permissions not +to grant write permission to everybody who should be allowed to capture +traffic, non-root users who cannot open the BPF devices for writing will +not be able to capture outgoing packets.) diff --git a/src/libpcap-1.10.5/doc/README.septel b/src/libpcap-1.10.5/doc/README.septel new file mode 100644 index 0000000000..d7fb5c7c61 --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.septel @@ -0,0 +1,50 @@ +The following instructions apply if you have a Linux platform and want +libpcap to support the Septel range of passive network monitoring cards +from Intel (https://www.intel.com) + +1) Install and build the Septel software distribution by following the +instructions supplied with that package. + +2) Configure libcap. To allow the 'configure' script to locate the Septel +software distribution use the '--with-septel' option: + + ./configure --with-septel=DIR + +where DIR is the root of the Septel software distribution, for example +/var/src/septel. + +By default (if you write only ./configure --with-septel) it takes +./../septel as argument for DIR. + +If the Septel software is correctly detected 'configure' will +report: + + checking whether we have Septel API... yes + +If 'configure' reports that there is no Septel API, the directory may have been +incorrectly specified or the Septel software was not built before configuring +libpcap. + +See also the libpcap INSTALL.md file for further libpcap configuration +options. + +Building libpcap at this stage will include support for both the native +packet capture stream and for capturing from Septel cards. To build +libpcap with only Septel support specify the capture type as 'septel' +when configuring libpcap: + + ./configure --with-septel=DIR --with-pcap=septel + +Applications built with libpcap configured in this way will only detect Septel +cards and will not capture from the native OS packet stream. + +Note: As mentioned in pcap-septel.c we should first edit the system.txt +file to change the user part example (UPE) module id to 0xdd instead of +0x2d for technical reason. So this change in system.txt is crucial and +things will go wrong if it's not done. System.txt along with config.txt +are configuration files that are edited by the user before running the +gctload program that uses these files for initialising modules and +configuring parameters. + +---------------------------------------------------------------------- +for more information please contact me : gil_hoyek@hotmail.com diff --git a/src/libpcap-1.10.5/doc/README.sita b/src/libpcap-1.10.5/doc/README.sita new file mode 100644 index 0000000000..c85e0d8cea --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.sita @@ -0,0 +1,71 @@ +NOTE: this is not currently supported; the configure script doesn't +support --with-sita, and CMake doesn't support enabling SITA ACN +support. The code currently does not compile; it should really be +implemented as an additional remote capture mechanism, using a URL, +rather than as a separate version of libpcap that supports only the ACN +product, but the infrastructure for that isn't yet available. + +The following instructions apply if you have a Linux platform and want +libpcap to support the 'ACN' WAN/LAN router product from SITA +(https://www.sita.aero) + +This might also work on non-Linux Unix-compatible platforms, but that +has not been tested. + +See also the libpcap INSTALL.md file for further libpcap configuration +options. + +These additions/extensions have been made to PCAP to allow it to +capture packets from a SITA ACN device (and potentially others). + +To enable its support you need to ensure that the distribution has +a correct configure.ac file; that can be created if necessary by +using the normal autoconf procedure of: + +aclocal +autoconf +autoheader +automake + +Then run configure with the 'sita' option: + +./configure --with-sita + +Applications built with libpcap configured in this way will only detect SITA +ACN interfaces and will not capture from the native OS packet stream. + +The SITA extension provides a remote datascope operation for capturing +both WAN and LAN protocols. It effectively splits the operation of +PCAP into two halves. The top layer performs the majority of the +work, but interfaces via a TCP session to remote agents that +provide the lower layer functionality of actual sniffing and +filtering. More detailed information regarding the functions and +inter-device protocol and naming conventions are described in detail +in 'pcap-sita.html'. + +pcap_findalldevs() reads the local system's /etc/hosts file looking +for host names that match the format of IOP type devices. ie. aaa_I_x_y +and then queries each associated IP address for a list of its WAN and +LAN devices. The local system the aggregates the lists obtained from +each IOP, sorts it, and provides it (to Wireshark et.al) as the +list of monitorable interfaces. + +Once a valid interface has been selected, pcap_open() is called +which opens a TCP session (to a well known port) on the target IOP +and tells it to start monitoring. + +All captured packets are then forwarded across that TCP session +back to the local 'top layer' for forwarding to the actual +sniffing program (wireshark...) + +Note that the DLT_SITA link-layer type includes a proprietary header +that is documented as part of the SITA dissector of Wireshark and is +also described in 'pcap-sita.html' for posterity sake. + +That header provides: +- Packet direction (in/out) (1 octet) +- Link layer hardware signal status (1 octet) +- Transmit/Receive error status (2 octets) +- Encapsulated WAN protocol ID (1 octet) + + diff --git a/src/libpcap-1.10.5/doc/README.solaris.md b/src/libpcap-1.10.5/doc/README.solaris.md new file mode 100644 index 0000000000..06ba789dfc --- /dev/null +++ b/src/libpcap-1.10.5/doc/README.solaris.md @@ -0,0 +1,58 @@ +# Compiling libpcap on Solaris and related OSes + +* Autoconf works everywhere. +* Neither Solaris lex nor Solaris yacc are suitable. +* Neither illumos lex nor illumos yacc are suitable. +* Solaris m4 and illumos m4 are suitable. + +## OmniOS r151042/AMD64 + +* flex 2.6.4 and GNU Bison 3.8.2 work. +* CMake 3.23.1 works. +* GCC 11.2.0 and Clang 14.0.3 work. + +## OpenIndiana 2021.04/AMD64 + +* flex 2.6.4 and GNU Bison 3.7.6 work. +* CMake 3.21.1 works. +* GCC 7.5.0 and GCC 10.3.0 work, Clang 9.0.1 works. + +For reference, the tests were done using a system installed from +`OI-hipster-text-20210430.iso` plus the following packages: +```shell +xargs -L1 pkg install < Folder. +Visual Studio will run CMake; however, you will need to indicate where +the Npcap or WinPcap SDK is installed. + +To do this, go to Project > "Change CMake Settings" > pcap and: + +Choose which configuration type to build, if you don't want the default +Debug build. + +In the CMakeSettings.json tab, change cmakeCommandArgs to include + + -DPacket_ROOT={path-to-sdk} + +where {path-to-sdk} is the path of the directory containing the Npcap or +WinPcap SDK. Note that backslashes in the path must be specified as two +backslashes. + +Save the configuration changes with File > "Save CMakeSettings.json" or +with control-S. + +Visual Studio will then re-run CMake. If that completes without errors, +you can build with CMake > "Build All". + +### Visual Studio 2019 ### + +Open the folder containing the libpcap source with Open > Folder. +Visual Studio will run CMake; however, you will need to indicate where +the Npcap or WinPcap SDK is installed. + +To do this, go to Project > "CMake Settings for pcap" and: + +Choose which configuration type to build, if you don't want the default +Debug build. + +Scroll down to "Cmake variables and cache", scroll through the list +looking for the entry for Packet_ROOT, and either type in the path of +the directory containing the Npcap or WinPcap SDK or use the "Browse..." +button to browse for that directory. + +Save the configuration changes with File > "Save CMakeSettings.json" or +with control-S. + +Visual Studio will then re-run CMake. If that completes without errors, +you can build with Build > "Build All". + +Building from the command line +------------------------------ + +Start the appropriate Native Tools command line prompt. + +Change to the directory into which you want to build libpcap, possibly +after creating it first. One choice is to create it as a subdirectory +of the libpcap source directory. + +Run the command + + cmake "-DPacket_ROOT={path-to-sdk}" {path-to-libpcap-source} + +where {path-to-sdk} is the path of the directory containing the Npcap or +WinPcap SDK and {path-to-libpcap-source} is the pathname of the +top-level source directory for libpcap. + +Run the command + + msbuild/m pcap.sln + +to compile libpcap. diff --git a/src/libpcap-1.10.5/etherent.c b/src/libpcap-1.10.5/etherent.c new file mode 100644 index 0000000000..fd228b81f6 --- /dev/null +++ b/src/libpcap-1.10.5/etherent.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include + +#include +#include +#include + +#include "pcap-int.h" + +#include + +#include "thread-local.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +static inline int skip_space(FILE *); +static inline int skip_line(FILE *); + +/* Hex digit to integer. */ +static inline u_char +xdtoi(u_char c) +{ + if (c >= '0' && c <= '9') + return (u_char)(c - '0'); + else if (c >= 'a' && c <= 'f') + return (u_char)(c - 'a' + 10); + else + return (u_char)(c - 'A' + 10); +} + +/* + * Skip linear white space (space and tab) and any CRs before LF. + * Stop when we hit a non-white-space character or an end-of-line LF. + */ +static inline int +skip_space(FILE *f) +{ + int c; + + do { + c = getc(f); + } while (c == ' ' || c == '\t' || c == '\r'); + + return c; +} + +static inline int +skip_line(FILE *f) +{ + int c; + + do + c = getc(f); + while (c != '\n' && c != EOF); + + return c; +} + +struct pcap_etherent * +pcap_next_etherent(FILE *fp) +{ + register int c, i; + u_char d; + char *bp; + size_t namesize; + static thread_local struct pcap_etherent e; + + memset((char *)&e, 0, sizeof(e)); + for (;;) { + /* Find addr */ + c = skip_space(fp); + if (c == EOF) + return (NULL); + if (c == '\n') + continue; + + /* If this is a comment, or first thing on line + cannot be Ethernet address, skip the line. */ + if (!PCAP_ISXDIGIT(c)) { + c = skip_line(fp); + if (c == EOF) + return (NULL); + continue; + } + + /* must be the start of an address */ + for (i = 0; i < 6; i += 1) { + d = xdtoi((u_char)c); + c = getc(fp); + if (c == EOF) + return (NULL); + if (PCAP_ISXDIGIT(c)) { + d <<= 4; + d |= xdtoi((u_char)c); + c = getc(fp); + if (c == EOF) + return (NULL); + } + e.addr[i] = d; + if (c != ':') + break; + c = getc(fp); + if (c == EOF) + return (NULL); + } + + /* Must be whitespace */ + if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { + c = skip_line(fp); + if (c == EOF) + return (NULL); + continue; + } + c = skip_space(fp); + if (c == EOF) + return (NULL); + + /* hit end of line... */ + if (c == '\n') + continue; + + if (c == '#') { + c = skip_line(fp); + if (c == EOF) + return (NULL); + continue; + } + + /* pick up name */ + bp = e.name; + /* Use 'namesize' to prevent buffer overflow. */ + namesize = sizeof(e.name) - 1; + do { + *bp++ = (u_char)c; + c = getc(fp); + if (c == EOF) + return (NULL); + } while (c != ' ' && c != '\t' && c != '\r' && c != '\n' + && --namesize != 0); + *bp = '\0'; + + /* Eat trailing junk */ + if (c != '\n') + (void)skip_line(fp); + + return &e; + } +} diff --git a/src/libpcap-1.10.5/ethertype.h b/src/libpcap-1.10.5/ethertype.h new file mode 100644 index 0000000000..e34e07b98d --- /dev/null +++ b/src/libpcap-1.10.5/ethertype.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Ethernet types. + * + * We wrap the declarations with #ifdef, so that if a file includes + * , which may declare some of these, we don't + * get a bunch of complaints from the C compiler about redefinitions + * of these values. + * + * We declare all of them here so that no file has to include + * if all it needs are ETHERTYPE_ values. + */ + +#ifndef ETHERTYPE_PUP +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_NS +#define ETHERTYPE_NS 0x0600 +#endif +#ifndef ETHERTYPE_SPRITE +#define ETHERTYPE_SPRITE 0x0500 +#endif +#ifndef ETHERTYPE_TRAIL +#define ETHERTYPE_TRAIL 0x1000 +#endif +#ifndef ETHERTYPE_MOPDL +#define ETHERTYPE_MOPDL 0x6001 +#endif +#ifndef ETHERTYPE_MOPRC +#define ETHERTYPE_MOPRC 0x6002 +#endif +#ifndef ETHERTYPE_DN +#define ETHERTYPE_DN 0x6003 +#endif +#ifndef ETHERTYPE_LAT +#define ETHERTYPE_LAT 0x6004 +#endif +#ifndef ETHERTYPE_SCA +#define ETHERTYPE_SCA 0x6007 +#endif +#ifndef ETHERTYPE_TEB +#define ETHERTYPE_TEB 0x6558 +#endif +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ +#endif +#ifndef ETHERTYPE_LANBRIDGE +#define ETHERTYPE_LANBRIDGE 0x8038 +#endif +#ifndef ETHERTYPE_DECDNS +#define ETHERTYPE_DECDNS 0x803c +#endif +#ifndef ETHERTYPE_DECDTS +#define ETHERTYPE_DECDTS 0x803e +#endif +#ifndef ETHERTYPE_VEXP +#define ETHERTYPE_VEXP 0x805b +#endif +#ifndef ETHERTYPE_VPROD +#define ETHERTYPE_VPROD 0x805c +#endif +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif +#ifndef ETHERTYPE_8021Q +#define ETHERTYPE_8021Q 0x8100 +#endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd +#endif +#ifndef ETHERTYPE_MPLS +#define ETHERTYPE_MPLS 0x8847 +#endif +#ifndef ETHERTYPE_MPLS_MULTI +#define ETHERTYPE_MPLS_MULTI 0x8848 +#endif +#ifndef ETHERTYPE_PPPOED +#define ETHERTYPE_PPPOED 0x8863 +#endif +#ifndef ETHERTYPE_PPPOES +#define ETHERTYPE_PPPOES 0x8864 +#endif +#ifndef ETHERTYPE_8021AD +#define ETHERTYPE_8021AD 0x88a8 +#endif +#ifndef ETHERTYPE_LOOPBACK +#define ETHERTYPE_LOOPBACK 0x9000 +#endif +#ifndef ETHERTYPE_8021QINQ +#define ETHERTYPE_8021QINQ 0x9100 +#endif diff --git a/src/libpcap-1.10.5/extract.h b/src/libpcap-1.10.5/extract.h new file mode 100644 index 0000000000..d31a40f37d --- /dev/null +++ b/src/libpcap-1.10.5/extract.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include "portability.h" + +/* + * If we have versions of GCC or Clang that support an __attribute__ + * to say "if we're building with unsigned behavior sanitization, + * don't complain about undefined behavior in this function", we + * label these functions with that attribute - we *know* it's undefined + * in the C standard, but we *also* know it does what we want with + * the ISA we're targeting and the compiler we're using. + * + * For GCC 4.9.0 and later, we use __attribute__((no_sanitize_undefined)); + * pre-5.0 GCC doesn't have __has_attribute, and I'm not sure whether + * GCC or Clang first had __attribute__((no_sanitize(XXX)). + * + * For Clang, we check for __attribute__((no_sanitize(XXX)) with + * __has_attribute, as there are versions of Clang that support + * __attribute__((no_sanitize("undefined")) but don't support + * __attribute__((no_sanitize_undefined)). + * + * We define this here, rather than in funcattrs.h, because we + * only want it used here, we don't want it to be broadly used. + * (Any printer will get this defined, but this should at least + * make it harder for people to find.) + */ +#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409) +#define UNALIGNED_OK __attribute__((no_sanitize_undefined)) +#elif __has_attribute(no_sanitize) +#define UNALIGNED_OK __attribute__((no_sanitize("undefined"))) +#else +#define UNALIGNED_OK +#endif + +#if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \ + (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \ + (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \ + (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) +/* + * The processor natively handles unaligned loads, so we can just + * cast the pointer and fetch through it. + * + * XXX - are those all the x86 tests we need? + * XXX - are those the only 68k tests we need not to generated + * unaligned accesses if the target is the 68000 or 68010? + * XXX - are there any tests we don't need, because some definitions are for + * compilers that also predefine the GCC symbols? + * XXX - do we need to test for both 32-bit and 64-bit versions of those + * architectures in all cases? + */ +UNALIGNED_OK static inline uint16_t +EXTRACT_BE_U_2(const void *p) +{ + return ((uint16_t)ntohs(*(const uint16_t *)(p))); +} + +UNALIGNED_OK static inline int16_t +EXTRACT_BE_S_2(const void *p) +{ + return ((int16_t)ntohs(*(const int16_t *)(p))); +} + +UNALIGNED_OK static inline uint32_t +EXTRACT_BE_U_4(const void *p) +{ + return ((uint32_t)ntohl(*(const uint32_t *)(p))); +} + +UNALIGNED_OK static inline int32_t +EXTRACT_BE_S_4(const void *p) +{ + return ((int32_t)ntohl(*(const int32_t *)(p))); +} + +UNALIGNED_OK static inline uint64_t +EXTRACT_BE_U_8(const void *p) +{ + return ((uint64_t)(((uint64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | + ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0)); + +} + +UNALIGNED_OK static inline int64_t +EXTRACT_BE_S_8(const void *p) +{ + return ((int64_t)(((int64_t)ntohl(*((const uint32_t *)(p) + 0))) << 32 | + ((uint64_t)ntohl(*((const uint32_t *)(p) + 1))) << 0)); + +} +#elif PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) && \ + (defined(__alpha) || defined(__alpha__) || \ + defined(__mips) || defined(__mips__)) +/* + * This is MIPS or Alpha, which don't natively handle unaligned loads, + * but which have instructions that can help when doing unaligned + * loads, and this is GCC 2.0 or later or a compiler that claims to + * be GCC 2.0 or later, which we assume that mean we have + * __attribute__((packed)), which we can use to convince the compiler + * to generate those instructions. + * + * Declare packed structures containing a uint16_t and a uint32_t, + * cast the pointer to point to one of those, and fetch through it; + * the GCC manual doesn't appear to explicitly say that + * __attribute__((packed)) causes the compiler to generate unaligned-safe + * code, but it appears to do so. + * + * We do this in case the compiler can generate code using those + * instructions to do an unaligned load and pass stuff to "ntohs()" or + * "ntohl()", which might be better than the code to fetch the + * bytes one at a time and assemble them. (That might not be the + * case on a little-endian platform, such as DEC's MIPS machines and + * Alpha machines, where "ntohs()" and "ntohl()" might not be done + * inline.) + * + * We do this only for specific architectures because, for example, + * at least some versions of GCC, when compiling for 64-bit SPARC, + * generate code that assumes alignment if we do this. + * + * XXX - add other architectures and compilers as possible and + * appropriate. + * + * HP's C compiler, indicated by __HP_cc being defined, supports + * "#pragma unaligned N" in version A.05.50 and later, where "N" + * specifies a number of bytes at which the typedef on the next + * line is aligned, e.g. + * + * #pragma unalign 1 + * typedef uint16_t unaligned_uint16_t; + * + * to define unaligned_uint16_t as a 16-bit unaligned data type. + * This could be presumably used, in sufficiently recent versions of + * the compiler, with macros similar to those below. This would be + * useful only if that compiler could generate better code for PA-RISC + * or Itanium than would be generated by a bunch of shifts-and-ORs. + * + * DEC C, indicated by __DECC being defined, has, at least on Alpha, + * an __unaligned qualifier that can be applied to pointers to get the + * compiler to generate code that does unaligned loads and stores when + * dereferencing the pointer in question. + * + * XXX - what if the native C compiler doesn't support + * __attribute__((packed))? How can we get it to generate unaligned + * accesses for *specific* items? + */ +typedef struct { + uint16_t val; +} __attribute__((packed)) unaligned_uint16_t; + +typedef struct { + int16_t val; +} __attribute__((packed)) unaligned_int16_t; + +typedef struct { + uint32_t val; +} __attribute__((packed)) unaligned_uint32_t; + +typedef struct { + int32_t val; +} __attribute__((packed)) unaligned_int32_t; + +UNALIGNED_OK static inline uint16_t +EXTRACT_BE_U_2(const void *p) +{ + return ((uint16_t)ntohs(((const unaligned_uint16_t *)(p))->val)); +} + +UNALIGNED_OK static inline int16_t +EXTRACT_BE_S_2(const void *p) +{ + return ((int16_t)ntohs(((const unaligned_int16_t *)(p))->val)); +} + +UNALIGNED_OK static inline uint32_t +EXTRACT_BE_U_4(const void *p) +{ + return ((uint32_t)ntohl(((const unaligned_uint32_t *)(p))->val)); +} + +UNALIGNED_OK static inline int32_t +EXTRACT_BE_S_4(const void *p) +{ + return ((int32_t)ntohl(((const unaligned_int32_t *)(p))->val)); +} + +UNALIGNED_OK static inline uint64_t +EXTRACT_BE_U_8(const void *p) +{ + return ((uint64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | + ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0)); +} + +UNALIGNED_OK static inline int64_t +EXTRACT_BE_S_8(const void *p) +{ + return ((int64_t)(((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 0)->val)) << 32 | + ((uint64_t)ntohl(((const unaligned_uint32_t *)(p) + 1)->val)) << 0)); +} +#else +/* + * This architecture doesn't natively support unaligned loads, and either + * this isn't a GCC-compatible compiler, we don't have __attribute__, + * or we do but we don't know of any better way with this instruction + * set to do unaligned loads, so do unaligned loads of big-endian + * quantities the hard way - fetch the bytes one at a time and + * assemble them. + * + * XXX - ARM is a special case. ARMv1 through ARMv5 didn't support + * unaligned loads; ARMv6 and later support it *but* have a bit in + * the system control register that the OS can set and that causes + * unaligned loads to fault rather than succeeding. + * + * At least some OSes may set that flag, so we do *not* treat ARM + * as supporting unaligned loads. If your OS supports them on ARM, + * and you want to use them, please update the tests in the #if above + * to check for ARM *and* for your OS. + */ +#define EXTRACT_BE_U_2(p) \ + ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0))) +#define EXTRACT_BE_S_2(p) \ + ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 0)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 1)) << 0))) +#define EXTRACT_BE_U_4(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0))) +#define EXTRACT_BE_S_4(p) \ + ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0))) +#define EXTRACT_BE_U_8(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0))) +#define EXTRACT_BE_S_8(p) \ + ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 7)) << 0))) + +/* + * Extract an IPv4 address, which is in network byte order, and not + * necessarily aligned, and provide the result in host byte order. + */ +#define EXTRACT_IPV4_TO_HOST_ORDER(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 3)) << 0))) +#endif /* unaligned access checks */ + +/* + * Non-power-of-2 sizes. + */ +#define EXTRACT_BE_U_3(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) + +#define EXTRACT_BE_S_3(p) \ + (((*((const uint8_t *)(p) + 0)) & 0x80) ? \ + ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0))) : \ + ((int32_t)(0xFF000000U | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 0)))) + +#define EXTRACT_BE_U_5(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) + +#define EXTRACT_BE_S_5(p) \ + (((*((const uint8_t *)(p) + 0)) & 0x80) ? \ + ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0))) : \ + ((int64_t)(INT64_T_CONSTANT(0xFFFFFF0000000000U) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 0)))) + +#define EXTRACT_BE_U_6(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) + +#define EXTRACT_BE_S_6(p) \ + (((*((const uint8_t *)(p) + 0)) & 0x80) ? \ + ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0))) : \ + ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFF00000000U) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 0)))) + +#define EXTRACT_BE_U_7(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) + +#define EXTRACT_BE_S_7(p) \ + (((*((const uint8_t *)(p) + 0)) & 0x80) ? \ + ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0))) : \ + ((int64_t)(INT64_T_CONSTANT(0xFFFFFFFFFF000000U) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 0)))) + +/* + * Macros to extract possibly-unaligned little-endian integral values. + * XXX - do loads on little-endian machines that support unaligned loads? + */ +#define EXTRACT_LE_U_2(p) \ + ((uint16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_S_2(p) \ + ((int16_t)(((uint16_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint16_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_U_4(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_S_4(p) \ + ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_U_3(p) \ + ((uint32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_S_3(p) \ + ((int32_t)(((uint32_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint32_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint32_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_U_8(p) \ + ((uint64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0))) +#define EXTRACT_LE_S_8(p) \ + ((int64_t)(((uint64_t)(*((const uint8_t *)(p) + 7)) << 56) | \ + ((uint64_t)(*((const uint8_t *)(p) + 6)) << 48) | \ + ((uint64_t)(*((const uint8_t *)(p) + 5)) << 40) | \ + ((uint64_t)(*((const uint8_t *)(p) + 4)) << 32) | \ + ((uint64_t)(*((const uint8_t *)(p) + 3)) << 24) | \ + ((uint64_t)(*((const uint8_t *)(p) + 2)) << 16) | \ + ((uint64_t)(*((const uint8_t *)(p) + 1)) << 8) | \ + ((uint64_t)(*((const uint8_t *)(p) + 0)) << 0))) diff --git a/src/libpcap-1.10.5/fad-getad.c b/src/libpcap-1.10.5/fad-getad.c new file mode 100644 index 0000000000..0df567c447 --- /dev/null +++ b/src/libpcap-1.10.5/fad-getad.c @@ -0,0 +1,293 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * We don't do this on Solaris 11 and later, as it appears there aren't + * any AF_PACKET addresses on interfaces, so we don't need this, and + * we end up including both the OS's and our , + * and their definitions of some data structures collide. + */ +#if (defined(__linux__) || defined(__Lynx__)) && defined(AF_PACKET) +# ifdef HAVE_NETPACKET_PACKET_H +/* Linux distributions with newer glibc */ +# include +# else /* HAVE_NETPACKET_PACKET_H */ +/* LynxOS, Linux distributions with older glibc */ +# ifdef __Lynx__ +/* LynxOS */ +# include +# else /* __Lynx__ */ +/* Linux */ +# include +# include +# endif /* __Lynx__ */ +# endif /* HAVE_NETPACKET_PACKET_H */ +#endif /* (defined(__linux__) || defined(__Lynx__)) && defined(AF_PACKET) */ + +/* + * This is fun. + * + * In older BSD systems, socket addresses were fixed-length, and + * "sizeof (struct sockaddr)" gave the size of the structure. + * All addresses fit within a "struct sockaddr". + * + * In newer BSD systems, the socket address is variable-length, and + * there's an "sa_len" field giving the length of the structure; + * this allows socket addresses to be longer than 2 bytes of family + * and 14 bytes of data. + * + * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 + * variant of the old BSD scheme (with "struct sockaddr_storage" rather + * than "struct sockaddr"), and some use the new BSD scheme. + * + * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" + * macro that determines the size based on the address family. Other + * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 + * but not in the final version). On the latter systems, we explicitly + * check the AF_ type to determine the length; we assume that on + * all those systems we have "struct sockaddr_storage". + * + * OSes that use this file are: + * - FreeBSD (HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - Haiku (HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - Hurd (HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - illumos (HAVE_STRUCT_SOCKADDR_SA_LEN is not defined) + * - Linux (HAVE_STRUCT_SOCKADDR_SA_LEN is not defined) + * - macOS (HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - NetBSD (HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - OpenBSD (SA_LEN() is defined) + * - Solaris 11 (HAVE_STRUCT_SOCKADDR_SA_LEN is not defined) + */ +#ifndef SA_LEN +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +#define SA_LEN(addr) ((addr)->sa_len) +#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE +static size_t +get_sa_len(struct sockaddr *addr) +{ + switch (addr->sa_family) { + +#ifdef AF_INET + case AF_INET: + return (sizeof (struct sockaddr_in)); +#endif + +#ifdef AF_INET6 + case AF_INET6: + return (sizeof (struct sockaddr_in6)); +#endif + +#if (defined(__linux__) || defined(__Lynx__)) && defined(AF_PACKET) + case AF_PACKET: + return (sizeof (struct sockaddr_ll)); +#endif + +#ifdef AF_LINK + case AF_LINK: + return (sizeof (struct sockaddr_dl)); +#endif + + default: + return (sizeof (struct sockaddr)); + } +} +#define SA_LEN(addr) (get_sa_len(addr)) +#else /* HAVE_STRUCT_SOCKADDR_STORAGE */ +#define SA_LEN(addr) (sizeof (struct sockaddr)) +#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */ +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#endif /* SA_LEN */ + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * could be opened. + */ +int +pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf, + int (*check_usable)(const char *), get_if_flags_func get_flags_func) +{ + struct ifaddrs *ifap, *ifa; + struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; + size_t addr_size, broadaddr_size, dstaddr_size; + int ret = 0; + char *p, *q; + + /* + * Get the list of interface addresses. + * + * Note: this won't return information about interfaces + * with no addresses, so, if a platform has interfaces + * with no interfaces on which traffic can be captured, + * we must check for those interfaces as well (see, for + * example, what's done on Linux). + * + * LAN interfaces will probably have link-layer + * addresses; I don't know whether all implementations + * of "getifaddrs()" now, or in the future, will return + * those. + */ + if (getifaddrs(&ifap) != 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "getifaddrs"); + return (-1); + } + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + /* + * If this entry has a colon followed by a number at + * the end, we assume it's a logical interface. Those + * are just the way you assign multiple IP addresses to + * a real interface on Linux, so an entry for a logical + * interface should be treated like the entry for the + * real interface; we do that by stripping off the ":" + * and the number. + * + * XXX - should we do this only on Linux? + */ + p = strchr(ifa->ifa_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (PCAP_ISDIGIT(*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } + + /* + * Can we capture on this device? + */ + if (!(*check_usable)(ifa->ifa_name)) { + /* + * No. + */ + continue; + } + + /* + * "ifa_addr" was apparently null on at least one + * interface on some system. Therefore, we supply + * the address and netmask only if "ifa_addr" is + * non-null (if there's no address, there's obviously + * no netmask). + */ + if (ifa->ifa_addr != NULL) { + addr = ifa->ifa_addr; + addr_size = SA_LEN(addr); + netmask = ifa->ifa_netmask; + } else { + addr = NULL; + addr_size = 0; + netmask = NULL; + } + + /* + * Note that, on some platforms, ifa_broadaddr and + * ifa_dstaddr could be the same field (true on at + * least some versions of *BSD and macOS), so we + * can't just check whether the broadcast address + * is null and add it if so and check whether the + * destination address is null and add it if so. + * + * Therefore, we must also check the IFF_BROADCAST + * flag, and only add a broadcast address if it's + * set, and check the IFF_POINTTOPOINT flag, and + * only add a destination address if it's set (as + * per man page recommendations on some of those + * platforms). + */ + if (ifa->ifa_flags & IFF_BROADCAST && + ifa->ifa_broadaddr != NULL) { + broadaddr = ifa->ifa_broadaddr; + broadaddr_size = SA_LEN(broadaddr); + } else { + broadaddr = NULL; + broadaddr_size = 0; + } + if (ifa->ifa_flags & IFF_POINTOPOINT && + ifa->ifa_dstaddr != NULL) { + dstaddr = ifa->ifa_dstaddr; + dstaddr_size = SA_LEN(ifa->ifa_dstaddr); + } else { + dstaddr = NULL; + dstaddr_size = 0; + } + + /* + * Add information for this address to the list. + */ + if (pcapint_add_addr_to_if(devlistp, ifa->ifa_name, ifa->ifa_flags, + get_flags_func, + addr, addr_size, netmask, addr_size, + broadaddr, broadaddr_size, dstaddr, dstaddr_size, + errbuf) < 0) { + ret = -1; + break; + } + } + + freeifaddrs(ifap); + + return (ret); +} diff --git a/src/libpcap-1.10.5/fad-gifc.c b/src/libpcap-1.10.5/fad-gifc.c new file mode 100644 index 0000000000..54834df88c --- /dev/null +++ b/src/libpcap-1.10.5/fad-gifc.c @@ -0,0 +1,427 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#include /* concession to AIX */ + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * This is fun. + * + * In older BSD systems, socket addresses were fixed-length, and + * "sizeof (struct sockaddr)" gave the size of the structure. + * All addresses fit within a "struct sockaddr". + * + * In newer BSD systems, the socket address is variable-length, and + * there's an "sa_len" field giving the length of the structure; + * this allows socket addresses to be longer than 2 bytes of family + * and 14 bytes of data. + * + * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 + * variant of the old BSD scheme (with "struct sockaddr_storage" rather + * than "struct sockaddr"), and some use the new BSD scheme. + * + * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" + * macro that determines the size based on the address family. Other + * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 + * but not in the final version). + * + * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have + * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the + * address in an entry returned by SIOCGIFCONF. + * + * OSes that use this file are: + * - AIX 7 (SA_LEN() is not defined, HAVE_STRUCT_SOCKADDR_SA_LEN is defined) + * - HP-UX 11 (HAVE_STRUCT_SOCKADDR_SA_LEN is not defined) + */ +#ifndef SA_LEN +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +#define SA_LEN(addr) ((addr)->sa_len) +#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#define SA_LEN(addr) (sizeof (struct sockaddr)) +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ +#endif /* SA_LEN */ + +/* + * This is also fun. + * + * There is no ioctl that returns the amount of space required for all + * the data that SIOCGIFCONF could return, and if a buffer is supplied + * that's not large enough for all the data SIOCGIFCONF could return, + * on at least some platforms it just returns the data that'd fit with + * no indication that there wasn't enough room for all the data, much + * less an indication of how much more room is required. + * + * The only way to ensure that we got all the data is to pass a buffer + * large enough that the amount of space in the buffer *not* filled in + * is greater than the largest possible entry. + * + * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption + * that no address is more than 255 bytes (on systems where the "sa_len" + * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the + * case, and addresses are unlikely to be bigger than that in any case). + */ +#define MAX_SA_LEN 255 + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * This is the implementation used on platforms that have SIOCGIFCONF but + * don't have any other mechanism for getting a list of interfaces. + * + * XXX - or platforms that have other, better mechanisms but for which + * we don't yet have code to use that mechanism; I think there's a better + * way on Linux, for example, but if that better way is "getifaddrs()", + * we already have that. + */ +int +pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf, + int (*check_usable)(const char *), get_if_flags_func get_flags_func) +{ + register int fd; + register struct ifreq *ifrp, *ifend, *ifnext; + size_t n; + struct ifconf ifc; + char *buf = NULL; + unsigned buf_size; +#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) + char *p, *q; +#endif + struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; + struct sockaddr *netmask, *broadaddr, *dstaddr; + size_t netmask_size, broadaddr_size, dstaddr_size; + int ret = 0; + + /* + * Create a socket from which to fetch the list of interfaces. + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + return (-1); + } + + /* + * Start with an 8K buffer, and keep growing the buffer until + * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN" + * bytes left over in the buffer or we fail to get the + * interface list for some reason other than EINVAL (which is + * presumed here to mean "buffer is too small"). + */ + buf_size = 8192; + for (;;) { + /* + * Don't let the buffer size get bigger than INT_MAX. + */ + if (buf_size > INT_MAX) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "interface information requires more than %u bytes", + INT_MAX); + (void)close(fd); + return (-1); + } + buf = malloc(buf_size); + if (buf == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + (void)close(fd); + return (-1); + } + + ifc.ifc_len = buf_size; + ifc.ifc_buf = buf; + memset(buf, 0, buf_size); + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 + && errno != EINVAL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFCONF"); + (void)close(fd); + free(buf); + return (-1); + } + if (ifc.ifc_len < (int)buf_size && + (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN) + break; + free(buf); + buf_size *= 2; + } + + ifrp = (struct ifreq *)buf; + ifend = (struct ifreq *)(buf + ifc.ifc_len); + + for (; ifrp < ifend; ifrp = ifnext) { + /* + * XXX - what if this isn't an IPv4 address? Can + * we still get the netmask, etc. with ioctls on + * an IPv4 socket? + * + * The answer is probably platform-dependent, and + * if the answer is "no" on more than one platform, + * the way you work around it is probably platform- + * dependent as well. + */ + n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ifnext = ifrp + 1; + else + ifnext = (struct ifreq *)((char *)ifrp + n); + + /* + * XXX - The 32-bit compatibility layer for Linux on IA-64 + * is slightly broken. It correctly converts the structures + * to and from kernel land from 64 bit to 32 bit but + * doesn't update ifc.ifc_len, leaving it larger than the + * amount really used. This means we read off the end + * of the buffer and encounter an interface with an + * "empty" name. Since this is highly unlikely to ever + * occur in a valid case we can just finish looking for + * interfaces if we see an empty name. + */ + if (!(*ifrp->ifr_name)) + break; + + /* + * Skip entries that begin with "dummy". + * XXX - what are these? Is this Linux-specific? + * Are there platforms on which we shouldn't do this? + */ + if (strncmp(ifrp->ifr_name, "dummy", 5) == 0) + continue; + + /* + * Can we capture on this device? + */ + if (!(*check_usable)(ifrp->ifr_name)) { + /* + * No. + */ + continue; + } + + /* + * Get the flags for this interface. + */ + strncpy(ifrflags.ifr_name, ifrp->ifr_name, + sizeof(ifrflags.ifr_name)); + if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + continue; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFFLAGS: %.*s", + (int)sizeof(ifrflags.ifr_name), + ifrflags.ifr_name); + ret = -1; + break; + } + + /* + * Get the netmask for this address on this interface. + */ + strncpy(ifrnetmask.ifr_name, ifrp->ifr_name, + sizeof(ifrnetmask.ifr_name)); + memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrnetmask.ifr_addr)); + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + netmask = NULL; + netmask_size = 0; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGIFNETMASK: %.*s", + (int)sizeof(ifrnetmask.ifr_name), + ifrnetmask.ifr_name); + ret = -1; + break; + } + } else { + netmask = &ifrnetmask.ifr_addr; + netmask_size = SA_LEN(netmask); + } + + /* + * Get the broadcast address for this address on this + * interface (if any). + */ + if (ifrflags.ifr_flags & IFF_BROADCAST) { + strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name, + sizeof(ifrbroadaddr.ifr_name)); + memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrbroadaddr.ifr_addr)); + if (ioctl(fd, SIOCGIFBRDADDR, + (char *)&ifrbroadaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + broadaddr = NULL; + broadaddr_size = 0; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGIFBRDADDR: %.*s", + (int)sizeof(ifrbroadaddr.ifr_name), + ifrbroadaddr.ifr_name); + ret = -1; + break; + } + } else { + broadaddr = &ifrbroadaddr.ifr_broadaddr; + broadaddr_size = SA_LEN(broadaddr); + } + } else { + /* + * Not a broadcast interface, so no broadcast + * address. + */ + broadaddr = NULL; + broadaddr_size = 0; + } + + /* + * Get the destination address for this address on this + * interface (if any). + */ + if (ifrflags.ifr_flags & IFF_POINTOPOINT) { + strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name, + sizeof(ifrdstaddr.ifr_name)); + memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr, + sizeof(ifrdstaddr.ifr_addr)); + if (ioctl(fd, SIOCGIFDSTADDR, + (char *)&ifrdstaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + dstaddr = NULL; + dstaddr_size = 0; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGIFDSTADDR: %.*s", + (int)sizeof(ifrdstaddr.ifr_name), + ifrdstaddr.ifr_name); + ret = -1; + break; + } + } else { + dstaddr = &ifrdstaddr.ifr_dstaddr; + dstaddr_size = SA_LEN(dstaddr); + } + } else { + /* + * Not a point-to-point interface, so no destination + * address. + */ + dstaddr = NULL; + dstaddr_size = 0; + } + +#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) + /* + * If this entry has a colon followed by a number at + * the end, it's a logical interface. Those are just + * the way you assign multiple IP addresses to a real + * interface, so an entry for a logical interface should + * be treated like the entry for the real interface; + * we do that by stripping off the ":" and the number. + */ + p = strchr(ifrp->ifr_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (PCAP_ISDIGIT(*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } +#endif + + /* + * Add information for this address to the list. + */ + if (pcapint_add_addr_to_if(devlistp, ifrp->ifr_name, + ifrflags.ifr_flags, get_flags_func, + &ifrp->ifr_addr, SA_LEN(&ifrp->ifr_addr), + netmask, netmask_size, broadaddr, broadaddr_size, + dstaddr, dstaddr_size, errbuf) < 0) { + ret = -1; + break; + } + } + free(buf); + (void)close(fd); + + return (ret); +} diff --git a/src/libpcap-1.10.5/fad-glifc.c b/src/libpcap-1.10.5/fad-glifc.c new file mode 100644 index 0000000000..28089d37e3 --- /dev/null +++ b/src/libpcap-1.10.5/fad-glifc.c @@ -0,0 +1,347 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#include /* concession to AIX */ + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Only Solaris 10 uses this file. + */ + +/* + * Get a list of all interfaces that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + * + * This is the implementation used on platforms that have SIOCGLIFCONF + * but don't have "getifaddrs()". (Solaris 8 and later; we use + * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) + */ +int +pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf, + int (*check_usable)(const char *), get_if_flags_func get_flags_func) +{ + register int fd4, fd6, fd; + register struct lifreq *ifrp, *ifend; + struct lifnum ifn; + struct lifconf ifc; + char *buf = NULL; + unsigned buf_size; +#ifdef HAVE_SOLARIS + char *p, *q; +#endif + struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; + struct sockaddr *netmask, *broadaddr, *dstaddr; + int ret = 0; + + /* + * Create a socket from which to fetch the list of interfaces, + * and from which to fetch IPv4 information. + */ + fd4 = socket(AF_INET, SOCK_DGRAM, 0); + if (fd4 < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "socket: AF_INET"); + return (-1); + } + + /* + * Create a socket from which to fetch IPv6 information. + */ + fd6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd6 < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "socket: AF_INET6"); + (void)close(fd4); + return (-1); + } + + /* + * How many entries will SIOCGLIFCONF return? + */ + ifn.lifn_family = AF_UNSPEC; + ifn.lifn_flags = 0; + ifn.lifn_count = 0; + if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGLIFNUM"); + (void)close(fd6); + (void)close(fd4); + return (-1); + } + + /* + * Allocate a buffer for those entries. + */ + buf_size = ifn.lifn_count * sizeof (struct lifreq); + buf = malloc(buf_size); + if (buf == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + (void)close(fd6); + (void)close(fd4); + return (-1); + } + + /* + * Get the entries. + */ + ifc.lifc_len = buf_size; + ifc.lifc_buf = buf; + ifc.lifc_family = AF_UNSPEC; + ifc.lifc_flags = 0; + memset(buf, 0, buf_size); + if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGLIFCONF"); + (void)close(fd6); + (void)close(fd4); + free(buf); + return (-1); + } + + /* + * Loop over the entries. + */ + ifrp = (struct lifreq *)buf; + ifend = (struct lifreq *)(buf + ifc.lifc_len); + + for (; ifrp < ifend; ifrp++) { + /* + * Skip entries that begin with "dummy". + * XXX - what are these? Is this Linux-specific? + * Are there platforms on which we shouldn't do this? + */ + if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) + continue; + + /* + * Can we capture on this device? + */ + if (!(*check_usable)(ifrp->lifr_name)) { + /* + * No. + */ + continue; + } + + /* + * IPv6 or not? + */ + if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) + fd = fd6; + else + fd = fd4; + + /* + * Get the flags for this interface. + */ + strncpy(ifrflags.lifr_name, ifrp->lifr_name, + sizeof(ifrflags.lifr_name)); + if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { + if (errno == ENXIO) + continue; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGLIFFLAGS: %.*s", + (int)sizeof(ifrflags.lifr_name), + ifrflags.lifr_name); + ret = -1; + break; + } + + /* + * Get the netmask for this address on this interface. + */ + strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, + sizeof(ifrnetmask.lifr_name)); + memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrnetmask.lifr_addr)); + if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + netmask = NULL; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGLIFNETMASK: %.*s", + (int)sizeof(ifrnetmask.lifr_name), + ifrnetmask.lifr_name); + ret = -1; + break; + } + } else + netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; + + /* + * Get the broadcast address for this address on this + * interface (if any). + */ + if (ifrflags.lifr_flags & IFF_BROADCAST) { + strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, + sizeof(ifrbroadaddr.lifr_name)); + memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrbroadaddr.lifr_addr)); + if (ioctl(fd, SIOCGLIFBRDADDR, + (char *)&ifrbroadaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + broadaddr = NULL; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGLIFBRDADDR: %.*s", + (int)sizeof(ifrbroadaddr.lifr_name), + ifrbroadaddr.lifr_name); + ret = -1; + break; + } + } else + broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; + } else { + /* + * Not a broadcast interface, so no broadcast + * address. + */ + broadaddr = NULL; + } + + /* + * Get the destination address for this address on this + * interface (if any). + */ + if (ifrflags.lifr_flags & IFF_POINTOPOINT) { + strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, + sizeof(ifrdstaddr.lifr_name)); + memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, + sizeof(ifrdstaddr.lifr_addr)); + if (ioctl(fd, SIOCGLIFDSTADDR, + (char *)&ifrdstaddr) < 0) { + if (errno == EADDRNOTAVAIL) { + /* + * Not available. + */ + dstaddr = NULL; + } else { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGLIFDSTADDR: %.*s", + (int)sizeof(ifrdstaddr.lifr_name), + ifrdstaddr.lifr_name); + ret = -1; + break; + } + } else + dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; + } else + dstaddr = NULL; + +#ifdef HAVE_SOLARIS + /* + * If this entry has a colon followed by a number at + * the end, it's a logical interface. Those are just + * the way you assign multiple IP addresses to a real + * interface, so an entry for a logical interface should + * be treated like the entry for the real interface; + * we do that by stripping off the ":" and the number. + */ + p = strchr(ifrp->lifr_name, ':'); + if (p != NULL) { + /* + * We have a ":"; is it followed by a number? + */ + q = p + 1; + while (PCAP_ISDIGIT(*q)) + q++; + if (*q == '\0') { + /* + * All digits after the ":" until the end. + * Strip off the ":" and everything after + * it. + */ + *p = '\0'; + } + } +#endif + + /* + * Add information for this address to the list. + */ + if (pcapint_add_addr_to_if(devlistp, ifrp->lifr_name, + ifrflags.lifr_flags, get_flags_func, + (struct sockaddr *)&ifrp->lifr_addr, + sizeof (struct sockaddr_storage), + netmask, sizeof (struct sockaddr_storage), + broadaddr, sizeof (struct sockaddr_storage), + dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { + ret = -1; + break; + } + } + free(buf); + (void)close(fd6); + (void)close(fd4); + + return (ret); +} diff --git a/src/libpcap-1.10.5/fmtutils.c b/src/libpcap-1.10.5/fmtutils.c new file mode 100644 index 0000000000..a5a4fe62f3 --- /dev/null +++ b/src/libpcap-1.10.5/fmtutils.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Utilities for message formatting used both by libpcap and rpcapd. + */ + +#include + +#include "ftmacros.h" + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#include "portability.h" + +#include "fmtutils.h" + +#ifdef _WIN32 +#include "charconv.h" +#endif + +/* + * Set the encoding. + */ +#ifdef _WIN32 +/* + * True if we should use UTF-8. + */ +static int use_utf_8; + +void +pcapint_fmt_set_encoding(unsigned int opts) +{ + if (opts == PCAP_CHAR_ENC_UTF_8) + use_utf_8 = 1; +} +#else +void +pcapint_fmt_set_encoding(unsigned int opts _U_) +{ + /* + * Nothing to do here. + */ +} +#endif + +#ifdef _WIN32 +/* + * Convert a null-terminated UTF-16LE string to UTF-8, putting it into + * a buffer starting at the specified location and stopping if we go + * past the specified size. This will only put out complete UTF-8 + * sequences. + * + * We do this ourselves because Microsoft doesn't offer a "convert and + * stop at a UTF-8 character boundary if we run out of space" routine. + */ +#define IS_LEADING_SURROGATE(c) \ + ((c) >= 0xd800 && (c) < 0xdc00) +#define IS_TRAILING_SURROGATE(c) \ + ((c) >= 0xdc00 && (c) < 0xe000) +#define SURROGATE_VALUE(leading, trailing) \ + (((((leading) - 0xd800) << 10) | ((trailing) - 0xdc00)) + 0x10000) +#define REPLACEMENT_CHARACTER 0x0FFFD + +static char * +utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8, + size_t utf_8_len) +{ + wchar_t c, c2; + uint32_t uc; + + if (utf_8_len == 0) { + /* + * Not even enough room for a trailing '\0'. + * Don't put anything into the buffer. + */ + return (utf_8); + } + + while ((c = *utf_16++) != '\0') { + if (IS_LEADING_SURROGATE(c)) { + /* + * Leading surrogate. Must be followed by + * a trailing surrogate. + */ + c2 = *utf_16; + if (c2 == '\0') { + /* + * Oops, string ends with a lead + * surrogate. Try to drop in + * a REPLACEMENT CHARACTER, and + * don't move the string pointer, + * so on the next trip through + * the loop we grab the terminating + * '\0' and quit. + */ + uc = REPLACEMENT_CHARACTER; + } else { + /* + * OK, we can consume this 2-octet + * value. + */ + utf_16++; + if (IS_TRAILING_SURROGATE(c2)) { + /* + * Trailing surrogate. + * This calculation will, + * for c being a leading + * surrogate and c2 being + * a trailing surrogate, + * produce a value between + * 0x100000 and 0x10ffff, + * so it's always going to be + * a valid Unicode code point. + */ + uc = SURROGATE_VALUE(c, c2); + } else { + /* + * Not a trailing surrogate; + * try to drop in a + * REPLACEMENT CHARACTER. + */ + uc = REPLACEMENT_CHARACTER; + } + } + } else { + /* + * Not a leading surrogate. + */ + if (IS_TRAILING_SURROGATE(c)) { + /* + * Trailing surrogate without + * a preceding leading surrogate. + * Try to drop in a REPLACEMENT + * CHARACTER. + */ + uc = REPLACEMENT_CHARACTER; + } else { + /* + * This is a valid BMP character; + * drop it in. + */ + uc = c; + } + } + + /* + * OK, uc is a valid Unicode character; how + * many bytes worth of UTF-8 does it require? + */ + if (uc < 0x0080) { + /* 1 byte. */ + if (utf_8_len < 2) { + /* + * Not enough room for that byte + * plus a trailing '\0'. + */ + break; + } + *utf_8++ = (char)uc; + utf_8_len--; + } else if (uc < 0x0800) { + /* 2 bytes. */ + if (utf_8_len < 3) { + /* + * Not enough room for those bytes + * plus a trailing '\0'. + */ + break; + } + *utf_8++ = ((uc >> 6) & 0x3F) | 0xC0; + *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; + utf_8_len -= 2; + } else if (uc < 0x010000) { + /* 3 bytes. */ + if (utf_8_len < 4) { + /* + * Not enough room for those bytes + * plus a trailing '\0'. + */ + break; + } + *utf_8++ = ((uc >> 12) & 0x0F) | 0xE0; + *utf_8++ = ((uc >> 6) & 0x3F) | 0x80; + *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; + utf_8_len -= 3; + } else { + /* 4 bytes. */ + if (utf_8_len < 5) { + /* + * Not enough room for those bytes + * plus a trailing '\0'. + */ + break; + } + *utf_8++ = ((uc >> 18) & 0x03) | 0xF0; + *utf_8++ = ((uc >> 12) & 0x3F) | 0x80; + *utf_8++ = ((uc >> 6) & 0x3F) | 0x80; + *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; + utf_8_len -= 3; + } + } + + /* + * OK, we have enough room for (at least) a trailing '\0'. + * (We started out with enough room, thanks to the test + * for a zero-length buffer at the beginning, and if + * there wasn't enough room for any character we wanted + * to put into the buffer *plus* a trailing '\0', + * we'd have quit before putting it into the buffer, + * and thus would have left enough room for the trailing + * '\0'.) + * + * Drop it in. + */ + *utf_8 = '\0'; + + /* + * Return a pointer to the terminating '\0', in case we + * want to drop something in after that. + */ + return (utf_8); +} +#endif /* _WIN32 */ + +/* + * Generate an error message based on a format, arguments, and an + * errno, with a message for the errno after the formatted output. + */ +void +pcapint_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pcapint_vfmt_errmsg_for_errno(errbuf, errbuflen, errnum, fmt, ap); + va_end(ap); +} + +void +pcapint_vfmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, + const char *fmt, va_list ap) +{ + size_t msglen; + char *p; + size_t errbuflen_remaining; + + (void)vsnprintf(errbuf, errbuflen, fmt, ap); + msglen = strlen(errbuf); + + /* + * Do we have enough space to append ": "? + * Including the terminating '\0', that's 3 bytes. + */ + if (msglen + 3 > errbuflen) { + /* No - just give them what we've produced. */ + return; + } + p = errbuf + msglen; + errbuflen_remaining = errbuflen - msglen; + *p++ = ':'; + *p++ = ' '; + *p = '\0'; + errbuflen_remaining -= 2; + + /* + * Now append the string for the error code. + */ +#if defined(HAVE__WCSERROR_S) + /* + * We have a Windows-style _wcserror_s(). + * Generate a UTF-16LE error message. + */ + wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE]; + errno_t err = _wcserror_s(utf_16_errbuf, PCAP_ERRBUF_SIZE, errnum); + if (err != 0) { + /* + * It doesn't appear to be documented anywhere obvious + * what the error returns from _wcserror_s(). + */ + snprintf(p, errbuflen_remaining, "Error %d", errnum); + return; + } + + /* + * Now convert it from UTF-16LE to UTF-8, dropping it in the + * remaining space in the buffer, and truncating it - cleanly, + * on a UTF-8 character boundary - if it doesn't fit. + */ + utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining); + + /* + * Now, if we're not in UTF-8 mode, convert errbuf to the + * local code page. + */ + if (!use_utf_8) + utf_8_to_acp_truncated(errbuf); +#else + /* + * Either Windows without _wcserror_s() or not Windows. Let pcap_strerror() + * solve the non-UTF-16 part of this problem space. + */ + snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum)); +#endif +} + +#ifdef _WIN32 +/* + * Generate an error message based on a format, arguments, and a + * Win32 error, with a message for the Win32 error after the formatted output. + */ +void +pcapint_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pcapint_vfmt_errmsg_for_win32_err(errbuf, errbuflen, errnum, fmt, ap); + va_end(ap); +} + +void +pcapint_vfmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, + const char *fmt, va_list ap) +{ + size_t msglen; + char *p; + size_t errbuflen_remaining; + DWORD retval; + wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE]; + size_t utf_8_len; + + vsnprintf(errbuf, errbuflen, fmt, ap); + msglen = strlen(errbuf); + + /* + * Do we have enough space to append ": "? + * Including the terminating '\0', that's 3 bytes. + */ + if (msglen + 3 > errbuflen) { + /* No - just give them what we've produced. */ + return; + } + p = errbuf + msglen; + errbuflen_remaining = errbuflen - msglen; + *p++ = ':'; + *p++ = ' '; + *p = '\0'; + msglen += 2; + errbuflen_remaining -= 2; + + /* + * Now append the string for the error code. + * + * XXX - what language ID to use? + * + * For UN*Xes, pcap_strerror() may or may not return localized + * strings. + * + * We currently don't have localized messages for libpcap, but + * we might want to do so. On the other hand, if most of these + * messages are going to be read by libpcap developers and + * perhaps by developers of libpcap-based applications, English + * might be a better choice, so the developer doesn't have to + * get the message translated if it's in a language they don't + * happen to understand. + */ + retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL); + if (retval == 0) { + /* + * Failed. + */ + snprintf(p, errbuflen_remaining, + "Couldn't get error message for error (%lu)", errnum); + return; + } + + /* + * Now convert it from UTF-16LE to UTF-8. + */ + p = utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining); + + /* + * Now append the error number, if it fits. + */ + utf_8_len = p - errbuf; + errbuflen_remaining -= utf_8_len; + if (utf_8_len == 0) { + /* The message was empty. */ + snprintf(p, errbuflen_remaining, "(%lu)", errnum); + } else + snprintf(p, errbuflen_remaining, " (%lu)", errnum); + + /* + * Now, if we're not in UTF-8 mode, convert errbuf to the + * local code page. + */ + if (!use_utf_8) + utf_8_to_acp_truncated(errbuf); +} +#endif diff --git a/src/libpcap-1.10.5/fmtutils.h b/src/libpcap-1.10.5/fmtutils.h new file mode 100644 index 0000000000..d163e386f3 --- /dev/null +++ b/src/libpcap-1.10.5/fmtutils.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef fmtutils_h +#define fmtutils_h + +#include /* we declare varargs functions */ + +#include "pcap/funcattrs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void pcapint_fmt_set_encoding(unsigned int); + +void pcapint_fmt_errmsg_for_errno(char *, size_t, int, + PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +void pcapint_vfmt_errmsg_for_errno(char *, size_t, int, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(4, 0); + +#ifdef _WIN32 +void pcapint_fmt_errmsg_for_win32_err(char *, size_t, DWORD, + PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); +void pcapint_vfmt_errmsg_for_win32_err(char *, size_t, DWORD, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(4, 0); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpcap-1.10.5/ftmacros.h b/src/libpcap-1.10.5/ftmacros.h new file mode 100644 index 0000000000..a1488e1281 --- /dev/null +++ b/src/libpcap-1.10.5/ftmacros.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ftmacros_h +#define ftmacros_h + +/* + * Define some feature test macros to make sure that everything we want + * to be declared gets declared. + * + * On some UN*Xes we need to force strtok_r() to be declared. + * We do *NOT* want to define _POSIX_C_SOURCE, as that tends + * to make non-POSIX APIs that we use unavailable. + * XXX - is there no portable way to say "please pollute the + * namespace to the maximum extent possible"? + */ +#if defined(sun) || defined(__sun) + /* + * On Solaris Clang defines __EXTENSIONS__ automatically. + */ + #ifndef __EXTENSIONS__ + #define __EXTENSIONS__ + #endif + + /* + * We also need to define _XPG4_2 in order to get + * the Single UNIX Specification version of + * recvmsg(). + */ + #define _XPG4_2 +#elif defined(_hpux) || defined(hpux) || defined(__hpux) + #define _REENTRANT + + /* + * We need this to get the versions of socket functions that + * use socklen_t. Define it only if it's not already defined, + * so we don't get redefinition warnings. + */ + #ifndef _XOPEN_SOURCE_EXTENDED + #define _XOPEN_SOURCE_EXTENDED + #endif + + /* + * XXX - the list of PA-RISC options for GCC makes it sound as if + * building code that uses a particular vintage of UNIX API/ABI + * is complicated: + * + * https://gcc.gnu.org/onlinedocs/gcc/HPPA-Options.html + * + * See the description of the -munix flag. + * + * We probably want libpcap to work with programs built for any + * UN*X standard. I'm not sure whether that's possible and, if + * it is, what sort of stuff it'd have to do. + * + * It might also be a requirement that we build with a special + * flag to allow the library to be used with threaded code, at + * least with HP's C compiler; hopefully doing so won't make it + * *not* work with *un*-threaded code. + */ +#else + /* + * Turn on _GNU_SOURCE to get everything GNU libc has to offer, + * including asprintf(), if we're using GNU libc. + * + * Unfortunately, one thing it has to offer is a strerror_r() + * that's not POSIX-compliant, but we deal with that in + * pcapint_fmt_errmsg_for_errno(). + * + * We don't limit this to, for example, Linux and Cygwin, because + * this might, for example, be GNU/HURD or one of Debian's kFreeBSD + * OSes ("GNU/FreeBSD"). + */ + #define _GNU_SOURCE + + /* + * We turn on both _DEFAULT_SOURCE and _BSD_SOURCE to try to get + * the BSD u_XXX types, such as u_int and u_short, defined. We + * define _DEFAULT_SOURCE first, so that newer versions of GNU libc + * don't whine about _BSD_SOURCE being deprecated; we still have + * to define _BSD_SOURCE to handle older versions of GNU libc that + * don't support _DEFAULT_SOURCE. + * + * But, if it's already defined, don't define it, so that we don't + * get a warning of it being redefined if it's defined as, for + * example, 1. + */ + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + /* Avoid redefining _BSD_SOURCE if it's already defined as for ex. 1 */ + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif +#endif + +#endif diff --git a/src/libpcap-1.10.5/gencode.c b/src/libpcap-1.10.5/gencode.c new file mode 100644 index 0000000000..31c50a71e3 --- /dev/null +++ b/src/libpcap-1.10.5/gencode.c @@ -0,0 +1,10261 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#ifdef _WIN32 + #include +#else + #include + + #ifdef __NetBSD__ + #include + #endif + + #include + #include +#endif /* _WIN32 */ + +#include +#include +#include +#include +#include +#include + +#ifdef MSDOS +#include "pcap-dos.h" +#endif + +#include "pcap-int.h" + +#include "extract.h" + +#include "ethertype.h" +#include "nlpid.h" +#include "llc.h" +#include "gencode.h" +#include "ieee80211.h" +#include "atmuni31.h" +#include "sunatmpos.h" +#include "pflog.h" +#include "ppp.h" +#include "pcap/sll.h" +#include "pcap/ipnet.h" +#include "arcnet.h" +#include "diag-control.h" + +#include "scanner.h" + +#if defined(__linux__) +#include +#include +#include +#endif + +#ifndef offsetof +#define offsetof(s, e) ((size_t)&((s *)0)->e) +#endif + +#ifdef _WIN32 + #ifdef INET6 + #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +typedef unsigned short sa_family_t; + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + uint16_t sin6_port; /* Transport layer port # */ + uint32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + + #ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; + #endif /* EAI_ADDRFAMILY */ + #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */ + #endif /* INET6 */ +#else /* _WIN32 */ + #include /* for "struct addrinfo" */ +#endif /* _WIN32 */ +#include + +#include "nametoaddr.h" + +#define ETHERMTU 1500 + +#ifndef IPPROTO_HOPOPTS +#define IPPROTO_HOPOPTS 0 +#endif +#ifndef IPPROTO_ROUTING +#define IPPROTO_ROUTING 43 +#endif +#ifndef IPPROTO_FRAGMENT +#define IPPROTO_FRAGMENT 44 +#endif +#ifndef IPPROTO_DSTOPTS +#define IPPROTO_DSTOPTS 60 +#endif +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +#define GENEVE_PORT 6081 + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#define JMP(c) ((c)|BPF_JMP|BPF_K) + +/* + * "Push" the current value of the link-layer header type and link-layer + * header offset onto a "stack", and set a new value. (It's not a + * full-blown stack; we keep only the top two items.) + */ +#define PUSH_LINKHDR(cs, new_linktype, new_is_variable, new_constant_part, new_reg) \ +{ \ + (cs)->prevlinktype = (cs)->linktype; \ + (cs)->off_prevlinkhdr = (cs)->off_linkhdr; \ + (cs)->linktype = (new_linktype); \ + (cs)->off_linkhdr.is_variable = (new_is_variable); \ + (cs)->off_linkhdr.constant_part = (new_constant_part); \ + (cs)->off_linkhdr.reg = (new_reg); \ + (cs)->is_geneve = 0; \ +} + +/* + * Offset "not set" value. + */ +#define OFFSET_NOT_SET 0xffffffffU + +/* + * Absolute offsets, which are offsets from the beginning of the raw + * packet data, are, in the general case, the sum of a variable value + * and a constant value; the variable value may be absent, in which + * case the offset is only the constant value, and the constant value + * may be zero, in which case the offset is only the variable value. + * + * bpf_abs_offset is a structure containing all that information: + * + * is_variable is 1 if there's a variable part. + * + * constant_part is the constant part of the value, possibly zero; + * + * if is_variable is 1, reg is the register number for a register + * containing the variable value if the register has been assigned, + * and -1 otherwise. + */ +typedef struct { + int is_variable; + u_int constant_part; + int reg; +} bpf_abs_offset; + +/* + * Value passed to gen_load_a() to indicate what the offset argument + * is relative to the beginning of. + */ +enum e_offrel { + OR_PACKET, /* full packet data */ + OR_LINKHDR, /* link-layer header */ + OR_PREVLINKHDR, /* previous link-layer header */ + OR_LLC, /* 802.2 LLC header */ + OR_PREVMPLSHDR, /* previous MPLS header */ + OR_LINKTYPE, /* link-layer type */ + OR_LINKPL, /* link-layer payload */ + OR_LINKPL_NOSNAP, /* link-layer payload, with no SNAP header at the link layer */ + OR_TRAN_IPV4, /* transport-layer header, with IPv4 network layer */ + OR_TRAN_IPV6 /* transport-layer header, with IPv6 network layer */ +}; + +/* + * We divvy out chunks of memory rather than call malloc each time so + * we don't have to worry about leaking memory. It's probably + * not a big deal if all this memory was wasted but if this ever + * goes into a library that would probably not be a good idea. + * + * XXX - this *is* in a library.... + */ +#define NCHUNKS 16 +#define CHUNK0SIZE 1024 +struct chunk { + size_t n_left; + void *m; +}; + +/* Code generator state */ + +struct _compiler_state { + jmp_buf top_ctx; + pcap_t *bpf_pcap; + int error_set; + + struct icode ic; + + int snaplen; + + int linktype; + int prevlinktype; + int outermostlinktype; + + bpf_u_int32 netmask; + int no_optimize; + + /* Hack for handling VLAN and MPLS stacks. */ + u_int label_stack_depth; + u_int vlan_stack_depth; + + /* XXX */ + u_int pcap_fddipad; + + /* + * As errors are handled by a longjmp, anything allocated must + * be freed in the longjmp handler, so it must be reachable + * from that handler. + * + * One thing that's allocated is the result of pcap_nametoaddrinfo(); + * it must be freed with freeaddrinfo(). This variable points to + * any addrinfo structure that would need to be freed. + */ + struct addrinfo *ai; + + /* + * Another thing that's allocated is the result of pcap_ether_aton(); + * it must be freed with free(). This variable points to any + * address that would need to be freed. + */ + u_char *e; + + /* + * Various code constructs need to know the layout of the packet. + * These values give the necessary offsets from the beginning + * of the packet data. + */ + + /* + * Absolute offset of the beginning of the link-layer header. + */ + bpf_abs_offset off_linkhdr; + + /* + * If we're checking a link-layer header for a packet encapsulated + * in another protocol layer, this is the equivalent information + * for the previous layers' link-layer header from the beginning + * of the raw packet data. + */ + bpf_abs_offset off_prevlinkhdr; + + /* + * This is the equivalent information for the outermost layers' + * link-layer header. + */ + bpf_abs_offset off_outermostlinkhdr; + + /* + * Absolute offset of the beginning of the link-layer payload. + */ + bpf_abs_offset off_linkpl; + + /* + * "off_linktype" is the offset to information in the link-layer + * header giving the packet type. This is an absolute offset + * from the beginning of the packet. + * + * For Ethernet, it's the offset of the Ethernet type field; this + * means that it must have a value that skips VLAN tags. + * + * For link-layer types that always use 802.2 headers, it's the + * offset of the LLC header; this means that it must have a value + * that skips VLAN tags. + * + * For PPP, it's the offset of the PPP type field. + * + * For Cisco HDLC, it's the offset of the CHDLC type field. + * + * For BSD loopback, it's the offset of the AF_ value. + * + * For Linux cooked sockets, it's the offset of the type field. + * + * off_linktype.constant_part is set to OFFSET_NOT_SET for no + * encapsulation, in which case, IP is assumed. + */ + bpf_abs_offset off_linktype; + + /* + * TRUE if the link layer includes an ATM pseudo-header. + */ + int is_atm; + + /* + * TRUE if "geneve" appeared in the filter; it causes us to + * generate code that checks for a Geneve header and assume + * that later filters apply to the encapsulated payload. + */ + int is_geneve; + + /* + * TRUE if we need variable length part of VLAN offset + */ + int is_vlan_vloffset; + + /* + * These are offsets for the ATM pseudo-header. + */ + u_int off_vpi; + u_int off_vci; + u_int off_proto; + + /* + * These are offsets for the MTP2 fields. + */ + u_int off_li; + u_int off_li_hsl; + + /* + * These are offsets for the MTP3 fields. + */ + u_int off_sio; + u_int off_opc; + u_int off_dpc; + u_int off_sls; + + /* + * This is the offset of the first byte after the ATM pseudo_header, + * or -1 if there is no ATM pseudo-header. + */ + u_int off_payload; + + /* + * These are offsets to the beginning of the network-layer header. + * They are relative to the beginning of the link-layer payload + * (i.e., they don't include off_linkhdr.constant_part or + * off_linkpl.constant_part). + * + * If the link layer never uses 802.2 LLC: + * + * "off_nl" and "off_nl_nosnap" are the same. + * + * If the link layer always uses 802.2 LLC: + * + * "off_nl" is the offset if there's a SNAP header following + * the 802.2 header; + * + * "off_nl_nosnap" is the offset if there's no SNAP header. + * + * If the link layer is Ethernet: + * + * "off_nl" is the offset if the packet is an Ethernet II packet + * (we assume no 802.3+802.2+SNAP); + * + * "off_nl_nosnap" is the offset if the packet is an 802.3 packet + * with an 802.2 header following it. + */ + u_int off_nl; + u_int off_nl_nosnap; + + /* + * Here we handle simple allocation of the scratch registers. + * If too many registers are alloc'd, the allocator punts. + */ + int regused[BPF_MEMWORDS]; + int curreg; + + /* + * Memory chunks. + */ + struct chunk chunks[NCHUNKS]; + int cur_chunk; +}; + +/* + * For use by routines outside this file. + */ +/* VARARGS */ +void +bpf_set_error(compiler_state_t *cstate, const char *fmt, ...) +{ + va_list ap; + + /* + * If we've already set an error, don't override it. + * The lexical analyzer reports some errors by setting + * the error and then returning a LEX_ERROR token, which + * is not recognized by any grammar rule, and thus forces + * the parse to stop. We don't want the error reported + * by the lexical analyzer to be overwritten by the syntax + * error. + */ + if (!cstate->error_set) { + va_start(ap, fmt); + (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, + fmt, ap); + va_end(ap); + cstate->error_set = 1; + } +} + +/* + * For use *ONLY* in routines in this file. + */ +static void PCAP_NORETURN bpf_error(compiler_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + +/* VARARGS */ +static void PCAP_NORETURN +bpf_error(compiler_state_t *cstate, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)vsnprintf(cstate->bpf_pcap->errbuf, PCAP_ERRBUF_SIZE, + fmt, ap); + va_end(ap); + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ +#ifdef _AIX + PCAP_UNREACHABLE +#endif /* _AIX */ +} + +static int init_linktype(compiler_state_t *, pcap_t *); + +static void init_regs(compiler_state_t *); +static int alloc_reg(compiler_state_t *); +static void free_reg(compiler_state_t *, int); + +static void initchunks(compiler_state_t *cstate); +static void *newchunk_nolongjmp(compiler_state_t *cstate, size_t); +static void *newchunk(compiler_state_t *cstate, size_t); +static void freechunks(compiler_state_t *cstate); +static inline struct block *new_block(compiler_state_t *cstate, int); +static inline struct slist *new_stmt(compiler_state_t *cstate, int); +static struct block *gen_retblk(compiler_state_t *cstate, int); +static inline void syntax(compiler_state_t *cstate); + +static void backpatch(struct block *, struct block *); +static void merge(struct block *, struct block *); +static struct block *gen_cmp(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32); +static struct block *gen_cmp_gt(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32); +static struct block *gen_cmp_ge(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32); +static struct block *gen_cmp_lt(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32); +static struct block *gen_cmp_le(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32); +static struct block *gen_mcmp(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32, bpf_u_int32); +static struct block *gen_bcmp(compiler_state_t *, enum e_offrel, u_int, + u_int, const u_char *); +static struct block *gen_ncmp(compiler_state_t *, enum e_offrel, u_int, + u_int, bpf_u_int32, int, int, bpf_u_int32); +static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *, + u_int, u_int); +static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int, + u_int); +static struct slist *gen_loadx_iphdrlen(compiler_state_t *); +static struct block *gen_uncond(compiler_state_t *, int); +static inline struct block *gen_true(compiler_state_t *); +static inline struct block *gen_false(compiler_state_t *); +static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32); +static struct block *gen_ipnet_linktype(compiler_state_t *, bpf_u_int32); +static struct block *gen_linux_sll_linktype(compiler_state_t *, bpf_u_int32); +static struct slist *gen_load_pflog_llprefixlen(compiler_state_t *); +static struct slist *gen_load_prism_llprefixlen(compiler_state_t *); +static struct slist *gen_load_avs_llprefixlen(compiler_state_t *); +static struct slist *gen_load_radiotap_llprefixlen(compiler_state_t *); +static struct slist *gen_load_ppi_llprefixlen(compiler_state_t *); +static void insert_compute_vloffsets(compiler_state_t *, struct block *); +static struct slist *gen_abs_offset_varpart(compiler_state_t *, + bpf_abs_offset *); +static bpf_u_int32 ethertype_to_ppptype(bpf_u_int32); +static struct block *gen_linktype(compiler_state_t *, bpf_u_int32); +static struct block *gen_snap(compiler_state_t *, bpf_u_int32, bpf_u_int32); +static struct block *gen_llc_linktype(compiler_state_t *, bpf_u_int32); +static struct block *gen_hostop(compiler_state_t *, bpf_u_int32, bpf_u_int32, + int, bpf_u_int32, u_int, u_int); +#ifdef INET6 +static struct block *gen_hostop6(compiler_state_t *, struct in6_addr *, + struct in6_addr *, int, bpf_u_int32, u_int, u_int); +#endif +static struct block *gen_ahostop(compiler_state_t *, const u_char *, int); +static struct block *gen_ehostop(compiler_state_t *, const u_char *, int); +static struct block *gen_fhostop(compiler_state_t *, const u_char *, int); +static struct block *gen_thostop(compiler_state_t *, const u_char *, int); +static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int); +static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int); +static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int); +static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32); +static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32, + int, int, int); +#ifdef INET6 +static struct block *gen_host6(compiler_state_t *, struct in6_addr *, + struct in6_addr *, int, int, int); +#endif +#ifndef INET6 +static struct block *gen_gateway(compiler_state_t *, const u_char *, + struct addrinfo *, int, int); +#endif +static struct block *gen_ipfrag(compiler_state_t *); +static struct block *gen_portatom(compiler_state_t *, int, bpf_u_int32); +static struct block *gen_portrangeatom(compiler_state_t *, u_int, bpf_u_int32, + bpf_u_int32); +static struct block *gen_portatom6(compiler_state_t *, int, bpf_u_int32); +static struct block *gen_portrangeatom6(compiler_state_t *, u_int, bpf_u_int32, + bpf_u_int32); +static struct block *gen_portop(compiler_state_t *, u_int, u_int, int); +static struct block *gen_port(compiler_state_t *, u_int, int, int); +static struct block *gen_portrangeop(compiler_state_t *, u_int, u_int, + bpf_u_int32, int); +static struct block *gen_portrange(compiler_state_t *, u_int, u_int, int, int); +struct block *gen_portop6(compiler_state_t *, u_int, u_int, int); +static struct block *gen_port6(compiler_state_t *, u_int, int, int); +static struct block *gen_portrangeop6(compiler_state_t *, u_int, u_int, + bpf_u_int32, int); +static struct block *gen_portrange6(compiler_state_t *, u_int, u_int, int, int); +static int lookup_proto(compiler_state_t *, const char *, int); +#if !defined(NO_PROTOCHAIN) +static struct block *gen_protochain(compiler_state_t *, bpf_u_int32, int); +#endif /* !defined(NO_PROTOCHAIN) */ +static struct block *gen_proto(compiler_state_t *, bpf_u_int32, int, int); +static struct slist *xfer_to_x(compiler_state_t *, struct arth *); +static struct slist *xfer_to_a(compiler_state_t *, struct arth *); +static struct block *gen_mac_multicast(compiler_state_t *, int); +static struct block *gen_len(compiler_state_t *, int, int); +static struct block *gen_check_802_11_data_frame(compiler_state_t *); +static struct block *gen_geneve_ll_check(compiler_state_t *cstate); + +static struct block *gen_ppi_dlt_check(compiler_state_t *); +static struct block *gen_atmfield_code_internal(compiler_state_t *, int, + bpf_u_int32, int, int); +static struct block *gen_atmtype_llc(compiler_state_t *); +static struct block *gen_msg_abbrev(compiler_state_t *, int type); + +static void +initchunks(compiler_state_t *cstate) +{ + int i; + + for (i = 0; i < NCHUNKS; i++) { + cstate->chunks[i].n_left = 0; + cstate->chunks[i].m = NULL; + } + cstate->cur_chunk = 0; +} + +static void * +newchunk_nolongjmp(compiler_state_t *cstate, size_t n) +{ + struct chunk *cp; + int k; + size_t size; + +#ifndef __NetBSD__ + /* XXX Round up to nearest long. */ + n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); +#else + /* XXX Round up to structure boundary. */ + n = ALIGN(n); +#endif + + cp = &cstate->chunks[cstate->cur_chunk]; + if (n > cp->n_left) { + ++cp; + k = ++cstate->cur_chunk; + if (k >= NCHUNKS) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } + size = CHUNK0SIZE << k; + cp->m = (void *)malloc(size); + if (cp->m == NULL) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } + memset((char *)cp->m, 0, size); + cp->n_left = size; + if (n > size) { + bpf_set_error(cstate, "out of memory"); + return (NULL); + } + } + cp->n_left -= n; + return (void *)((char *)cp->m + cp->n_left); +} + +static void * +newchunk(compiler_state_t *cstate, size_t n) +{ + void *p; + + p = newchunk_nolongjmp(cstate, n); + if (p == NULL) { + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + } + return (p); +} + +static void +freechunks(compiler_state_t *cstate) +{ + int i; + + for (i = 0; i < NCHUNKS; ++i) + if (cstate->chunks[i].m != NULL) + free(cstate->chunks[i].m); +} + +/* + * A strdup whose allocations are freed after code generation is over. + * This is used by the lexical analyzer, so it can't longjmp; it just + * returns NULL on an allocation error, and the callers must check + * for it. + */ +char * +sdup(compiler_state_t *cstate, const char *s) +{ + size_t n = strlen(s) + 1; + char *cp = newchunk_nolongjmp(cstate, n); + + if (cp == NULL) + return (NULL); + pcapint_strlcpy(cp, s, n); + return (cp); +} + +static inline struct block * +new_block(compiler_state_t *cstate, int code) +{ + struct block *p; + + p = (struct block *)newchunk(cstate, sizeof(*p)); + p->s.code = code; + p->head = p; + + return p; +} + +static inline struct slist * +new_stmt(compiler_state_t *cstate, int code) +{ + struct slist *p; + + p = (struct slist *)newchunk(cstate, sizeof(*p)); + p->s.code = code; + + return p; +} + +static struct block * +gen_retblk(compiler_state_t *cstate, int v) +{ + struct block *b = new_block(cstate, BPF_RET|BPF_K); + + b->s.k = v; + return b; +} + +static inline PCAP_NORETURN_DEF void +syntax(compiler_state_t *cstate) +{ + bpf_error(cstate, "syntax error in filter expression"); +} + +int +pcap_compile(pcap_t *p, struct bpf_program *program, + const char *buf, int optimize, bpf_u_int32 mask) +{ +#ifdef _WIN32 + static int done = 0; +#endif + compiler_state_t cstate; + const char * volatile xbuf = buf; + yyscan_t scanner = NULL; + volatile YY_BUFFER_STATE in_buffer = NULL; + u_int len; + int rc; + + /* + * If this pcap_t hasn't been activated, it doesn't have a + * link-layer type, so we can't use it. + */ + if (!p->activated) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "not-yet-activated pcap_t passed to pcap_compile"); + return (PCAP_ERROR); + } + +#ifdef _WIN32 + if (!done) { + pcap_wsockinit(); + done = 1; + } +#endif + +#ifdef ENABLE_REMOTE + /* + * If the device on which we're capturing need to be notified + * that a new filter is being compiled, do so. + * + * This allows them to save a copy of it, in case, for example, + * they're implementing a form of remote packet capture, and + * want the remote machine to filter out the packets in which + * it's sending the packets it's captured. + * + * XXX - the fact that we happen to be compiling a filter + * doesn't necessarily mean we'll be installing it as the + * filter for this pcap_t; we might be running it from userland + * on captured packets to do packet classification. We really + * need a better way of handling this, but this is all that + * the WinPcap remote capture code did. + */ + if (p->save_current_filter_op != NULL) + (p->save_current_filter_op)(p, buf); +#endif + + initchunks(&cstate); + cstate.no_optimize = 0; +#ifdef INET6 + cstate.ai = NULL; +#endif + cstate.e = NULL; + cstate.ic.root = NULL; + cstate.ic.cur_mark = 0; + cstate.bpf_pcap = p; + cstate.error_set = 0; + init_regs(&cstate); + + cstate.netmask = mask; + + cstate.snaplen = pcap_snapshot(p); + if (cstate.snaplen == 0) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snaplen of 0 rejects all packets"); + rc = PCAP_ERROR; + goto quit; + } + + if (pcap_lex_init(&scanner) != 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't initialize scanner"); + rc = PCAP_ERROR; + goto quit; + } + in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); + + /* + * Associate the compiler state with the lexical analyzer + * state. + */ + pcap_set_extra(&cstate, scanner); + + if (init_linktype(&cstate, p) == -1) { + rc = PCAP_ERROR; + goto quit; + } + if (pcap_parse(scanner, &cstate) != 0) { +#ifdef INET6 + if (cstate.ai != NULL) + freeaddrinfo(cstate.ai); +#endif + if (cstate.e != NULL) + free(cstate.e); + rc = PCAP_ERROR; + goto quit; + } + + if (cstate.ic.root == NULL) { + /* + * Catch errors reported by gen_retblk(). + */ + if (setjmp(cstate.top_ctx)) { + rc = PCAP_ERROR; + goto quit; + } + cstate.ic.root = gen_retblk(&cstate, cstate.snaplen); + } + + if (optimize && !cstate.no_optimize) { + if (bpf_optimize(&cstate.ic, p->errbuf) == -1) { + /* Failure */ + rc = PCAP_ERROR; + goto quit; + } + if (cstate.ic.root == NULL || + (cstate.ic.root->s.code == (BPF_RET|BPF_K) && cstate.ic.root->s.k == 0)) { + (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "expression rejects all packets"); + rc = PCAP_ERROR; + goto quit; + } + } + program->bf_insns = icode_to_fcode(&cstate.ic, + cstate.ic.root, &len, p->errbuf); + if (program->bf_insns == NULL) { + /* Failure */ + rc = PCAP_ERROR; + goto quit; + } + program->bf_len = len; + + rc = 0; /* We're all okay */ + +quit: + /* + * Clean up everything for the lexical analyzer. + */ + if (in_buffer != NULL) + pcap__delete_buffer(in_buffer, scanner); + if (scanner != NULL) + pcap_lex_destroy(scanner); + + /* + * Clean up our own allocated memory. + */ + freechunks(&cstate); + + return (rc); +} + +/* + * entry point for using the compiler with no pcap open + * pass in all the stuff that is needed explicitly instead. + */ +int +pcap_compile_nopcap(int snaplen_arg, int linktype_arg, + struct bpf_program *program, + const char *buf, int optimize, bpf_u_int32 mask) +{ + pcap_t *p; + int ret; + + p = pcap_open_dead(linktype_arg, snaplen_arg); + if (p == NULL) + return (PCAP_ERROR); + ret = pcap_compile(p, program, buf, optimize, mask); + pcap_close(p); + return (ret); +} + +/* + * Clean up a "struct bpf_program" by freeing all the memory allocated + * in it. + */ +void +pcap_freecode(struct bpf_program *program) +{ + program->bf_len = 0; + if (program->bf_insns != NULL) { + free((char *)program->bf_insns); + program->bf_insns = NULL; + } +} + +/* + * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates + * which of the jt and jf fields has been resolved and which is a pointer + * back to another unresolved block (or nil). At least one of the fields + * in each block is already resolved. + */ +static void +backpatch(struct block *list, struct block *target) +{ + struct block *next; + + while (list) { + if (!list->sense) { + next = JT(list); + JT(list) = target; + } else { + next = JF(list); + JF(list) = target; + } + list = next; + } +} + +/* + * Merge the lists in b0 and b1, using the 'sense' field to indicate + * which of jt and jf is the link. + */ +static void +merge(struct block *b0, struct block *b1) +{ + register struct block **p = &b0; + + /* Find end of list. */ + while (*p) + p = !((*p)->sense) ? &JT(*p) : &JF(*p); + + /* Concatenate the lists. */ + *p = b1; +} + +int +finish_parse(compiler_state_t *cstate, struct block *p) +{ + struct block *ppi_dlt_check; + + /* + * Catch errors reported by us and routines below us, and return -1 + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (-1); + + /* + * Insert before the statements of the first (root) block any + * statements needed to load the lengths of any variable-length + * headers into registers. + * + * XXX - a fancier strategy would be to insert those before the + * statements of all blocks that use those lengths and that + * have no predecessors that use them, so that we only compute + * the lengths if we need them. There might be even better + * approaches than that. + * + * However, those strategies would be more complicated, and + * as we don't generate code to compute a length if the + * program has no tests that use the length, and as most + * tests will probably use those lengths, we would just + * postpone computing the lengths so that it's not done + * for tests that fail early, and it's not clear that's + * worth the effort. + */ + insert_compute_vloffsets(cstate, p->head); + + /* + * For DLT_PPI captures, generate a check of the per-packet + * DLT value to make sure it's DLT_IEEE802_11. + * + * XXX - TurboCap cards use DLT_PPI for Ethernet. + * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header + * with appropriate Ethernet information and use that rather + * than using something such as DLT_PPI where you don't know + * the link-layer header type until runtime, which, in the + * general case, would force us to generate both Ethernet *and* + * 802.11 code (*and* anything else for which PPI is used) + * and choose between them early in the BPF program? + */ + ppi_dlt_check = gen_ppi_dlt_check(cstate); + if (ppi_dlt_check != NULL) + gen_and(ppi_dlt_check, p); + + backpatch(p, gen_retblk(cstate, cstate->snaplen)); + p->sense = !p->sense; + backpatch(p, gen_retblk(cstate, 0)); + cstate->ic.root = p->head; + return (0); +} + +void +gen_and(struct block *b0, struct block *b1) +{ + backpatch(b0, b1->head); + b0->sense = !b0->sense; + b1->sense = !b1->sense; + merge(b1, b0); + b1->sense = !b1->sense; + b1->head = b0->head; +} + +void +gen_or(struct block *b0, struct block *b1) +{ + b0->sense = !b0->sense; + backpatch(b0, b1->head); + b0->sense = !b0->sense; + merge(b1, b0); + b1->head = b0->head; +} + +void +gen_not(struct block *b) +{ + b->sense = !b->sense; +} + +static struct block * +gen_cmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v) +{ + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JEQ, 0, v); +} + +static struct block * +gen_cmp_gt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v) +{ + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 0, v); +} + +static struct block * +gen_cmp_ge(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v) +{ + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 0, v); +} + +static struct block * +gen_cmp_lt(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v) +{ + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGE, 1, v); +} + +static struct block * +gen_cmp_le(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v) +{ + return gen_ncmp(cstate, offrel, offset, size, 0xffffffff, BPF_JGT, 1, v); +} + +static struct block * +gen_mcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 v, bpf_u_int32 mask) +{ + return gen_ncmp(cstate, offrel, offset, size, mask, BPF_JEQ, 0, v); +} + +static struct block * +gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, const u_char *v) +{ + register struct block *b, *tmp; + + b = NULL; + while (size >= 4) { + register const u_char *p = &v[size - 4]; + + tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, + EXTRACT_BE_U_4(p)); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + size -= 4; + } + while (size >= 2) { + register const u_char *p = &v[size - 2]; + + tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, + EXTRACT_BE_U_2(p)); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + size -= 2; + } + if (size > 0) { + tmp = gen_cmp(cstate, offrel, offset, BPF_B, v[0]); + if (b != NULL) + gen_and(b, tmp); + b = tmp; + } + return b; +} + +/* + * AND the field of size "size" at offset "offset" relative to the header + * specified by "offrel" with "mask", and compare it with the value "v" + * with the test specified by "jtype"; if "reverse" is true, the test + * should test the opposite of "jtype". + */ +static struct block * +gen_ncmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size, bpf_u_int32 mask, int jtype, int reverse, + bpf_u_int32 v) +{ + struct slist *s, *s2; + struct block *b; + + s = gen_load_a(cstate, offrel, offset, size); + + if (mask != 0xffffffff) { + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + s2->s.k = mask; + sappend(s, s2); + } + + b = new_block(cstate, JMP(jtype)); + b->stmts = s; + b->s.k = v; + if (reverse && (jtype == BPF_JGT || jtype == BPF_JGE)) + gen_not(b); + return b; +} + +static int +init_linktype(compiler_state_t *cstate, pcap_t *p) +{ + cstate->pcap_fddipad = p->fddipad; + + /* + * We start out with only one link-layer header. + */ + cstate->outermostlinktype = pcap_datalink(p); + cstate->off_outermostlinkhdr.constant_part = 0; + cstate->off_outermostlinkhdr.is_variable = 0; + cstate->off_outermostlinkhdr.reg = -1; + + cstate->prevlinktype = cstate->outermostlinktype; + cstate->off_prevlinkhdr.constant_part = 0; + cstate->off_prevlinkhdr.is_variable = 0; + cstate->off_prevlinkhdr.reg = -1; + + cstate->linktype = cstate->outermostlinktype; + cstate->off_linkhdr.constant_part = 0; + cstate->off_linkhdr.is_variable = 0; + cstate->off_linkhdr.reg = -1; + + /* + * XXX + */ + cstate->off_linkpl.constant_part = 0; + cstate->off_linkpl.is_variable = 0; + cstate->off_linkpl.reg = -1; + + cstate->off_linktype.constant_part = 0; + cstate->off_linktype.is_variable = 0; + cstate->off_linktype.reg = -1; + + /* + * Assume it's not raw ATM with a pseudo-header, for now. + */ + cstate->is_atm = 0; + cstate->off_vpi = OFFSET_NOT_SET; + cstate->off_vci = OFFSET_NOT_SET; + cstate->off_proto = OFFSET_NOT_SET; + cstate->off_payload = OFFSET_NOT_SET; + + /* + * And not Geneve. + */ + cstate->is_geneve = 0; + + /* + * No variable length VLAN offset by default + */ + cstate->is_vlan_vloffset = 0; + + /* + * And assume we're not doing SS7. + */ + cstate->off_li = OFFSET_NOT_SET; + cstate->off_li_hsl = OFFSET_NOT_SET; + cstate->off_sio = OFFSET_NOT_SET; + cstate->off_opc = OFFSET_NOT_SET; + cstate->off_dpc = OFFSET_NOT_SET; + cstate->off_sls = OFFSET_NOT_SET; + + cstate->label_stack_depth = 0; + cstate->vlan_stack_depth = 0; + + switch (cstate->linktype) { + + case DLT_ARCNET: + cstate->off_linktype.constant_part = 2; + cstate->off_linkpl.constant_part = 6; + cstate->off_nl = 0; /* XXX in reality, variable! */ + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_ARCNET_LINUX: + cstate->off_linktype.constant_part = 4; + cstate->off_linkpl.constant_part = 8; + cstate->off_nl = 0; /* XXX in reality, variable! */ + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_EN10MB: + cstate->off_linktype.constant_part = 12; + cstate->off_linkpl.constant_part = 14; /* Ethernet header length */ + cstate->off_nl = 0; /* Ethernet II */ + cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case DLT_SLIP: + /* + * SLIP doesn't have a link level type. The 16 byte + * header is hacked into our SLIP driver. + */ + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 16; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_SLIP_BSDOS: + /* XXX this may be the same as the DLT_PPP_BSDOS case */ + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + /* XXX end */ + cstate->off_linkpl.constant_part = 24; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_NULL: + case DLT_LOOP: + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 4; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_ENC: + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 12; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP: + case DLT_PPP_PPPD: + case DLT_C_HDLC: /* BSD/OS Cisco HDLC */ + case DLT_HDLC: /* NetBSD (Cisco) HDLC */ + case DLT_PPP_SERIAL: /* NetBSD sync/async serial PPP */ + cstate->off_linktype.constant_part = 2; /* skip HDLC-like framing */ + cstate->off_linkpl.constant_part = 4; /* skip HDLC-like framing and protocol field */ + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP_ETHER: + /* + * This does no include the Ethernet header, and + * only covers session state. + */ + cstate->off_linktype.constant_part = 6; + cstate->off_linkpl.constant_part = 8; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_PPP_BSDOS: + cstate->off_linktype.constant_part = 5; + cstate->off_linkpl.constant_part = 24; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_FDDI: + /* + * FDDI doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + */ + cstate->off_linktype.constant_part = 13; + cstate->off_linktype.constant_part += cstate->pcap_fddipad; + cstate->off_linkpl.constant_part = 13; /* FDDI MAC header length */ + cstate->off_linkpl.constant_part += cstate->pcap_fddipad; + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_IEEE802: + /* + * Token Ring doesn't really have a link-level type field. + * We set "off_linktype" to the offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * XXX - the header is actually variable-length. + * Some various Linux patched versions gave 38 + * as "off_linktype" and 40 as "off_nl"; however, + * if a token ring packet has *no* routing + * information, i.e. is not source-routed, the correct + * values are 20 and 22, as they are in the vanilla code. + * + * A packet is source-routed iff the uppermost bit + * of the first byte of the source address, at an + * offset of 8, has the uppermost bit set. If the + * packet is source-routed, the total number of bytes + * of routing information is 2 plus bits 0x1F00 of + * the 16-bit value at an offset of 14 (shifted right + * 8 - figure out which byte that is). + */ + cstate->off_linktype.constant_part = 14; + cstate->off_linkpl.constant_part = 14; /* Token Ring MAC header length */ + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + cstate->off_linkhdr.is_variable = 1; + /* Fall through, 802.11 doesn't have a variable link + * prefix but is otherwise the same. */ + /* FALLTHROUGH */ + + case DLT_IEEE802_11: + /* + * 802.11 doesn't really have a link-level type field. + * We set "off_linktype.constant_part" to the offset of + * the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? + * + * We also handle variable-length radio headers here. + * The Prism header is in theory variable-length, but in + * practice it's always 144 bytes long. However, some + * drivers on Linux use ARPHRD_IEEE80211_PRISM, but + * sometimes or always supply an AVS header, so we + * have to check whether the radio header is a Prism + * header or an AVS header, so, in practice, it's + * variable-length. + */ + cstate->off_linktype.constant_part = 24; + cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ + cstate->off_linkpl.is_variable = 1; + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_PPI: + /* + * At the moment we treat PPI the same way that we treat + * normal Radiotap encoded packets. The difference is in + * the function that generates the code at the beginning + * to compute the header length. Since this code generator + * of PPI supports bare 802.11 encapsulation only (i.e. + * the encapsulated DLT should be DLT_IEEE802_11) we + * generate code to check for this too. + */ + cstate->off_linktype.constant_part = 24; + cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ + cstate->off_linkpl.is_variable = 1; + cstate->off_linkhdr.is_variable = 1; + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: /* Linux ATM defines this */ + /* + * assume routed, non-ISO PDUs + * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) + * + * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, + * or PPP with the PPP NLPID (e.g., PPPoA)? The + * latter would presumably be treated the way PPPoE + * should be, so you can do "pppoe and udp port 2049" + * or "pppoa and tcp port 80" and have it check for + * PPPo{A,E} and a PPP protocol of IP and.... + */ + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 0; /* packet begins with LLC header */ + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_SUNATM: + /* + * Full Frontal ATM; you get AALn PDUs with an ATM + * pseudo-header. + */ + cstate->is_atm = 1; + cstate->off_vpi = SUNATM_VPI_POS; + cstate->off_vci = SUNATM_VCI_POS; + cstate->off_proto = PROTO_POS; + cstate->off_payload = SUNATM_PKT_BEGIN_POS; + cstate->off_linktype.constant_part = cstate->off_payload; + cstate->off_linkpl.constant_part = cstate->off_payload; /* if LLC-encapsulated */ + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_RAW: + case DLT_IPV4: + case DLT_IPV6: + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 0; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */ + cstate->off_linktype.constant_part = 14; + cstate->off_linkpl.constant_part = 16; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */ + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 20; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_LTALK: + /* + * LocalTalk does have a 1-byte type field in the LLAP header, + * but really it just indicates whether there is a "short" or + * "long" DDP packet following. + */ + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 0; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_IP_OVER_FC: + /* + * RFC 2625 IP-over-Fibre-Channel doesn't really have a + * link-level type field. We set "off_linktype" to the + * offset of the LLC header. + * + * To check for Ethernet types, we assume that SSAP = SNAP + * is being used and pick out the encapsulated Ethernet type. + * XXX - should we generate code to check for SNAP? RFC + * 2625 says SNAP should be used. + */ + cstate->off_linktype.constant_part = 16; + cstate->off_linkpl.constant_part = 16; + cstate->off_nl = 8; /* 802.2+SNAP */ + cstate->off_nl_nosnap = 3; /* 802.2 */ + break; + + case DLT_FRELAY: + /* + * XXX - we should set this to handle SNAP-encapsulated + * frames (NLPID of 0x80). + */ + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 0; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + /* + * the only BPF-interesting FRF.16 frames are non-control frames; + * Frame Relay has a variable length link-layer + * so lets start with offset 4 for now and increments later on (FIXME); + */ + case DLT_MFR: + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 0; + cstate->off_nl = 4; + cstate->off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ + break; + + case DLT_APPLE_IP_OVER_IEEE1394: + cstate->off_linktype.constant_part = 16; + cstate->off_linkpl.constant_part = 18; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_SYMANTEC_FIREWALL: + cstate->off_linktype.constant_part = 6; + cstate->off_linkpl.constant_part = 44; + cstate->off_nl = 0; /* Ethernet II */ + cstate->off_nl_nosnap = 0; /* XXX - what does it do with 802.3 packets? */ + break; + + case DLT_PFLOG: + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 0; /* link-layer header is variable-length */ + cstate->off_linkpl.is_variable = 1; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_FRELAY: + cstate->off_linktype.constant_part = 4; + cstate->off_linkpl.constant_part = 4; + cstate->off_nl = 0; + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_ATM1: + cstate->off_linktype.constant_part = 4; /* in reality variable between 4-8 */ + cstate->off_linkpl.constant_part = 4; /* in reality variable between 4-8 */ + cstate->off_nl = 0; + cstate->off_nl_nosnap = 10; + break; + + case DLT_JUNIPER_ATM2: + cstate->off_linktype.constant_part = 8; /* in reality variable between 8-12 */ + cstate->off_linkpl.constant_part = 8; /* in reality variable between 8-12 */ + cstate->off_nl = 0; + cstate->off_nl_nosnap = 10; + break; + + /* frames captured on a Juniper PPPoE service PIC + * contain raw ethernet frames */ + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_ETHER: + cstate->off_linkpl.constant_part = 14; + cstate->off_linktype.constant_part = 16; + cstate->off_nl = 18; /* Ethernet II */ + cstate->off_nl_nosnap = 21; /* 802.3+802.2 */ + break; + + case DLT_JUNIPER_PPPOE_ATM: + cstate->off_linktype.constant_part = 4; + cstate->off_linkpl.constant_part = 6; + cstate->off_nl = 0; + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_GGSN: + cstate->off_linktype.constant_part = 6; + cstate->off_linkpl.constant_part = 12; + cstate->off_nl = 0; + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_ES: + cstate->off_linktype.constant_part = 6; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ + cstate->off_nl = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_MONITOR: + cstate->off_linktype.constant_part = 12; + cstate->off_linkpl.constant_part = 12; + cstate->off_nl = 0; /* raw IP/IP6 header */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_BACNET_MS_TP: + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_JUNIPER_SERVICES: + cstate->off_linktype.constant_part = 12; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ + cstate->off_nl = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_JUNIPER_VP: + cstate->off_linktype.constant_part = 18; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_JUNIPER_ST: + cstate->off_linktype.constant_part = 18; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_JUNIPER_ISM: + cstate->off_linktype.constant_part = 8; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + cstate->off_linktype.constant_part = 8; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_MTP2: + cstate->off_li = 2; + cstate->off_li_hsl = 4; + cstate->off_sio = 3; + cstate->off_opc = 4; + cstate->off_dpc = 4; + cstate->off_sls = 7; + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_MTP2_WITH_PHDR: + cstate->off_li = 6; + cstate->off_li_hsl = 8; + cstate->off_sio = 7; + cstate->off_opc = 8; + cstate->off_dpc = 8; + cstate->off_sls = 11; + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_ERF: + cstate->off_li = 22; + cstate->off_li_hsl = 24; + cstate->off_sio = 23; + cstate->off_opc = 24; + cstate->off_dpc = 24; + cstate->off_sls = 27; + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_PFSYNC: + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = 4; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; + break; + + case DLT_AX25_KISS: + /* + * Currently, only raw "link[N:M]" filtering is supported. + */ + cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */ + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; /* variable, min 16, max 71 steps of 7 */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ + break; + + case DLT_IPNET: + cstate->off_linktype.constant_part = 1; + cstate->off_linkpl.constant_part = 24; /* ipnet header length */ + cstate->off_nl = 0; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + break; + + case DLT_NETANALYZER: + cstate->off_linkhdr.constant_part = 4; /* Ethernet header is past 4-byte pseudo-header */ + cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; + cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+Ethernet header length */ + cstate->off_nl = 0; /* Ethernet II */ + cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case DLT_NETANALYZER_TRANSPARENT: + cstate->off_linkhdr.constant_part = 12; /* MAC header is past 4-byte pseudo-header, preamble, and SFD */ + cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; + cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* pseudo-header+preamble+SFD+Ethernet header length */ + cstate->off_nl = 0; /* Ethernet II */ + cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + default: + /* + * For values in the range in which we've assigned new + * DLT_ values, only raw "link[N:M]" filtering is supported. + */ + if (cstate->linktype >= DLT_HIGH_MATCHING_MIN && + cstate->linktype <= DLT_HIGH_MATCHING_MAX) { + cstate->off_linktype.constant_part = OFFSET_NOT_SET; + cstate->off_linkpl.constant_part = OFFSET_NOT_SET; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; + } else { + bpf_set_error(cstate, "unknown data link type %d (min %d, max %d)", + cstate->linktype, DLT_HIGH_MATCHING_MIN, DLT_HIGH_MATCHING_MAX); + return (-1); + } + break; + } + + cstate->off_outermostlinkhdr = cstate->off_prevlinkhdr = cstate->off_linkhdr; + return (0); +} + +/* + * Load a value relative to the specified absolute offset. + */ +static struct slist * +gen_load_absoffsetrel(compiler_state_t *cstate, bpf_abs_offset *abs_offset, + u_int offset, u_int size) +{ + struct slist *s, *s2; + + s = gen_abs_offset_varpart(cstate, abs_offset); + + /* + * If "s" is non-null, it has code to arrange that the X register + * contains the variable part of the absolute offset, so we + * generate a load relative to that, with an offset of + * abs_offset->constant_part + offset. + * + * Otherwise, we can do an absolute load with an offset of + * abs_offset->constant_part + offset. + */ + if (s != NULL) { + /* + * "s" points to a list of statements that puts the + * variable part of the absolute offset into the X register. + * Do an indirect load, to use the X register as an offset. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); + s2->s.k = abs_offset->constant_part + offset; + sappend(s, s2); + } else { + /* + * There is no variable part of the absolute offset, so + * just do an absolute load. + */ + s = new_stmt(cstate, BPF_LD|BPF_ABS|size); + s->s.k = abs_offset->constant_part + offset; + } + return s; +} + +/* + * Load a value relative to the beginning of the specified header. + */ +static struct slist * +gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, + u_int size) +{ + struct slist *s, *s2; + + /* + * Squelch warnings from compilers that *don't* assume that + * offrel always has a valid enum value and therefore don't + * assume that we'll always go through one of the case arms. + * + * If we have a default case, compilers that *do* assume that + * will then complain about the default case code being + * unreachable. + * + * Damned if you do, damned if you don't. + */ + s = NULL; + + switch (offrel) { + + case OR_PACKET: + s = new_stmt(cstate, BPF_LD|BPF_ABS|size); + s->s.k = offset; + break; + + case OR_LINKHDR: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkhdr, offset, size); + break; + + case OR_PREVLINKHDR: + s = gen_load_absoffsetrel(cstate, &cstate->off_prevlinkhdr, offset, size); + break; + + case OR_LLC: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, offset, size); + break; + + case OR_PREVMPLSHDR: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl - 4 + offset, size); + break; + + case OR_LINKPL: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + offset, size); + break; + + case OR_LINKPL_NOSNAP: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl_nosnap + offset, size); + break; + + case OR_LINKTYPE: + s = gen_load_absoffsetrel(cstate, &cstate->off_linktype, offset, size); + break; + + case OR_TRAN_IPV4: + /* + * Load the X register with the length of the IPv4 header + * (plus the offset of the link-layer header, if it's + * preceded by a variable-length header such as a radio + * header), in bytes. + */ + s = gen_loadx_iphdrlen(cstate); + + /* + * Load the item at {offset of the link-layer payload} + + * {offset, relative to the start of the link-layer + * payload, of the IPv4 header} + {length of the IPv4 header} + + * {specified offset}. + * + * If the offset of the link-layer payload is variable, + * the variable part of that offset is included in the + * value in the X register, and we include the constant + * part in the offset of the load. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_IND|size); + s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + offset; + sappend(s, s2); + break; + + case OR_TRAN_IPV6: + s = gen_load_absoffsetrel(cstate, &cstate->off_linkpl, cstate->off_nl + 40 + offset, size); + break; + } + return s; +} + +/* + * Generate code to load into the X register the sum of the length of + * the IPv4 header and the variable part of the offset of the link-layer + * payload. + */ +static struct slist * +gen_loadx_iphdrlen(compiler_state_t *cstate) +{ + struct slist *s, *s2; + + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); + if (s != NULL) { + /* + * The offset of the link-layer payload has a variable + * part. "s" points to a list of statements that put + * the variable part of that offset into the X register. + * + * The 4*([k]&0xf) addressing mode can't be used, as we + * don't have a constant offset, so we have to load the + * value in question into the A register and add to it + * the value from the X register. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s2->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + s2->s.k = 0xf; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); + s2->s.k = 2; + sappend(s, s2); + + /* + * The A register now contains the length of the IP header. + * We need to add to it the variable part of the offset of + * the link-layer payload, which is still in the X + * register, and move the result into the X register. + */ + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + } else { + /* + * The offset of the link-layer payload is a constant, + * so no code was generated to load the (nonexistent) + * variable part of that offset. + * + * This means we can use the 4*([k]&0xf) addressing + * mode. Load the length of the IPv4 header, which + * is at an offset of cstate->off_nl from the beginning of + * the link-layer payload, and thus at an offset of + * cstate->off_linkpl.constant_part + cstate->off_nl from the beginning + * of the raw packet data, using that addressing mode. + */ + s = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); + s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + } + return s; +} + + +static struct block * +gen_uncond(compiler_state_t *cstate, int rsense) +{ + struct block *b; + struct slist *s; + + s = new_stmt(cstate, BPF_LD|BPF_IMM); + s->s.k = !rsense; + b = new_block(cstate, JMP(BPF_JEQ)); + b->stmts = s; + + return b; +} + +static inline struct block * +gen_true(compiler_state_t *cstate) +{ + return gen_uncond(cstate, 1); +} + +static inline struct block * +gen_false(compiler_state_t *cstate) +{ + return gen_uncond(cstate, 0); +} + +/* + * Byte-swap a 32-bit number. + * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on + * big-endian platforms.) + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) + +/* + * Generate code to match a particular packet type. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the type/length field or to check the type/length field for + * a value <= ETHERMTU to see whether it's a type field and then do + * the appropriate test. + */ +static struct block * +gen_ether_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + struct block *b0, *b1; + + switch (ll_proto) { + + case LLCSAP_ISONS: + case LLCSAP_IP: + case LLCSAP_NETBEUI: + /* + * OSI protocols and NetBEUI always use 802.2 encapsulation, + * so we check the DSAP and SSAP. + * + * LLCSAP_IP checks for IP-over-802.2, rather + * than IP-over-Ethernet or IP-over-SNAP. + * + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other types <= ETHERMTU + * (i.e., other SAP values)? + */ + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Check for; + * + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which are 802.3 + * frames (i.e., the type/length field is + * a length field, <= ETHERMTU, rather than + * a type field) with the first two bytes + * after the Ethernet/802.3 header being + * 0xFFFF; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * XXX - should we generate the same code both + * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? + */ + + /* + * This generates code to check both for the + * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. + */ + b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF); + gen_or(b0, b1); + + /* + * Now we add code to check for SNAP frames with + * ETHERTYPE_IPX, i.e. Ethernet_SNAP. + */ + b0 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); + gen_or(b0, b1); + + /* + * Now we generate code to check for 802.3 + * frames in general. + */ + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * Now add the check for 802.3 frames before the + * check for Ethernet_802.2 and Ethernet_802.3, + * as those checks should only be done on 802.3 + * frames, not on Ethernet frames. + */ + gen_and(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for an Ethernet type field less than + * 1500, which means it's an 802.3 length field. + */ + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (ll_proto == ETHERTYPE_ATALK) + b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); + else /* ll_proto == ETHERTYPE_AARP */ + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + + gen_or(b0, b1); + return b1; + + default: + if (ll_proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check that the frame is an 802.2 frame + * (i.e., that the length/type field is + * a length field, <= ETHERMTU) and + * then check the DSAP. + */ + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + b1 = gen_cmp(cstate, OR_LINKTYPE, 2, BPF_B, ll_proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "ll_proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + } + } +} + +static struct block * +gen_loopback_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + /* + * For DLT_NULL, the link-layer header is a 32-bit word + * containing an AF_ value in *host* byte order, and for + * DLT_ENC, the link-layer header begins with a 32-bit + * word containing an AF_ value in host byte order. + * + * In addition, if we're reading a saved capture file, + * the host byte order in the capture may not be the + * same as the host byte order on this machine. + * + * For DLT_LOOP, the link-layer header is a 32-bit + * word containing an AF_ value in *network* byte order. + */ + if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) { + /* + * The AF_ value is in host byte order, but the BPF + * interpreter will convert it to network byte order. + * + * If this is a save file, and it's from a machine + * with the opposite byte order to ours, we byte-swap + * the AF_ value. + * + * Then we run it through "htonl()", and generate + * code to compare against the result. + */ + if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped) + ll_proto = SWAPLONG(ll_proto); + ll_proto = htonl(ll_proto); + } + return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, ll_proto)); +} + +/* + * "proto" is an Ethernet type value and for IPNET, if it is not IPv4 + * or IPv6 then we have an error. + */ +static struct block * +gen_ipnet_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + switch (ll_proto) { + + case ETHERTYPE_IP: + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET); + /*NOTREACHED*/ + + case ETHERTYPE_IPV6: + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, IPH_AF_INET6); + /*NOTREACHED*/ + + default: + break; + } + + return gen_false(cstate); +} + +/* + * Generate code to match a particular packet type. + * + * "ll_proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the type field or to check the type field for the special + * LINUX_SLL_P_802_2 value and then do the appropriate test. + */ +static struct block * +gen_linux_sll_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + struct block *b0, *b1; + + switch (ll_proto) { + + case LLCSAP_ISONS: + case LLCSAP_IP: + case LLCSAP_NETBEUI: + /* + * OSI protocols and NetBEUI always use 802.2 encapsulation, + * so we check the DSAP and SSAP. + * + * LLCSAP_IP checks for IP-over-802.2, rather + * than IP-over-Ethernet or IP-over-SNAP. + * + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other types <= ETHERMTU + * (i.e., other SAP values)? + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, (ll_proto << 8) | ll_proto); + gen_and(b0, b1); + return b1; + + case LLCSAP_IPX: + /* + * Ethernet_II frames, which are Ethernet + * frames with a frame type of ETHERTYPE_IPX; + * + * Ethernet_802.3 frames, which have a frame + * type of LINUX_SLL_P_802_3; + * + * Ethernet_802.2 frames, which are 802.3 + * frames with an 802.2 LLC header (i.e, have + * a frame type of LINUX_SLL_P_802_2) and + * with the IPX LSAP as the DSAP in the LLC + * header; + * + * Ethernet_SNAP frames, which are 802.3 + * frames with an LLC header and a SNAP + * header and with an OUI of 0x000000 + * (encapsulated Ethernet) and a protocol + * ID of ETHERTYPE_IPX in the SNAP header. + * + * First, do the checks on LINUX_SLL_P_802_2 + * frames; generate the check for either + * Ethernet_802.2 or Ethernet_SNAP frames, and + * then put a check for LINUX_SLL_P_802_2 frames + * before it. + */ + b0 = gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_IPX); + gen_or(b0, b1); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + gen_and(b0, b1); + + /* + * Now check for 802.3 frames and OR that with + * the previous test. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_3); + gen_or(b0, b1); + + /* + * Now add the check for Ethernet_II frames, and + * do that before checking for the other frame + * types. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ETHERTYPE_IPX); + gen_or(b0, b1); + return b1; + + case ETHERTYPE_ATALK: + case ETHERTYPE_AARP: + /* + * EtherTalk (AppleTalk protocols on Ethernet link + * layer) may use 802.2 encapsulation. + */ + + /* + * Check for 802.2 encapsulation (EtherTalk phase 2?); + * we check for the 802.2 protocol type in the + * "Ethernet type" field. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * 802.2-encapsulated ETHERTYPE_AARP packets are + * SNAP packets with an organization code of + * 0x000000 (encapsulated Ethernet) and a protocol + * type of ETHERTYPE_AARP (Appletalk ARP). + */ + if (ll_proto == ETHERTYPE_ATALK) + b1 = gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); + else /* ll_proto == ETHERTYPE_AARP */ + b1 = gen_snap(cstate, 0x000000, ETHERTYPE_AARP); + gen_and(b0, b1); + + /* + * Check for Ethernet encapsulation (Ethertalk + * phase 1?); we just check for the Ethernet + * protocol type. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + + gen_or(b0, b1); + return b1; + + default: + if (ll_proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so the frames + * that match would be 802.2 frames. + * Check for the 802.2 protocol type + * in the "Ethernet type" field, and + * then check the DSAP. + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, LINUX_SLL_P_802_2); + b1 = gen_cmp(cstate, OR_LINKHDR, cstate->off_linkpl.constant_part, BPF_B, + ll_proto); + gen_and(b0, b1); + return b1; + } else { + /* + * This is an Ethernet type, so compare + * the length/type field with it (if + * the frame is an 802.2 frame, the length + * field will be <= ETHERMTU, and, as + * "ll_proto" is > ETHERMTU, this test + * will fail and the frame won't match, + * which is what we want). + */ + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + } + } +} + +/* + * Load a value relative to the beginning of the link-layer header after the + * pflog header. + */ +static struct slist * +gen_load_pflog_llprefixlen(compiler_state_t *cstate) +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the pflog header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (cstate->off_linkpl.reg != -1) { + /* + * The length is in the first byte of the header. + */ + s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s1->s.k = 0; + + /* + * Round it up to a multiple of 4. + * Add 3, and clear the lower 2 bits. + */ + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s2->s.k = 3; + sappend(s1, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + s2->s.k = 0xfffffffc; + sappend(s1, s2); + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +static struct slist * +gen_load_prism_llprefixlen(compiler_state_t *cstate) +{ + struct slist *s1, *s2; + struct slist *sjeq_avs_cookie; + struct slist *sjcommon; + + /* + * This code is not compatible with the optimizer, as + * we are generating jmp instructions within a normal + * slist of instructions + */ + cstate->no_optimize = 1; + + /* + * Generate code to load the length of the radio header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + * + * Some Linux drivers use ARPHRD_IEEE80211_PRISM but sometimes + * or always use the AVS header rather than the Prism header. + * We load a 4-byte big-endian value at the beginning of the + * raw packet data, and see whether, when masked with 0xFFFFF000, + * it's equal to 0x80211000. If so, that indicates that it's + * an AVS header (the masked-out bits are the version number). + * Otherwise, it's a Prism header. + * + * XXX - the Prism header is also, in theory, variable-length, + * but no known software generates headers that aren't 144 + * bytes long. + */ + if (cstate->off_linkhdr.reg != -1) { + /* + * Load the cookie. + */ + s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); + s1->s.k = 0; + + /* + * AND it with 0xFFFFF000. + */ + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + s2->s.k = 0xFFFFF000; + sappend(s1, s2); + + /* + * Compare with 0x80211000. + */ + sjeq_avs_cookie = new_stmt(cstate, JMP(BPF_JEQ)); + sjeq_avs_cookie->s.k = 0x80211000; + sappend(s1, sjeq_avs_cookie); + + /* + * If it's AVS: + * + * The 4 bytes at an offset of 4 from the beginning of + * the AVS header are the length of the AVS header. + * That field is big-endian. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); + s2->s.k = 4; + sappend(s1, s2); + sjeq_avs_cookie->s.jt = s2; + + /* + * Now jump to the code to allocate a register + * into which to save the header length and + * store the length there. (The "jump always" + * instruction needs to have the k field set; + * it's added to the PC, so, as we're jumping + * over a single instruction, it should be 1.) + */ + sjcommon = new_stmt(cstate, JMP(BPF_JA)); + sjcommon->s.k = 1; + sappend(s1, sjcommon); + + /* + * Now for the code that handles the Prism header. + * Just load the length of the Prism header (144) + * into the A register. Have the test for an AVS + * header branch here if we don't have an AVS header. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); + s2->s.k = 144; + sappend(s1, s2); + sjeq_avs_cookie->s.jf = s2; + + /* + * Now allocate a register to hold that value and store + * it. The code for the AVS header will jump here after + * loading the length of the AVS header. + */ + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkhdr.reg; + sappend(s1, s2); + sjcommon->s.jf = s2; + + /* + * Now move it into the X register. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +static struct slist * +gen_load_avs_llprefixlen(compiler_state_t *cstate) +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the AVS header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (cstate->off_linkhdr.reg != -1) { + /* + * The 4 bytes at an offset of 4 from the beginning of + * the AVS header are the length of the AVS header. + * That field is big-endian. + */ + s1 = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); + s1->s.k = 4; + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +static struct slist * +gen_load_radiotap_llprefixlen(compiler_state_t *cstate) +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the radiotap header into + * the register assigned to hold that length, if one has been + * assigned. (If one hasn't been assigned, no code we've + * generated uses that prefix, so we don't need to generate any + * code to load it.) + */ + if (cstate->off_linkhdr.reg != -1) { + /* + * The 2 bytes at offsets of 2 and 3 from the beginning + * of the radiotap header are the length of the radiotap + * header; unfortunately, it's little-endian, so we have + * to load it a byte at a time and construct the value. + */ + + /* + * Load the high-order byte, at an offset of 3, shift it + * left a byte, and put the result in the X register. + */ + s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s1->s.k = 3; + s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); + sappend(s1, s2); + s2->s.k = 8; + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + /* + * Load the next byte, at an offset of 2, and OR the + * value from the X register into it. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + sappend(s1, s2); + s2->s.k = 2; + s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); + sappend(s1, s2); + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +/* + * At the moment we treat PPI as normal Radiotap encoded + * packets. The difference is in the function that generates + * the code at the beginning to compute the header length. + * Since this code generator of PPI supports bare 802.11 + * encapsulation only (i.e. the encapsulated DLT should be + * DLT_IEEE802_11) we generate code to check for this too; + * that's done in finish_parse(). + */ +static struct slist * +gen_load_ppi_llprefixlen(compiler_state_t *cstate) +{ + struct slist *s1, *s2; + + /* + * Generate code to load the length of the radiotap header + * into the register assigned to hold that length, if one has + * been assigned. + */ + if (cstate->off_linkhdr.reg != -1) { + /* + * The 2 bytes at offsets of 2 and 3 from the beginning + * of the radiotap header are the length of the radiotap + * header; unfortunately, it's little-endian, so we have + * to load it a byte at a time and construct the value. + */ + + /* + * Load the high-order byte, at an offset of 3, shift it + * left a byte, and put the result in the X register. + */ + s1 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s1->s.k = 3; + s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K); + sappend(s1, s2); + s2->s.k = 8; + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + /* + * Load the next byte, at an offset of 2, and OR the + * value from the X register into it. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + sappend(s1, s2); + s2->s.k = 2; + s2 = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_X); + sappend(s1, s2); + + /* + * Now allocate a register to hold that value and store + * it. + */ + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkhdr.reg; + sappend(s1, s2); + + /* + * Now move it into the X register. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s1, s2); + + return (s1); + } else + return (NULL); +} + +/* + * Load a value relative to the beginning of the link-layer header after the 802.11 + * header, i.e. LLC_SNAP. + * The link-layer header doesn't necessarily begin at the beginning + * of the packet data; there might be a variable-length prefix containing + * radio information. + */ +static struct slist * +gen_load_802_11_header_len(compiler_state_t *cstate, struct slist *s, struct slist *snext) +{ + struct slist *s2; + struct slist *sjset_data_frame_1; + struct slist *sjset_data_frame_2; + struct slist *sjset_qos; + struct slist *sjset_radiotap_flags_present; + struct slist *sjset_radiotap_ext_present; + struct slist *sjset_radiotap_tsft_present; + struct slist *sjset_tsft_datapad, *sjset_notsft_datapad; + struct slist *s_roundup; + + if (cstate->off_linkpl.reg == -1) { + /* + * No register has been assigned to the offset of + * the link-layer payload, which means nobody needs + * it; don't bother computing it - just return + * what we already have. + */ + return (s); + } + + /* + * This code is not compatible with the optimizer, as + * we are generating jmp instructions within a normal + * slist of instructions + */ + cstate->no_optimize = 1; + + /* + * If "s" is non-null, it has code to arrange that the X register + * contains the length of the prefix preceding the link-layer + * header. + * + * Otherwise, the length of the prefix preceding the link-layer + * header is "off_outermostlinkhdr.constant_part". + */ + if (s == NULL) { + /* + * There is no variable-length header preceding the + * link-layer header. + * + * Load the length of the fixed-length prefix preceding + * the link-layer header (if any) into the X register, + * and store it in the cstate->off_linkpl.reg register. + * That length is off_outermostlinkhdr.constant_part. + */ + s = new_stmt(cstate, BPF_LDX|BPF_IMM); + s->s.k = cstate->off_outermostlinkhdr.constant_part; + } + + /* + * The X register contains the offset of the beginning of the + * link-layer header; add 24, which is the minimum length + * of the MAC header for a data frame, to that, and store it + * in cstate->off_linkpl.reg, and then load the Frame Control field, + * which is at the offset in the X register, with an indexed load. + */ + s2 = new_stmt(cstate, BPF_MISC|BPF_TXA); + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s2->s.k = 24; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + + s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s2->s.k = 0; + sappend(s, s2); + + /* + * Check the Frame Control field to see if this is a data frame; + * a data frame has the 0x08 bit (b3) in that field set and the + * 0x04 bit (b2) clear. + */ + sjset_data_frame_1 = new_stmt(cstate, JMP(BPF_JSET)); + sjset_data_frame_1->s.k = 0x08; + sappend(s, sjset_data_frame_1); + + /* + * If b3 is set, test b2, otherwise go to the first statement of + * the rest of the program. + */ + sjset_data_frame_1->s.jt = sjset_data_frame_2 = new_stmt(cstate, JMP(BPF_JSET)); + sjset_data_frame_2->s.k = 0x04; + sappend(s, sjset_data_frame_2); + sjset_data_frame_1->s.jf = snext; + + /* + * If b2 is not set, this is a data frame; test the QoS bit. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_data_frame_2->s.jt = snext; + sjset_data_frame_2->s.jf = sjset_qos = new_stmt(cstate, JMP(BPF_JSET)); + sjset_qos->s.k = 0x80; /* QoS bit */ + sappend(s, sjset_qos); + + /* + * If it's set, add 2 to cstate->off_linkpl.reg, to skip the QoS + * field. + * Otherwise, go to the first statement of the rest of the + * program. + */ + sjset_qos->s.jt = s2 = new_stmt(cstate, BPF_LD|BPF_MEM); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 2; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + + /* + * If we have a radiotap header, look at it to see whether + * there's Atheros padding between the MAC-layer header + * and the payload. + * + * Note: all of the fields in the radiotap header are + * little-endian, so we byte-swap all of the values + * we test against, as they will be loaded as big-endian + * values. + * + * XXX - in the general case, we would have to scan through + * *all* the presence bits, if there's more than one word of + * presence bits. That would require a loop, meaning that + * we wouldn't be able to run the filter in the kernel. + * + * We assume here that the Atheros adapters that insert the + * annoying padding don't have multiple antennae and therefore + * do not generate radiotap headers with multiple presence words. + */ + if (cstate->linktype == DLT_IEEE802_11_RADIO) { + /* + * Is the IEEE80211_RADIOTAP_FLAGS bit (0x0000002) set + * in the first presence flag word? + */ + sjset_qos->s.jf = s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_W); + s2->s.k = 4; + sappend(s, s2); + + sjset_radiotap_flags_present = new_stmt(cstate, JMP(BPF_JSET)); + sjset_radiotap_flags_present->s.k = SWAPLONG(0x00000002); + sappend(s, sjset_radiotap_flags_present); + + /* + * If not, skip all of this. + */ + sjset_radiotap_flags_present->s.jf = snext; + + /* + * Otherwise, is the "extension" bit set in that word? + */ + sjset_radiotap_ext_present = new_stmt(cstate, JMP(BPF_JSET)); + sjset_radiotap_ext_present->s.k = SWAPLONG(0x80000000); + sappend(s, sjset_radiotap_ext_present); + sjset_radiotap_flags_present->s.jt = sjset_radiotap_ext_present; + + /* + * If so, skip all of this. + */ + sjset_radiotap_ext_present->s.jt = snext; + + /* + * Otherwise, is the IEEE80211_RADIOTAP_TSFT bit set? + */ + sjset_radiotap_tsft_present = new_stmt(cstate, JMP(BPF_JSET)); + sjset_radiotap_tsft_present->s.k = SWAPLONG(0x00000001); + sappend(s, sjset_radiotap_tsft_present); + sjset_radiotap_ext_present->s.jf = sjset_radiotap_tsft_present; + + /* + * If IEEE80211_RADIOTAP_TSFT is set, the flags field is + * at an offset of 16 from the beginning of the raw packet + * data (8 bytes for the radiotap header and 8 bytes for + * the TSFT field). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 16; + sappend(s, s2); + sjset_radiotap_tsft_present->s.jt = s2; + + sjset_tsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); + sjset_tsft_datapad->s.k = 0x20; + sappend(s, sjset_tsft_datapad); + + /* + * If IEEE80211_RADIOTAP_TSFT is not set, the flags field is + * at an offset of 8 from the beginning of the raw packet + * data (8 bytes for the radiotap header). + * + * Test whether the IEEE80211_RADIOTAP_F_DATAPAD bit (0x20) + * is set. + */ + s2 = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); + s2->s.k = 8; + sappend(s, s2); + sjset_radiotap_tsft_present->s.jf = s2; + + sjset_notsft_datapad = new_stmt(cstate, JMP(BPF_JSET)); + sjset_notsft_datapad->s.k = 0x20; + sappend(s, sjset_notsft_datapad); + + /* + * In either case, if IEEE80211_RADIOTAP_F_DATAPAD is + * set, round the length of the 802.11 header to + * a multiple of 4. Do that by adding 3 and then + * dividing by and multiplying by 4, which we do by + * ANDing with ~3. + */ + s_roundup = new_stmt(cstate, BPF_LD|BPF_MEM); + s_roundup->s.k = cstate->off_linkpl.reg; + sappend(s, s_roundup); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = 3; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_IMM); + s2->s.k = (bpf_u_int32)~3; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + + sjset_tsft_datapad->s.jt = s_roundup; + sjset_tsft_datapad->s.jf = snext; + sjset_notsft_datapad->s.jt = s_roundup; + sjset_notsft_datapad->s.jf = snext; + } else + sjset_qos->s.jf = snext; + + return s; +} + +static void +insert_compute_vloffsets(compiler_state_t *cstate, struct block *b) +{ + struct slist *s; + + /* There is an implicit dependency between the link + * payload and link header since the payload computation + * includes the variable part of the header. Therefore, + * if nobody else has allocated a register for the link + * header and we need it, do it now. */ + if (cstate->off_linkpl.reg != -1 && cstate->off_linkhdr.is_variable && + cstate->off_linkhdr.reg == -1) + cstate->off_linkhdr.reg = alloc_reg(cstate); + + /* + * For link-layer types that have a variable-length header + * preceding the link-layer header, generate code to load + * the offset of the link-layer header into the register + * assigned to that offset, if any. + * + * XXX - this, and the next switch statement, won't handle + * encapsulation of 802.11 or 802.11+radio information in + * some other protocol stack. That's significantly more + * complicated. + */ + switch (cstate->outermostlinktype) { + + case DLT_PRISM_HEADER: + s = gen_load_prism_llprefixlen(cstate); + break; + + case DLT_IEEE802_11_RADIO_AVS: + s = gen_load_avs_llprefixlen(cstate); + break; + + case DLT_IEEE802_11_RADIO: + s = gen_load_radiotap_llprefixlen(cstate); + break; + + case DLT_PPI: + s = gen_load_ppi_llprefixlen(cstate); + break; + + default: + s = NULL; + break; + } + + /* + * For link-layer types that have a variable-length link-layer + * header, generate code to load the offset of the link-layer + * payload into the register assigned to that offset, if any. + */ + switch (cstate->outermostlinktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + s = gen_load_802_11_header_len(cstate, s, b->stmts); + break; + + case DLT_PFLOG: + s = gen_load_pflog_llprefixlen(cstate); + break; + } + + /* + * If there is no initialization yet and we need variable + * length offsets for VLAN, initialize them to zero + */ + if (s == NULL && cstate->is_vlan_vloffset) { + struct slist *s2; + + if (cstate->off_linkpl.reg == -1) + cstate->off_linkpl.reg = alloc_reg(cstate); + if (cstate->off_linktype.reg == -1) + cstate->off_linktype.reg = alloc_reg(cstate); + + s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); + s->s.k = 0; + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linktype.reg; + sappend(s, s2); + } + + /* + * If we have any offset-loading code, append all the + * existing statements in the block to those statements, + * and make the resulting list the list of statements + * for the block. + */ + if (s != NULL) { + sappend(s, b->stmts); + b->stmts = s; + } +} + +static struct block * +gen_ppi_dlt_check(compiler_state_t *cstate) +{ + struct slist *s_load_dlt; + struct block *b; + + if (cstate->linktype == DLT_PPI) + { + /* Create the statements that check for the DLT + */ + s_load_dlt = new_stmt(cstate, BPF_LD|BPF_W|BPF_ABS); + s_load_dlt->s.k = 4; + + b = new_block(cstate, JMP(BPF_JEQ)); + + b->stmts = s_load_dlt; + b->s.k = SWAPLONG(DLT_IEEE802_11); + } + else + { + b = NULL; + } + + return b; +} + +/* + * Take an absolute offset, and: + * + * if it has no variable part, return NULL; + * + * if it has a variable part, generate code to load the register + * containing that variable part into the X register, returning + * a pointer to that code - if no register for that offset has + * been allocated, allocate it first. + * + * (The code to set that register will be generated later, but will + * be placed earlier in the code sequence.) + */ +static struct slist * +gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off) +{ + struct slist *s; + + if (off->is_variable) { + if (off->reg == -1) { + /* + * We haven't yet assigned a register for the + * variable part of the offset of the link-layer + * header; allocate one. + */ + off->reg = alloc_reg(cstate); + } + + /* + * Load the register containing the variable part of the + * offset of the link-layer header into the X register. + */ + s = new_stmt(cstate, BPF_LDX|BPF_MEM); + s->s.k = off->reg; + return s; + } else { + /* + * That offset isn't variable, there's no variable part, + * so we don't need to generate any code. + */ + return NULL; + } +} + +/* + * Map an Ethernet type to the equivalent PPP type. + */ +static bpf_u_int32 +ethertype_to_ppptype(bpf_u_int32 ll_proto) +{ + switch (ll_proto) { + + case ETHERTYPE_IP: + ll_proto = PPP_IP; + break; + + case ETHERTYPE_IPV6: + ll_proto = PPP_IPV6; + break; + + case ETHERTYPE_DN: + ll_proto = PPP_DECNET; + break; + + case ETHERTYPE_ATALK: + ll_proto = PPP_APPLE; + break; + + case ETHERTYPE_NS: + ll_proto = PPP_NS; + break; + + case LLCSAP_ISONS: + ll_proto = PPP_OSI; + break; + + case LLCSAP_8021D: + /* + * I'm assuming the "Bridging PDU"s that go + * over PPP are Spanning Tree Protocol + * Bridging PDUs. + */ + ll_proto = PPP_BRPDU; + break; + + case LLCSAP_IPX: + ll_proto = PPP_IPX; + break; + } + return (ll_proto); +} + +/* + * Generate any tests that, for encapsulation of a link-layer packet + * inside another protocol stack, need to be done to check for those + * link-layer packets (and that haven't already been done by a check + * for that encapsulation). + */ +static struct block * +gen_prevlinkhdr_check(compiler_state_t *cstate) +{ + struct block *b0; + + if (cstate->is_geneve) + return gen_geneve_ll_check(cstate); + + switch (cstate->prevlinktype) { + + case DLT_SUNATM: + /* + * This is LANE-encapsulated Ethernet; check that the LANE + * packet doesn't begin with an LE Control marker, i.e. + * that it's data, not a control message. + * + * (We've already generated a test for LANE.) + */ + b0 = gen_cmp(cstate, OR_PREVLINKHDR, SUNATM_PKT_BEGIN_POS, BPF_H, 0xFF00); + gen_not(b0); + return b0; + + default: + /* + * No such tests are necessary. + */ + return NULL; + } + /*NOTREACHED*/ +} + +/* + * The three different values we should check for when checking for an + * IPv6 packet with DLT_NULL. + */ +#define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */ +#define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */ +#define BSD_AFNUM_INET6_DARWIN 30 /* macOS, iOS, other Darwin-based OSes */ + +/* + * Generate code to match a particular packet type by matching the + * link-layer type field or fields in the 802.2 LLC header. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. + */ +static struct block * +gen_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + struct block *b0, *b1, *b2; + const char *description; + + /* are we checking MPLS-encapsulated packets? */ + if (cstate->label_stack_depth > 0) + return gen_mpls_linktype(cstate, ll_proto); + + switch (cstate->linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + /* Geneve has an EtherType regardless of whether there is an + * L2 header. */ + if (!cstate->is_geneve) + b0 = gen_prevlinkhdr_check(cstate); + else + b0 = NULL; + + b1 = gen_ether_linktype(cstate, ll_proto); + if (b0 != NULL) + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + + case DLT_C_HDLC: + case DLT_HDLC: + switch (ll_proto) { + + case LLCSAP_ISONS: + ll_proto = (ll_proto << 8 | LLCSAP_ISONS); + /* fall through */ + + default: + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + /*NOTREACHED*/ + } + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + /* + * Check that we have a data frame. + */ + b0 = gen_check_802_11_data_frame(cstate); + + /* + * Now check for the specified link-layer type. + */ + b1 = gen_llc_linktype(cstate, ll_proto); + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + + case DLT_FDDI: + /* + * XXX - check for LLC frames. + */ + return gen_llc_linktype(cstate, ll_proto); + /*NOTREACHED*/ + + case DLT_IEEE802: + /* + * XXX - check for LLC PDUs, as per IEEE 802.5. + */ + return gen_llc_linktype(cstate, ll_proto); + /*NOTREACHED*/ + + case DLT_ATM_RFC1483: + case DLT_ATM_CLIP: + case DLT_IP_OVER_FC: + return gen_llc_linktype(cstate, ll_proto); + /*NOTREACHED*/ + + case DLT_SUNATM: + /* + * Check for an LLC-encapsulated version of this protocol; + * if we were checking for LANE, linktype would no longer + * be DLT_SUNATM. + * + * Check for LLC encapsulation and then check the protocol. + */ + b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + b1 = gen_llc_linktype(cstate, ll_proto); + gen_and(b0, b1); + return b1; + /*NOTREACHED*/ + + case DLT_LINUX_SLL: + return gen_linux_sll_linktype(cstate, ll_proto); + /*NOTREACHED*/ + + case DLT_SLIP: + case DLT_SLIP_BSDOS: + case DLT_RAW: + /* + * These types don't provide any type field; packets + * are always IPv4 or IPv6. + * + * XXX - for IPv4, check for a version number of 4, and, + * for IPv6, check for a version number of 6? + */ + switch (ll_proto) { + + case ETHERTYPE_IP: + /* Check for a version number of 4. */ + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x40, 0xF0); + + case ETHERTYPE_IPV6: + /* Check for a version number of 6. */ + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, 0x60, 0xF0); + + default: + return gen_false(cstate); /* always false */ + } + /*NOTREACHED*/ + + case DLT_IPV4: + /* + * Raw IPv4, so no type field. + */ + if (ll_proto == ETHERTYPE_IP) + return gen_true(cstate); /* always true */ + + /* Checking for something other than IPv4; always false */ + return gen_false(cstate); + /*NOTREACHED*/ + + case DLT_IPV6: + /* + * Raw IPv6, so no type field. + */ + if (ll_proto == ETHERTYPE_IPV6) + return gen_true(cstate); /* always true */ + + /* Checking for something other than IPv6; always false */ + return gen_false(cstate); + /*NOTREACHED*/ + + case DLT_PPP: + case DLT_PPP_PPPD: + case DLT_PPP_SERIAL: + case DLT_PPP_ETHER: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, + ethertype_to_ppptype(ll_proto)); + /*NOTREACHED*/ + + case DLT_PPP_BSDOS: + /* + * We use Ethernet protocol types inside libpcap; + * map them to the corresponding PPP protocol types. + */ + switch (ll_proto) { + + case ETHERTYPE_IP: + /* + * Also check for Van Jacobson-compressed IP. + * XXX - do this for other forms of PPP? + */ + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_IP); + b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJC); + gen_or(b0, b1); + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, PPP_VJNC); + gen_or(b1, b0); + return b0; + + default: + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, + ethertype_to_ppptype(ll_proto)); + } + /*NOTREACHED*/ + + case DLT_NULL: + case DLT_LOOP: + case DLT_ENC: + switch (ll_proto) { + + case ETHERTYPE_IP: + return (gen_loopback_linktype(cstate, AF_INET)); + + case ETHERTYPE_IPV6: + /* + * AF_ values may, unfortunately, be platform- + * dependent; AF_INET isn't, because everybody + * used 4.2BSD's value, but AF_INET6 is, because + * 4.2BSD didn't have a value for it (given that + * IPv6 didn't exist back in the early 1980's), + * and they all picked their own values. + * + * This means that, if we're reading from a + * savefile, we need to check for all the + * possible values. + * + * If we're doing a live capture, we only need + * to check for this platform's value; however, + * Npcap uses 24, which isn't Windows's AF_INET6 + * value. (Given the multiple different values, + * programs that read pcap files shouldn't be + * checking for their platform's AF_INET6 value + * anyway, they should check for all of the + * possible values. and they might as well do + * that even for live captures.) + */ + if (cstate->bpf_pcap->rfile != NULL) { + /* + * Savefile - check for all three + * possible IPv6 values. + */ + b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD); + b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD); + gen_or(b0, b1); + b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN); + gen_or(b0, b1); + return (b1); + } else { + /* + * Live capture, so we only need to + * check for the value used on this + * platform. + */ +#ifdef _WIN32 + /* + * Npcap doesn't use Windows's AF_INET6, + * as that collides with AF_IPX on + * some BSDs (both have the value 23). + * Instead, it uses 24. + */ + return (gen_loopback_linktype(cstate, 24)); +#else /* _WIN32 */ +#ifdef AF_INET6 + return (gen_loopback_linktype(cstate, AF_INET6)); +#else /* AF_INET6 */ + /* + * I guess this platform doesn't support + * IPv6, so we just reject all packets. + */ + return gen_false(cstate); +#endif /* AF_INET6 */ +#endif /* _WIN32 */ + } + + default: + /* + * Not a type on which we support filtering. + * XXX - support those that have AF_ values + * #defined on this platform, at least? + */ + return gen_false(cstate); + } + + case DLT_PFLOG: + /* + * af field is host byte order in contrast to the rest of + * the packet. + */ + if (ll_proto == ETHERTYPE_IP) + return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), + BPF_B, AF_INET)); + else if (ll_proto == ETHERTYPE_IPV6) + return (gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, af), + BPF_B, AF_INET6)); + else + return gen_false(cstate); + /*NOTREACHED*/ + + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* + * XXX should we check for first fragment if the protocol + * uses PHDS? + */ + switch (ll_proto) { + + default: + return gen_false(cstate); + + case ETHERTYPE_IPV6: + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_INET6)); + + case ETHERTYPE_IP: + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_IP); + b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_IP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_ARP: + b0 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_ARP); + b1 = gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_ARP_OLD); + gen_or(b0, b1); + return (b1); + + case ETHERTYPE_REVARP: + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_REVARP)); + + case ETHERTYPE_ATALK: + return (gen_cmp(cstate, OR_LINKTYPE, 0, BPF_B, + ARCTYPE_ATALK)); + } + /*NOTREACHED*/ + + case DLT_LTALK: + switch (ll_proto) { + case ETHERTYPE_ATALK: + return gen_true(cstate); + default: + return gen_false(cstate); + } + /*NOTREACHED*/ + + case DLT_FRELAY: + /* + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + */ + switch (ll_proto) { + + case ETHERTYPE_IP: + /* + * Check for the special NLPID for IP. + */ + return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0xcc); + + case ETHERTYPE_IPV6: + /* + * Check for the special NLPID for IPv6. + */ + return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | 0x8e); + + case LLCSAP_ISONS: + /* + * Check for several OSI protocols. + * + * Frame Relay packets typically have an OSI + * NLPID at the beginning; we check for each + * of them. + * + * What we check for is the NLPID and a frame + * control field of UI, i.e. 0x03 followed + * by the NLPID. + */ + b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO8473_CLNP); + b1 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO9542_ESIS); + b2 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | ISO10589_ISIS); + gen_or(b1, b2); + gen_or(b0, b2); + return b2; + + default: + return gen_false(cstate); + } + /*NOTREACHED*/ + + case DLT_MFR: + bpf_error(cstate, "Multi-link Frame Relay link-layer type filtering not implemented"); + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_ATM1: + case DLT_JUNIPER_ATM2: + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_PPPOE_ATM: + case DLT_JUNIPER_GGSN: + case DLT_JUNIPER_ES: + case DLT_JUNIPER_MONITOR: + case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_VP: + case DLT_JUNIPER_ST: + case DLT_JUNIPER_ISM: + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + + /* just lets verify the magic number for now - + * on ATM we may have up to 6 different encapsulations on the wire + * and need a lot of heuristics to figure out that the payload + * might be; + * + * FIXME encapsulation specific BPF_ filters + */ + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x4d474300, 0xffffff00); /* compare the magic number */ + + case DLT_BACNET_MS_TP: + return gen_mcmp(cstate, OR_LINKHDR, 0, BPF_W, 0x55FF0000, 0xffff0000); + + case DLT_IPNET: + return gen_ipnet_linktype(cstate, ll_proto); + + case DLT_LINUX_IRDA: + bpf_error(cstate, "IrDA link-layer type filtering not implemented"); + + case DLT_DOCSIS: + bpf_error(cstate, "DOCSIS link-layer type filtering not implemented"); + + case DLT_MTP2: + case DLT_MTP2_WITH_PHDR: + bpf_error(cstate, "MTP2 link-layer type filtering not implemented"); + + case DLT_ERF: + bpf_error(cstate, "ERF link-layer type filtering not implemented"); + + case DLT_PFSYNC: + bpf_error(cstate, "PFSYNC link-layer type filtering not implemented"); + + case DLT_LINUX_LAPD: + bpf_error(cstate, "LAPD link-layer type filtering not implemented"); + + case DLT_USB_FREEBSD: + case DLT_USB_LINUX: + case DLT_USB_LINUX_MMAPPED: + case DLT_USBPCAP: + bpf_error(cstate, "USB link-layer type filtering not implemented"); + + case DLT_BLUETOOTH_HCI_H4: + case DLT_BLUETOOTH_HCI_H4_WITH_PHDR: + bpf_error(cstate, "Bluetooth link-layer type filtering not implemented"); + + case DLT_CAN20B: + case DLT_CAN_SOCKETCAN: + bpf_error(cstate, "CAN link-layer type filtering not implemented"); + + case DLT_IEEE802_15_4: + case DLT_IEEE802_15_4_LINUX: + case DLT_IEEE802_15_4_NONASK_PHY: + case DLT_IEEE802_15_4_NOFCS: + case DLT_IEEE802_15_4_TAP: + bpf_error(cstate, "IEEE 802.15.4 link-layer type filtering not implemented"); + + case DLT_IEEE802_16_MAC_CPS_RADIO: + bpf_error(cstate, "IEEE 802.16 link-layer type filtering not implemented"); + + case DLT_SITA: + bpf_error(cstate, "SITA link-layer type filtering not implemented"); + + case DLT_RAIF1: + bpf_error(cstate, "RAIF1 link-layer type filtering not implemented"); + + case DLT_IPMB_KONTRON: + case DLT_IPMB_LINUX: + bpf_error(cstate, "IPMB link-layer type filtering not implemented"); + + case DLT_AX25_KISS: + bpf_error(cstate, "AX.25 link-layer type filtering not implemented"); + + case DLT_NFLOG: + /* Using the fixed-size NFLOG header it is possible to tell only + * the address family of the packet, other meaningful data is + * either missing or behind TLVs. + */ + bpf_error(cstate, "NFLOG link-layer type filtering not implemented"); + + default: + /* + * Does this link-layer header type have a field + * indicating the type of the next protocol? If + * so, off_linktype.constant_part will be the offset of that + * field in the packet; if not, it will be OFFSET_NOT_SET. + */ + if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) { + /* + * Yes; assume it's an Ethernet type. (If + * it's not, it needs to be handled specially + * above.) + */ + return gen_cmp(cstate, OR_LINKTYPE, 0, BPF_H, ll_proto); + /*NOTREACHED */ + } else { + /* + * No; report an error. + */ + description = pcap_datalink_val_to_description_or_dlt(cstate->linktype); + bpf_error(cstate, "%s link-layer type filtering not implemented", + description); + /*NOTREACHED */ + } + } +} + +/* + * Check for an LLC SNAP packet with a given organization code and + * protocol type; we check the entire contents of the 802.2 LLC and + * snap headers, checking for DSAP and SSAP of SNAP and a control + * field of 0x03 in the LLC header, and for the specified organization + * code and protocol type in the SNAP header. + */ +static struct block * +gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) +{ + u_char snapblock[8]; + + snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ + snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ + snapblock[2] = 0x03; /* control = UI */ + snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */ + snapblock[4] = (u_char)(orgcode >> 8); /* middle 8 bits of organization code */ + snapblock[5] = (u_char)(orgcode >> 0); /* lower 8 bits of organization code */ + snapblock[6] = (u_char)(ptype >> 8); /* upper 8 bits of protocol type */ + snapblock[7] = (u_char)(ptype >> 0); /* lower 8 bits of protocol type */ + return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock); +} + +/* + * Generate code to match frames with an LLC header. + */ +static struct block * +gen_llc_internal(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + switch (cstate->linktype) { + + case DLT_EN10MB: + /* + * We check for an Ethernet type field less than + * 1500, which means it's an 802.3 length field. + */ + b0 = gen_cmp_gt(cstate, OR_LINKTYPE, 0, BPF_H, ETHERMTU); + gen_not(b0); + + /* + * Now check for the purported DSAP and SSAP not being + * 0xFF, to rule out NetWare-over-802.3. + */ + b1 = gen_cmp(cstate, OR_LLC, 0, BPF_H, 0xFFFF); + gen_not(b1); + gen_and(b0, b1); + return b1; + + case DLT_SUNATM: + /* + * We check for LLC traffic. + */ + b0 = gen_atmtype_llc(cstate); + return b0; + + case DLT_IEEE802: /* Token Ring */ + /* + * XXX - check for LLC frames. + */ + return gen_true(cstate); + + case DLT_FDDI: + /* + * XXX - check for LLC frames. + */ + return gen_true(cstate); + + case DLT_ATM_RFC1483: + /* + * For LLC encapsulation, these are defined to have an + * 802.2 LLC header. + * + * For VC encapsulation, they don't, but there's no + * way to check for that; the protocol used on the VC + * is negotiated out of band. + */ + return gen_true(cstate); + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_PPI: + /* + * Check that we have a data frame. + */ + b0 = gen_check_802_11_data_frame(cstate); + return b0; + + default: + bpf_error(cstate, "'llc' not supported for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } +} + +struct block * +gen_llc(compiler_state_t *cstate) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_llc_internal(cstate); +} + +struct block * +gen_llc_i(compiler_state_t *cstate) +{ + struct block *b0, *b1; + struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc_internal(cstate); + + /* + * Load the control byte and test the low-order bit; it must + * be clear for I frames. + */ + s = gen_load_a(cstate, OR_LLC, 2, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x01; + b1->stmts = s; + gen_not(b1); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_s(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc_internal(cstate); + + /* + * Now compare the low-order 2 bit of the control byte against + * the appropriate value for S frames. + */ + b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_S_FMT, 0x03); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_u(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc_internal(cstate); + + /* + * Now compare the low-order 2 bit of the control byte against + * the appropriate value for U frames. + */ + b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, LLC_U_FMT, 0x03); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_s_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc_internal(cstate); + + /* + * Now check for an S frame with the appropriate type. + */ + b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_S_CMD_MASK); + gen_and(b0, b1); + return b1; +} + +struct block * +gen_llc_u_subtype(compiler_state_t *cstate, bpf_u_int32 subtype) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Check whether this is an LLC frame. + */ + b0 = gen_llc_internal(cstate); + + /* + * Now check for a U frame with the appropriate type. + */ + b1 = gen_mcmp(cstate, OR_LLC, 2, BPF_B, subtype, LLC_U_CMD_MASK); + gen_and(b0, b1); + return b1; +} + +/* + * Generate code to match a particular packet type, for link-layer types + * using 802.2 LLC headers. + * + * This is *NOT* used for Ethernet; "gen_ether_linktype()" is used + * for that - it handles the D/I/X Ethernet vs. 802.3+802.2 issues. + * + * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP + * value, if <= ETHERMTU. We use that to determine whether to + * match the DSAP or both DSAP and LSAP or to check the OUI and + * protocol ID in a SNAP header. + */ +static struct block * +gen_llc_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + /* + * XXX - handle token-ring variable-length header. + */ + switch (ll_proto) { + + case LLCSAP_IP: + case LLCSAP_ISONS: + case LLCSAP_NETBEUI: + /* + * XXX - should we check both the DSAP and the + * SSAP, like this, or should we check just the + * DSAP, as we do for other SAP values? + */ + return gen_cmp(cstate, OR_LLC, 0, BPF_H, (bpf_u_int32) + ((ll_proto << 8) | ll_proto)); + + case LLCSAP_IPX: + /* + * XXX - are there ever SNAP frames for IPX on + * non-Ethernet 802.x networks? + */ + return gen_cmp(cstate, OR_LLC, 0, BPF_B, LLCSAP_IPX); + + case ETHERTYPE_ATALK: + /* + * 802.2-encapsulated ETHERTYPE_ATALK packets are + * SNAP packets with an organization code of + * 0x080007 (Apple, for Appletalk) and a protocol + * type of ETHERTYPE_ATALK (Appletalk). + * + * XXX - check for an organization code of + * encapsulated Ethernet as well? + */ + return gen_snap(cstate, 0x080007, ETHERTYPE_ATALK); + + default: + /* + * XXX - we don't have to check for IPX 802.3 + * here, but should we check for the IPX Ethertype? + */ + if (ll_proto <= ETHERMTU) { + /* + * This is an LLC SAP value, so check + * the DSAP. + */ + return gen_cmp(cstate, OR_LLC, 0, BPF_B, ll_proto); + } else { + /* + * This is an Ethernet type; we assume that it's + * unlikely that it'll appear in the right place + * at random, and therefore check only the + * location that would hold the Ethernet type + * in a SNAP frame with an organization code of + * 0x000000 (encapsulated Ethernet). + * + * XXX - if we were to check for the SNAP DSAP and + * LSAP, as per XXX, and were also to check for an + * organization code of 0x000000 (encapsulated + * Ethernet), we'd do + * + * return gen_snap(cstate, 0x000000, ll_proto); + * + * here; for now, we don't, as per the above. + * I don't know whether it's worth the extra CPU + * time to do the right check or not. + */ + return gen_cmp(cstate, OR_LLC, 6, BPF_H, ll_proto); + } + } +} + +static struct block * +gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, + int dir, bpf_u_int32 ll_proto, u_int src_off, u_int dst_off) +{ + struct block *b0, *b1; + u_int offset; + + switch (dir) { + + case Q_SRC: + offset = src_off; + break; + + case Q_DST: + offset = dst_off; + break; + + case Q_AND: + b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); + b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_hostop(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); + b1 = gen_hostop(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + b0 = gen_linktype(cstate, ll_proto); + b1 = gen_mcmp(cstate, OR_LINKPL, offset, BPF_W, addr, mask); + gen_and(b0, b1); + return b1; +} + +#ifdef INET6 +static struct block * +gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, + struct in6_addr *mask, int dir, bpf_u_int32 ll_proto, u_int src_off, + u_int dst_off) +{ + struct block *b0, *b1; + u_int offset; + /* + * Code below needs to access four separate 32-bit parts of the 128-bit + * IPv6 address and mask. In some OSes this is as simple as using the + * s6_addr32 pseudo-member of struct in6_addr, which contains a union of + * 8-, 16- and 32-bit arrays. In other OSes this is not the case, as + * far as libpcap sees it. Hence copy the data before use to avoid + * potential unaligned memory access and the associated compiler + * warnings (whether genuine or not). + */ + bpf_u_int32 a[4], m[4]; + + switch (dir) { + + case Q_SRC: + offset = src_off; + break; + + case Q_DST: + offset = dst_off; + break; + + case Q_AND: + b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); + b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_hostop6(cstate, addr, mask, Q_SRC, ll_proto, src_off, dst_off); + b1 = gen_hostop6(cstate, addr, mask, Q_DST, ll_proto, src_off, dst_off); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + /* this order is important */ + memcpy(a, addr, sizeof(a)); + memcpy(m, mask, sizeof(m)); + b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); + b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); + gen_and(b0, b1); + b0 = gen_mcmp(cstate, OR_LINKPL, offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); + gen_and(b0, b1); + b0 = gen_mcmp(cstate, OR_LINKPL, offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); + gen_and(b0, b1); + b0 = gen_linktype(cstate, ll_proto); + gen_and(b0, b1); + return b1; +} +#endif + +static struct block * +gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(cstate, OR_LINKHDR, 6, 6, eaddr); + + case Q_DST: + return gen_bcmp(cstate, OR_LINKHDR, 0, 6, eaddr); + + case Q_AND: + b0 = gen_ehostop(cstate, eaddr, Q_SRC); + b1 = gen_ehostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ehostop(cstate, eaddr, Q_SRC); + b1 = gen_ehostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is only supported on 802.11 with 802.11 headers"); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +/* + * Like gen_ehostop, but for DLT_FDDI + */ +static struct block * +gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(cstate, OR_LINKHDR, 6 + 1 + cstate->pcap_fddipad, 6, eaddr); + + case Q_DST: + return gen_bcmp(cstate, OR_LINKHDR, 0 + 1 + cstate->pcap_fddipad, 6, eaddr); + + case Q_AND: + b0 = gen_fhostop(cstate, eaddr, Q_SRC); + b1 = gen_fhostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_fhostop(cstate, eaddr, Q_SRC); + b1 = gen_fhostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is only supported on 802.11"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is only supported on 802.11"); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +/* + * Like gen_ehostop, but for DLT_IEEE802 (Token Ring) + */ +static struct block * +gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(cstate, OR_LINKHDR, 8, 6, eaddr); + + case Q_DST: + return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); + + case Q_AND: + b0 = gen_thostop(cstate, eaddr, Q_SRC); + b1 = gen_thostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_thostop(cstate, eaddr, Q_SRC); + b1 = gen_thostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is only supported on 802.11"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is only supported on 802.11"); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +/* + * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and + * various 802.11 + radio headers. + */ +static struct block * +gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + +#ifdef ENABLE_WLAN_FILTERING_PATCH + /* + * TODO GV 20070613 + * We need to disable the optimizer because the optimizer is buggy + * and wipes out some LD instructions generated by the below + * code to validate the Frame Control bits + */ + cstate->no_optimize = 1; +#endif /* ENABLE_WLAN_FILTERING_PATCH */ + + switch (dir) { + case Q_SRC: + /* + * Oh, yuk. + * + * For control frames, there is no SA. + * + * For management frames, SA is at an + * offset of 10 from the beginning of + * the packet. + * + * For data frames, SA is at an offset + * of 10 from the beginning of the packet + * if From DS is clear, at an offset of + * 16 from the beginning of the packet + * if From DS is set and To DS is clear, + * and an offset of 24 from the beginning + * of the packet if From DS is set and To DS + * is set. + */ + + /* + * Generate the tests to be done for data frames + * with From DS set. + * + * First, check for To DS set, i.e. check "link[1] & 0x01". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the SA is at 24. + */ + b0 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the SA is at 16. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames with + * From DS set. + */ + gen_or(b1, b0); + + /* + * Now check for From DS being set, and AND that with + * the ORed-together checks. + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x02; /* From DS */ + b1->stmts = s; + gen_and(b1, b0); + + /* + * Now check for data frames with From DS not set. + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x02; /* From DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If From DS isn't set, the SA is at 10. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the checks for data frames with + * From DS not set and for data frames with From DS + * set; that gives the checks done for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the SA is at 10. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_DST: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + + case Q_AND: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + /* + * XXX - add BSSID keyword? + */ + case Q_ADDR1: + return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); + + case Q_ADDR2: + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + case Q_ADDR3: + /* + * Not present in control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_ADDR4: + /* + * Present only if the direction mask has both "From DS" + * and "To DS" set. Neither control frames nor management + * frames should have both of those set, so we don't + * check the frame type. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, + IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); + b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_RA: + /* + * Not present in management frames; addr1 in other + * frames. + */ + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "(link[0] & 0x08)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * Check addr1. + */ + b0 = gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr); + + /* + * AND that with the check of addr1. + */ + gen_and(b1, b0); + return (b0); + + case Q_TA: + /* + * Not present in management frames; addr2, if present, + * in other frames. + */ + + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "(link[0] & 0x08)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the check for frames other than + * CTS and ACK frames. + */ + gen_and(b1, b2); + + /* + * Check addr2. + */ + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + } + abort(); + /*NOTREACHED*/ +} + +/* + * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel. + * (We assume that the addresses are IEEE 48-bit MAC addresses, + * as the RFC states.) + */ +static struct block * +gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + register struct block *b0, *b1; + + switch (dir) { + case Q_SRC: + return gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + + case Q_DST: + return gen_bcmp(cstate, OR_LINKHDR, 2, 6, eaddr); + + case Q_AND: + b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); + b1 = gen_ipfchostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ipfchostop(cstate, eaddr, Q_SRC); + b1 = gen_ipfchostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is only supported on 802.11"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is only supported on 802.11"); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +/* + * This is quite tricky because there may be pad bytes in front of the + * DECNET header, and then there are two possible data packet formats that + * carry both src and dst addresses, plus 5 packet types in a format that + * carries only the src node, plus 2 types that use a different format and + * also carry just the src node. + * + * Yuck. + * + * Instead of doing those all right, we just look for data packets with + * 0 or 1 bytes of padding. If you want to look at other packets, that + * will require a lot more hacking. + * + * To add support for filtering on DECNET "areas" (network numbers) + * one would want to add a "mask" argument to this routine. That would + * make the filter even more inefficient, although one could be clever + * and not generate masking instructions if the mask is 0xFFFF. + */ +static struct block * +gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir) +{ + struct block *b0, *b1, *b2, *tmp; + u_int offset_lh; /* offset if long header is received */ + u_int offset_sh; /* offset if short header is received */ + + switch (dir) { + + case Q_DST: + offset_sh = 1; /* follows flags */ + offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ + break; + + case Q_SRC: + offset_sh = 3; /* follows flags, dstnode */ + offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ + break; + + case Q_AND: + /* Inefficient because we do our Calvinball dance twice */ + b0 = gen_dnhostop(cstate, addr, Q_SRC); + b1 = gen_dnhostop(cstate, addr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + /* Inefficient because we do our Calvinball dance twice */ + b0 = gen_dnhostop(cstate, addr, Q_SRC); + b1 = gen_dnhostop(cstate, addr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + b0 = gen_linktype(cstate, ETHERTYPE_DN); + /* Check for pad = 1, long header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, + (bpf_u_int32)ntohs(0x0681), (bpf_u_int32)ntohs(0x07FF)); + b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, + BPF_H, (bpf_u_int32)ntohs((u_short)addr)); + gen_and(tmp, b1); + /* Check for pad = 0, long header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x06, + (bpf_u_int32)0x7); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, + (bpf_u_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + /* Check for pad = 1, short header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, + (bpf_u_int32)ntohs(0x0281), (bpf_u_int32)ntohs(0x07FF)); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_sh, BPF_H, + (bpf_u_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + /* Check for pad = 0, short header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_u_int32)0x02, + (bpf_u_int32)0x7); + b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_sh, BPF_H, + (bpf_u_int32)ntohs((u_short)addr)); + gen_and(tmp, b2); + gen_or(b2, b1); + + /* Combine with test for cstate->linktype */ + gen_and(b0, b1); + return b1; +} + +/* + * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets; + * test the bottom-of-stack bit, and then check the version number + * field in the IP header. + */ +static struct block * +gen_mpls_linktype(compiler_state_t *cstate, bpf_u_int32 ll_proto) +{ + struct block *b0, *b1; + + switch (ll_proto) { + + case ETHERTYPE_IP: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0); + gen_and(b0, b1); + return b1; + + case ETHERTYPE_IPV6: + /* match the bottom-of-stack bit */ + b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); + /* match the IPv4 version number */ + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0); + gen_and(b0, b1); + return b1; + + default: + /* FIXME add other L3 proto IDs */ + bpf_error(cstate, "unsupported protocol over mpls"); + /*NOTREACHED*/ + } +} + +static struct block * +gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, + int proto, int dir, int type) +{ + struct block *b0, *b1; + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; + + switch (proto) { + + case Q_DEFAULT: + b0 = gen_host(cstate, addr, mask, Q_IP, dir, type); + /* + * Only check for non-IPv4 addresses if we're not + * checking MPLS-encapsulated packets. + */ + if (cstate->label_stack_depth == 0) { + b1 = gen_host(cstate, addr, mask, Q_ARP, dir, type); + gen_or(b0, b1); + b0 = gen_host(cstate, addr, mask, Q_RARP, dir, type); + gen_or(b1, b0); + } + return b0; + + case Q_LINK: + bpf_error(cstate, "link-layer modifier applied to %s", typestr); + + case Q_IP: + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); + + case Q_RARP: + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_REVARP, 14, 24); + + case Q_ARP: + return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); + + case Q_SCTP: + bpf_error(cstate, "'sctp' modifier applied to %s", typestr); + + case Q_TCP: + bpf_error(cstate, "'tcp' modifier applied to %s", typestr); + + case Q_UDP: + bpf_error(cstate, "'udp' modifier applied to %s", typestr); + + case Q_ICMP: + bpf_error(cstate, "'icmp' modifier applied to %s", typestr); + + case Q_IGMP: + bpf_error(cstate, "'igmp' modifier applied to %s", typestr); + + case Q_IGRP: + bpf_error(cstate, "'igrp' modifier applied to %s", typestr); + + case Q_ATALK: + bpf_error(cstate, "AppleTalk host filtering not implemented"); + + case Q_DECNET: + return gen_dnhostop(cstate, addr, dir); + + case Q_LAT: + bpf_error(cstate, "LAT host filtering not implemented"); + + case Q_SCA: + bpf_error(cstate, "SCA host filtering not implemented"); + + case Q_MOPRC: + bpf_error(cstate, "MOPRC host filtering not implemented"); + + case Q_MOPDL: + bpf_error(cstate, "MOPDL host filtering not implemented"); + + case Q_IPV6: + bpf_error(cstate, "'ip6' modifier applied to ip host"); + + case Q_ICMPV6: + bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); + + case Q_AH: + bpf_error(cstate, "'ah' modifier applied to %s", typestr); + + case Q_ESP: + bpf_error(cstate, "'esp' modifier applied to %s", typestr); + + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); + + case Q_AARP: + bpf_error(cstate, "AARP host filtering not implemented"); + + case Q_ISO: + bpf_error(cstate, "ISO host filtering not implemented"); + + case Q_ESIS: + bpf_error(cstate, "'esis' modifier applied to %s", typestr); + + case Q_ISIS: + bpf_error(cstate, "'isis' modifier applied to %s", typestr); + + case Q_CLNP: + bpf_error(cstate, "'clnp' modifier applied to %s", typestr); + + case Q_STP: + bpf_error(cstate, "'stp' modifier applied to %s", typestr); + + case Q_IPX: + bpf_error(cstate, "IPX host filtering not implemented"); + + case Q_NETBEUI: + bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); + + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to %s", typestr); + + case Q_RADIO: + bpf_error(cstate, "'radio' modifier applied to %s", typestr); + + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to %s", typestr); + + default: + abort(); + } + /*NOTREACHED*/ +} + +#ifdef INET6 +static struct block * +gen_host6(compiler_state_t *cstate, struct in6_addr *addr, + struct in6_addr *mask, int proto, int dir, int type) +{ + const char *typestr; + + if (type == Q_NET) + typestr = "net"; + else + typestr = "host"; + + switch (proto) { + + case Q_DEFAULT: + return gen_host6(cstate, addr, mask, Q_IPV6, dir, type); + + case Q_LINK: + bpf_error(cstate, "link-layer modifier applied to ip6 %s", typestr); + + case Q_IP: + bpf_error(cstate, "'ip' modifier applied to ip6 %s", typestr); + + case Q_RARP: + bpf_error(cstate, "'rarp' modifier applied to ip6 %s", typestr); + + case Q_ARP: + bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); + + case Q_SCTP: + bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr); + + case Q_TCP: + bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr); + + case Q_UDP: + bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr); + + case Q_ICMP: + bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr); + + case Q_IGMP: + bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr); + + case Q_IGRP: + bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr); + + case Q_ATALK: + bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr); + + case Q_DECNET: + bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); + + case Q_LAT: + bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr); + + case Q_SCA: + bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr); + + case Q_MOPRC: + bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr); + + case Q_MOPDL: + bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr); + + case Q_IPV6: + return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); + + case Q_ICMPV6: + bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr); + + case Q_AH: + bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr); + + case Q_ESP: + bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr); + + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr); + + case Q_AARP: + bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr); + + case Q_ISO: + bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr); + + case Q_ESIS: + bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr); + + case Q_ISIS: + bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr); + + case Q_CLNP: + bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr); + + case Q_STP: + bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr); + + case Q_IPX: + bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr); + + case Q_NETBEUI: + bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr); + + case Q_RADIO: + bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr); + + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr); + + default: + abort(); + } + /*NOTREACHED*/ +} +#endif + +#ifndef INET6 +static struct block * +gen_gateway(compiler_state_t *cstate, const u_char *eaddr, + struct addrinfo *alist, int proto, int dir) +{ + struct block *b0, *b1, *tmp; + struct addrinfo *ai; + struct sockaddr_in *sin; + + if (dir != 0) + bpf_error(cstate, "direction applied to 'gateway'"); + + switch (proto) { + case Q_DEFAULT: + case Q_IP: + case Q_ARP: + case Q_RARP: + switch (cstate->linktype) { + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(cstate); + b0 = gen_ehostop(cstate, eaddr, Q_OR); + if (b1 != NULL) + gen_and(b1, b0); + break; + case DLT_FDDI: + b0 = gen_fhostop(cstate, eaddr, Q_OR); + break; + case DLT_IEEE802: + b0 = gen_thostop(cstate, eaddr, Q_OR); + break; + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + b0 = gen_wlanhostop(cstate, eaddr, Q_OR); + break; + case DLT_SUNATM: + /* + * This is LLC-multiplexed traffic; if it were + * LANE, cstate->linktype would have been set to + * DLT_EN10MB. + */ + bpf_error(cstate, + "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + case DLT_IP_OVER_FC: + b0 = gen_ipfchostop(cstate, eaddr, Q_OR); + break; + default: + bpf_error(cstate, + "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + } + b1 = NULL; + for (ai = alist; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Is it an IPv4 address? + */ + if (ai->ai_addr->sa_family == AF_INET) { + /* + * Generate an entry for it. + */ + sin = (struct sockaddr_in *)ai->ai_addr; + tmp = gen_host(cstate, + ntohl(sin->sin_addr.s_addr), + 0xffffffff, proto, Q_OR, Q_HOST); + /* + * Is it the *first* IPv4 address? + */ + if (b1 == NULL) { + /* + * Yes, so start with it. + */ + b1 = tmp; + } else { + /* + * No, so OR it into the + * existing set of + * addresses. + */ + gen_or(b1, tmp); + b1 = tmp; + } + } + } + } + if (b1 == NULL) { + /* + * No IPv4 addresses found. + */ + return (NULL); + } + gen_not(b1); + gen_and(b0, b1); + return b1; + } + bpf_error(cstate, "illegal modifier of 'gateway'"); + /*NOTREACHED*/ +} +#endif + +static struct block * +gen_proto_abbrev_internal(compiler_state_t *cstate, int proto) +{ + struct block *b0; + struct block *b1; + + switch (proto) { + + case Q_SCTP: + b1 = gen_proto(cstate, IPPROTO_SCTP, Q_DEFAULT, Q_DEFAULT); + break; + + case Q_TCP: + b1 = gen_proto(cstate, IPPROTO_TCP, Q_DEFAULT, Q_DEFAULT); + break; + + case Q_UDP: + b1 = gen_proto(cstate, IPPROTO_UDP, Q_DEFAULT, Q_DEFAULT); + break; + + case Q_ICMP: + b1 = gen_proto(cstate, IPPROTO_ICMP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_IGMP +#define IPPROTO_IGMP 2 +#endif + + case Q_IGMP: + b1 = gen_proto(cstate, IPPROTO_IGMP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_IGRP +#define IPPROTO_IGRP 9 +#endif + case Q_IGRP: + b1 = gen_proto(cstate, IPPROTO_IGRP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_PIM +#define IPPROTO_PIM 103 +#endif + + case Q_PIM: + b1 = gen_proto(cstate, IPPROTO_PIM, Q_DEFAULT, Q_DEFAULT); + break; + +#ifndef IPPROTO_VRRP +#define IPPROTO_VRRP 112 +#endif + + case Q_VRRP: + b1 = gen_proto(cstate, IPPROTO_VRRP, Q_IP, Q_DEFAULT); + break; + +#ifndef IPPROTO_CARP +#define IPPROTO_CARP 112 +#endif + + case Q_CARP: + b1 = gen_proto(cstate, IPPROTO_CARP, Q_IP, Q_DEFAULT); + break; + + case Q_IP: + b1 = gen_linktype(cstate, ETHERTYPE_IP); + break; + + case Q_ARP: + b1 = gen_linktype(cstate, ETHERTYPE_ARP); + break; + + case Q_RARP: + b1 = gen_linktype(cstate, ETHERTYPE_REVARP); + break; + + case Q_LINK: + bpf_error(cstate, "link layer applied in wrong context"); + + case Q_ATALK: + b1 = gen_linktype(cstate, ETHERTYPE_ATALK); + break; + + case Q_AARP: + b1 = gen_linktype(cstate, ETHERTYPE_AARP); + break; + + case Q_DECNET: + b1 = gen_linktype(cstate, ETHERTYPE_DN); + break; + + case Q_SCA: + b1 = gen_linktype(cstate, ETHERTYPE_SCA); + break; + + case Q_LAT: + b1 = gen_linktype(cstate, ETHERTYPE_LAT); + break; + + case Q_MOPDL: + b1 = gen_linktype(cstate, ETHERTYPE_MOPDL); + break; + + case Q_MOPRC: + b1 = gen_linktype(cstate, ETHERTYPE_MOPRC); + break; + + case Q_IPV6: + b1 = gen_linktype(cstate, ETHERTYPE_IPV6); + break; + +#ifndef IPPROTO_ICMPV6 +#define IPPROTO_ICMPV6 58 +#endif + case Q_ICMPV6: + b1 = gen_proto(cstate, IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); + break; + +#ifndef IPPROTO_AH +#define IPPROTO_AH 51 +#endif + case Q_AH: + b1 = gen_proto(cstate, IPPROTO_AH, Q_DEFAULT, Q_DEFAULT); + break; + +#ifndef IPPROTO_ESP +#define IPPROTO_ESP 50 +#endif + case Q_ESP: + b1 = gen_proto(cstate, IPPROTO_ESP, Q_DEFAULT, Q_DEFAULT); + break; + + case Q_ISO: + b1 = gen_linktype(cstate, LLCSAP_ISONS); + break; + + case Q_ESIS: + b1 = gen_proto(cstate, ISO9542_ESIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS: + b1 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); + break; + + case Q_ISIS_L1: /* all IS-IS Level1 PDU-Types */ + b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_L2: /* all IS-IS Level2 PDU-Types */ + b0 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); /* FIXME extract the circuit-type bits */ + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_IIH: /* all IS-IS Hello PDU-Types */ + b0 = gen_proto(cstate, ISIS_L1_LAN_IIH, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_L2_LAN_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_PTP_IIH, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_LSP: + b0 = gen_proto(cstate, ISIS_L1_LSP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_L2_LSP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_SNP: + b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + b0 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_CSNP: + b0 = gen_proto(cstate, ISIS_L1_CSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_L2_CSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_ISIS_PSNP: + b0 = gen_proto(cstate, ISIS_L1_PSNP, Q_ISIS, Q_DEFAULT); + b1 = gen_proto(cstate, ISIS_L2_PSNP, Q_ISIS, Q_DEFAULT); + gen_or(b0, b1); + break; + + case Q_CLNP: + b1 = gen_proto(cstate, ISO8473_CLNP, Q_ISO, Q_DEFAULT); + break; + + case Q_STP: + b1 = gen_linktype(cstate, LLCSAP_8021D); + break; + + case Q_IPX: + b1 = gen_linktype(cstate, LLCSAP_IPX); + break; + + case Q_NETBEUI: + b1 = gen_linktype(cstate, LLCSAP_NETBEUI); + break; + + case Q_RADIO: + bpf_error(cstate, "'radio' is not a valid protocol type"); + + default: + abort(); + } + return b1; +} + +struct block * +gen_proto_abbrev(compiler_state_t *cstate, int proto) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_proto_abbrev_internal(cstate, proto); +} + +static struct block * +gen_ipfrag(compiler_state_t *cstate) +{ + struct slist *s; + struct block *b; + + /* not IPv4 frag other than the first frag */ + s = gen_load_a(cstate, OR_LINKPL, 6, BPF_H); + b = new_block(cstate, JMP(BPF_JSET)); + b->s.k = 0x1fff; + b->stmts = s; + gen_not(b); + + return b; +} + +/* + * Generate a comparison to a port value in the transport-layer header + * at the specified offset from the beginning of that header. + * + * XXX - this handles a variable-length prefix preceding the link-layer + * header, such as the radiotap or AVS radio prefix, but doesn't handle + * variable-length link-layer headers (such as Token Ring or 802.11 + * headers). + */ +static struct block * +gen_portatom(compiler_state_t *cstate, int off, bpf_u_int32 v) +{ + return gen_cmp(cstate, OR_TRAN_IPV4, off, BPF_H, v); +} + +static struct block * +gen_portatom6(compiler_state_t *cstate, int off, bpf_u_int32 v) +{ + return gen_cmp(cstate, OR_TRAN_IPV6, off, BPF_H, v); +} + +static struct block * +gen_portop(compiler_state_t *cstate, u_int port, u_int proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' and not a fragment other than the first fragment */ + tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto); + b0 = gen_ipfrag(cstate); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portatom(cstate, 0, port); + break; + + case Q_DST: + b1 = gen_portatom(cstate, 2, port); + break; + + case Q_AND: + tmp = gen_portatom(cstate, 0, port); + b1 = gen_portatom(cstate, 2, port); + gen_and(tmp, b1); + break; + + case Q_DEFAULT: + case Q_OR: + tmp = gen_portatom(cstate, 0, port); + b1 = gen_portatom(cstate, 2, port); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for ports"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for ports"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_port(compiler_state_t *cstate, u_int port, int ip_proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* + * ether proto ip + * + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ + b0 = gen_linktype(cstate, ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portop(cstate, port, (u_int)ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portop(cstate, port, IPPROTO_TCP, dir); + b1 = gen_portop(cstate, port, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portop(cstate, port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +struct block * +gen_portop6(compiler_state_t *cstate, u_int port, u_int proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* ip6 proto 'proto' */ + /* XXX - catch the first fragment of a fragmented packet? */ + b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto); + + switch (dir) { + case Q_SRC: + b1 = gen_portatom6(cstate, 0, port); + break; + + case Q_DST: + b1 = gen_portatom6(cstate, 2, port); + break; + + case Q_AND: + tmp = gen_portatom6(cstate, 0, port); + b1 = gen_portatom6(cstate, 2, port); + gen_and(tmp, b1); + break; + + case Q_DEFAULT: + case Q_OR: + tmp = gen_portatom6(cstate, 0, port); + b1 = gen_portatom6(cstate, 2, port); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_port6(compiler_state_t *cstate, u_int port, int ip_proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* link proto ip6 */ + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portop6(cstate, port, (u_int)ip_proto, dir); + break; + + case PROTO_UNDEF: + tmp = gen_portop6(cstate, port, IPPROTO_TCP, dir); + b1 = gen_portop6(cstate, port, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portop6(cstate, port, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +/* gen_portrange code */ +static struct block * +gen_portrangeatom(compiler_state_t *cstate, u_int off, bpf_u_int32 v1, + bpf_u_int32 v2) +{ + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_u_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + + b1 = gen_cmp_ge(cstate, OR_TRAN_IPV4, off, BPF_H, v1); + b2 = gen_cmp_le(cstate, OR_TRAN_IPV4, off, BPF_H, v2); + + gen_and(b1, b2); + + return b2; +} + +static struct block * +gen_portrangeop(compiler_state_t *cstate, u_int port1, u_int port2, + bpf_u_int32 proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* ip proto 'proto' and not a fragment other than the first fragment */ + tmp = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, proto); + b0 = gen_ipfrag(cstate); + gen_and(tmp, b0); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom(cstate, 0, port1, port2); + break; + + case Q_DST: + b1 = gen_portrangeatom(cstate, 2, port1, port2); + break; + + case Q_AND: + tmp = gen_portrangeatom(cstate, 0, port1, port2); + b1 = gen_portrangeatom(cstate, 2, port1, port2); + gen_and(tmp, b1); + break; + + case Q_DEFAULT: + case Q_OR: + tmp = gen_portrangeatom(cstate, 0, port1, port2); + b1 = gen_portrangeatom(cstate, 2, port1, port2); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for port ranges"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for port ranges"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto, + int dir) +{ + struct block *b0, *b1, *tmp; + + /* link proto ip */ + b0 = gen_linktype(cstate, ETHERTYPE_IP); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop(cstate, port1, port2, (bpf_u_int32)ip_proto, + dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop(cstate, port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop(cstate, port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_portrangeatom6(compiler_state_t *cstate, u_int off, bpf_u_int32 v1, + bpf_u_int32 v2) +{ + struct block *b1, *b2; + + if (v1 > v2) { + /* + * Reverse the order of the ports, so v1 is the lower one. + */ + bpf_u_int32 vtemp; + + vtemp = v1; + v1 = v2; + v2 = vtemp; + } + + b1 = gen_cmp_ge(cstate, OR_TRAN_IPV6, off, BPF_H, v1); + b2 = gen_cmp_le(cstate, OR_TRAN_IPV6, off, BPF_H, v2); + + gen_and(b1, b2); + + return b2; +} + +static struct block * +gen_portrangeop6(compiler_state_t *cstate, u_int port1, u_int port2, + bpf_u_int32 proto, int dir) +{ + struct block *b0, *b1, *tmp; + + /* ip6 proto 'proto' */ + /* XXX - catch the first fragment of a fragmented packet? */ + b0 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, proto); + + switch (dir) { + case Q_SRC: + b1 = gen_portrangeatom6(cstate, 0, port1, port2); + break; + + case Q_DST: + b1 = gen_portrangeatom6(cstate, 2, port1, port2); + break; + + case Q_AND: + tmp = gen_portrangeatom6(cstate, 0, port1, port2); + b1 = gen_portrangeatom6(cstate, 2, port1, port2); + gen_and(tmp, b1); + break; + + case Q_DEFAULT: + case Q_OR: + tmp = gen_portrangeatom6(cstate, 0, port1, port2); + b1 = gen_portrangeatom6(cstate, 2, port1, port2); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_portrange6(compiler_state_t *cstate, u_int port1, u_int port2, int ip_proto, + int dir) +{ + struct block *b0, *b1, *tmp; + + /* link proto ip6 */ + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + + switch (ip_proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + b1 = gen_portrangeop6(cstate, port1, port2, (bpf_u_int32)ip_proto, + dir); + break; + + case PROTO_UNDEF: + tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_TCP, dir); + b1 = gen_portrangeop6(cstate, port1, port2, IPPROTO_UDP, dir); + gen_or(tmp, b1); + tmp = gen_portrangeop6(cstate, port1, port2, IPPROTO_SCTP, dir); + gen_or(tmp, b1); + break; + + default: + abort(); + } + gen_and(b0, b1); + return b1; +} + +static int +lookup_proto(compiler_state_t *cstate, const char *name, int proto) +{ + register int v; + + switch (proto) { + + case Q_DEFAULT: + case Q_IP: + case Q_IPV6: + v = pcap_nametoproto(name); + if (v == PROTO_UNDEF) + bpf_error(cstate, "unknown ip proto '%s'", name); + break; + + case Q_LINK: + /* XXX should look up h/w protocol type based on cstate->linktype */ + v = pcap_nametoeproto(name); + if (v == PROTO_UNDEF) { + v = pcap_nametollc(name); + if (v == PROTO_UNDEF) + bpf_error(cstate, "unknown ether proto '%s'", name); + } + break; + + case Q_ISO: + if (strcmp(name, "esis") == 0) + v = ISO9542_ESIS; + else if (strcmp(name, "isis") == 0) + v = ISO10589_ISIS; + else if (strcmp(name, "clnp") == 0) + v = ISO8473_CLNP; + else + bpf_error(cstate, "unknown osi proto '%s'", name); + break; + + default: + v = PROTO_UNDEF; + break; + } + return v; +} + +#if !defined(NO_PROTOCHAIN) +static struct block * +gen_protochain(compiler_state_t *cstate, bpf_u_int32 v, int proto) +{ + struct block *b0, *b; + struct slist *s[100]; + int fix2, fix3, fix4, fix5; + int ahcheck, again, end; + int i, max; + int reg2 = alloc_reg(cstate); + + memset(s, 0, sizeof(s)); + fix3 = fix4 = fix5 = 0; + + switch (proto) { + case Q_IP: + case Q_IPV6: + break; + case Q_DEFAULT: + b0 = gen_protochain(cstate, v, Q_IP); + b = gen_protochain(cstate, v, Q_IPV6); + gen_or(b0, b); + return b; + default: + bpf_error(cstate, "bad protocol applied for 'protochain'"); + /*NOTREACHED*/ + } + + /* + * We don't handle variable-length prefixes before the link-layer + * header, or variable-length link-layer headers, here yet. + * We might want to add BPF instructions to do the protochain + * work, to simplify that and, on platforms that have a BPF + * interpreter with the new instructions, let the filtering + * be done in the kernel. (We already require a modified BPF + * engine to do the protochain stuff, to support backward + * branches, and backward branch support is unlikely to appear + * in kernel BPF engines.) + */ + if (cstate->off_linkpl.is_variable) + bpf_error(cstate, "'protochain' not supported with variable length headers"); + + /* + * To quote a comment in optimize.c: + * + * "These data structures are used in a Cocke and Schwartz style + * value numbering scheme. Since the flowgraph is acyclic, + * exit values can be propagated from a node's predecessors + * provided it is uniquely defined." + * + * "Acyclic" means "no backward branches", which means "no + * loops", so we have to turn the optimizer off. + */ + cstate->no_optimize = 1; + + /* + * s[0] is a dummy entry to protect other BPF insn from damage + * by s[fix] = foo with uninitialized variable "fix". It is somewhat + * hard to find interdependency made by jump table fixup. + */ + i = 0; + s[i] = new_stmt(cstate, 0); /*dummy*/ + i++; + + switch (proto) { + case Q_IP: + b0 = gen_linktype(cstate, ETHERTYPE_IP); + + /* A = ip->ip_p */ + s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 9; + i++; + /* X = ip->ip_hl << 2 */ + s[i] = new_stmt(cstate, BPF_LDX|BPF_MSH|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + i++; + break; + + case Q_IPV6: + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + + /* A = ip6->ip_nxt */ + s[i] = new_stmt(cstate, BPF_LD|BPF_ABS|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 6; + i++; + /* X = sizeof(struct ip6_hdr) */ + s[i] = new_stmt(cstate, BPF_LDX|BPF_IMM); + s[i]->s.k = 40; + i++; + break; + + default: + bpf_error(cstate, "unsupported proto to gen_protochain"); + /*NOTREACHED*/ + } + + /* again: if (A == v) goto end; else fall through; */ + again = i; + s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.k = v; + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + fix5 = i; + i++; + +#ifndef IPPROTO_NONE +#define IPPROTO_NONE 59 +#endif + /* if (A == IPPROTO_NONE) goto end */ + s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_NONE; + s[fix5]->s.jf = s[i]; + fix2 = i; + i++; + + if (proto == Q_IPV6) { + int v6start, v6end, v6advance, j; + + v6start = i; + /* if (A == IPPROTO_HOPOPTS) goto v6advance */ + s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_HOPOPTS; + s[fix2]->s.jf = s[i]; + i++; + /* if (A == IPPROTO_DSTOPTS) goto v6advance */ + s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_DSTOPTS; + i++; + /* if (A == IPPROTO_ROUTING) goto v6advance */ + s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*update in next stmt*/ + s[i]->s.k = IPPROTO_ROUTING; + i++; + /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ + s[i - 1]->s.jf = s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*later*/ + s[i]->s.k = IPPROTO_FRAGMENT; + fix3 = i; + v6end = i; + i++; + + /* v6advance: */ + v6advance = i; + + /* + * in short, + * A = P[X + packet head]; + * X = X + (P[X + packet head + 1] + 1) * 8; + */ + /* A = P[X + packet head] */ + s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + i++; + /* MEM[reg2] = A */ + s[i] = new_stmt(cstate, BPF_ST); + s[i]->s.k = reg2; + i++; + /* A = P[X + packet head + 1]; */ + s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 1; + i++; + /* A += 1 */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 1; + i++; + /* A *= 8 */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); + s[i]->s.k = 8; + i++; + /* A += X */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); + s[i]->s.k = 0; + i++; + /* X = A; */ + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); + i++; + /* A = MEM[reg2] */ + s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); + s[i]->s.k = reg2; + i++; + + /* goto again; (must use BPF_JA for backward jump) */ + s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); + s[i]->s.k = again - i - 1; + s[i - 1]->s.jf = s[i]; + i++; + + /* fixup */ + for (j = v6start; j <= v6end; j++) + s[j]->s.jt = s[v6advance]; + } else { + /* nop */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 0; + s[fix2]->s.jf = s[i]; + i++; + } + + /* ahcheck: */ + ahcheck = i; + /* if (A == IPPROTO_AH) then fall through; else goto end; */ + s[i] = new_stmt(cstate, BPF_JMP|BPF_JEQ|BPF_K); + s[i]->s.jt = NULL; /*later*/ + s[i]->s.jf = NULL; /*later*/ + s[i]->s.k = IPPROTO_AH; + if (fix3) + s[fix3]->s.jf = s[ahcheck]; + fix4 = i; + i++; + + /* + * in short, + * A = P[X]; + * X = X + (P[X + 1] + 2) * 4; + */ + /* A = X */ + s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); + i++; + /* A = P[X + packet head]; */ + s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + i++; + /* MEM[reg2] = A */ + s[i] = new_stmt(cstate, BPF_ST); + s[i]->s.k = reg2; + i++; + /* A = X */ + s[i - 1]->s.jt = s[i] = new_stmt(cstate, BPF_MISC|BPF_TXA); + i++; + /* A += 1 */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 1; + i++; + /* X = A */ + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); + i++; + /* A = P[X + packet head] */ + s[i] = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s[i]->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + i++; + /* A += 2 */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 2; + i++; + /* A *= 4 */ + s[i] = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); + s[i]->s.k = 4; + i++; + /* X = A; */ + s[i] = new_stmt(cstate, BPF_MISC|BPF_TAX); + i++; + /* A = MEM[reg2] */ + s[i] = new_stmt(cstate, BPF_LD|BPF_MEM); + s[i]->s.k = reg2; + i++; + + /* goto again; (must use BPF_JA for backward jump) */ + s[i] = new_stmt(cstate, BPF_JMP|BPF_JA); + s[i]->s.k = again - i - 1; + i++; + + /* end: nop */ + end = i; + s[i] = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s[i]->s.k = 0; + s[fix2]->s.jt = s[end]; + s[fix4]->s.jf = s[end]; + s[fix5]->s.jt = s[end]; + i++; + + /* + * make slist chain + */ + max = i; + for (i = 0; i < max - 1; i++) + s[i]->next = s[i + 1]; + s[max - 1]->next = NULL; + + /* + * emit final check + */ + b = new_block(cstate, JMP(BPF_JEQ)); + b->stmts = s[1]; /*remember, s[0] is dummy*/ + b->s.k = v; + + free_reg(cstate, reg2); + + gen_and(b0, b); + return b; +} +#endif /* !defined(NO_PROTOCHAIN) */ + +static struct block * +gen_check_802_11_data_frame(compiler_state_t *cstate) +{ + struct slist *s; + struct block *b0, *b1; + + /* + * A data frame has the 0x08 bit (b3) in the frame control field set + * and the 0x04 bit (b2) clear. + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b0 = new_block(cstate, JMP(BPF_JSET)); + b0->s.k = 0x08; + b0->stmts = s; + + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + gen_and(b1, b0); + + return b0; +} + +/* + * Generate code that checks whether the packet is a packet for protocol + * and whether the type field in that protocol's header has + * the value , e.g. if is Q_IP, it checks whether it's an + * IP packet and checks the protocol number in the IP header against . + * + * If is Q_DEFAULT, i.e. just "proto" was specified, it checks + * against Q_IP and Q_IPV6. + */ +static struct block * +gen_proto(compiler_state_t *cstate, bpf_u_int32 v, int proto, int dir) +{ + struct block *b0, *b1; + struct block *b2; + + if (dir != Q_DEFAULT) + bpf_error(cstate, "direction applied to 'proto'"); + + switch (proto) { + case Q_DEFAULT: + b0 = gen_proto(cstate, v, Q_IP, dir); + b1 = gen_proto(cstate, v, Q_IPV6, dir); + gen_or(b0, b1); + return b1; + + case Q_LINK: + return gen_linktype(cstate, v); + + case Q_IP: + /* + * For FDDI, RFC 1188 says that SNAP encapsulation is used, + * not LLC encapsulation with LLCSAP_IP. + * + * For IEEE 802 networks - which includes 802.5 token ring + * (which is what DLT_IEEE802 means) and 802.11 - RFC 1042 + * says that SNAP encapsulation is used, not LLC encapsulation + * with LLCSAP_IP. + * + * For LLC-encapsulated ATM/"Classical IP", RFC 1483 and + * RFC 2225 say that SNAP encapsulation is used, not LLC + * encapsulation with LLCSAP_IP. + * + * So we always check for ETHERTYPE_IP. + */ + b0 = gen_linktype(cstate, ETHERTYPE_IP); + b1 = gen_cmp(cstate, OR_LINKPL, 9, BPF_B, v); + gen_and(b0, b1); + return b1; + + case Q_ARP: + bpf_error(cstate, "arp does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_RARP: + bpf_error(cstate, "rarp does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_SCTP: + bpf_error(cstate, "'sctp proto' is bogus"); + /*NOTREACHED*/ + + case Q_TCP: + bpf_error(cstate, "'tcp proto' is bogus"); + /*NOTREACHED*/ + + case Q_UDP: + bpf_error(cstate, "'udp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ICMP: + bpf_error(cstate, "'icmp proto' is bogus"); + /*NOTREACHED*/ + + case Q_IGMP: + bpf_error(cstate, "'igmp proto' is bogus"); + /*NOTREACHED*/ + + case Q_IGRP: + bpf_error(cstate, "'igrp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ATALK: + bpf_error(cstate, "AppleTalk encapsulation is not specifiable"); + /*NOTREACHED*/ + + case Q_DECNET: + bpf_error(cstate, "DECNET encapsulation is not specifiable"); + /*NOTREACHED*/ + + case Q_LAT: + bpf_error(cstate, "LAT does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_SCA: + bpf_error(cstate, "SCA does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_MOPRC: + bpf_error(cstate, "MOPRC does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_MOPDL: + bpf_error(cstate, "MOPDL does not encapsulate another protocol"); + /*NOTREACHED*/ + + case Q_IPV6: + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + /* + * Also check for a fragment header before the final + * header. + */ + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, IPPROTO_FRAGMENT); + b1 = gen_cmp(cstate, OR_LINKPL, 40, BPF_B, v); + gen_and(b2, b1); + b2 = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, v); + gen_or(b2, b1); + gen_and(b0, b1); + return b1; + + case Q_ICMPV6: + bpf_error(cstate, "'icmp6 proto' is bogus"); + /*NOTREACHED*/ + + case Q_AH: + bpf_error(cstate, "'ah proto' is bogus"); + /*NOTREACHED*/ + + case Q_ESP: + bpf_error(cstate, "'esp proto' is bogus"); + /*NOTREACHED*/ + + case Q_PIM: + bpf_error(cstate, "'pim proto' is bogus"); + /*NOTREACHED*/ + + case Q_VRRP: + bpf_error(cstate, "'vrrp proto' is bogus"); + /*NOTREACHED*/ + + case Q_AARP: + bpf_error(cstate, "'aarp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISO: + switch (cstate->linktype) { + + case DLT_FRELAY: + /* + * Frame Relay packets typically have an OSI + * NLPID at the beginning; "gen_linktype(cstate, LLCSAP_ISONS)" + * generates code to check for all the OSI + * NLPIDs, so calling it and then adding a check + * for the particular NLPID for which we're + * looking is bogus, as we can just check for + * the NLPID. + * + * What we check for is the NLPID and a frame + * control field value of UI, i.e. 0x03 followed + * by the NLPID. + * + * XXX - assumes a 2-byte Frame Relay header with + * DLCI and flags. What if the address is longer? + * + * XXX - what about SNAP-encapsulated frames? + */ + return gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, (0x03<<8) | v); + /*NOTREACHED*/ + + case DLT_C_HDLC: + case DLT_HDLC: + /* + * Cisco uses an Ethertype lookalike - for OSI, + * it's 0xfefe. + */ + b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS); + /* OSI in C-HDLC is stuffed with a fudge byte */ + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, v); + gen_and(b0, b1); + return b1; + + default: + b0 = gen_linktype(cstate, LLCSAP_ISONS); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, v); + gen_and(b0, b1); + return b1; + } + + case Q_ESIS: + bpf_error(cstate, "'esis proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS: + b0 = gen_proto(cstate, ISO10589_ISIS, Q_ISO, Q_DEFAULT); + /* + * 4 is the offset of the PDU type relative to the IS-IS + * header. + */ + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, v); + gen_and(b0, b1); + return b1; + + case Q_CLNP: + bpf_error(cstate, "'clnp proto' is not supported"); + /*NOTREACHED*/ + + case Q_STP: + bpf_error(cstate, "'stp proto' is bogus"); + /*NOTREACHED*/ + + case Q_IPX: + bpf_error(cstate, "'ipx proto' is bogus"); + /*NOTREACHED*/ + + case Q_NETBEUI: + bpf_error(cstate, "'netbeui proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_L1: + bpf_error(cstate, "'l1 proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_L2: + bpf_error(cstate, "'l2 proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp proto' is bogus"); + /*NOTREACHED*/ + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp proto' is bogus"); + /*NOTREACHED*/ + + case Q_RADIO: + bpf_error(cstate, "'radio proto' is bogus"); + /*NOTREACHED*/ + + case Q_CARP: + bpf_error(cstate, "'carp proto' is bogus"); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + /*NOTREACHED*/ +} + +/* + * Convert a non-numeric name to a port number. + */ +static int +nametoport(compiler_state_t *cstate, const char *name, int ipproto) +{ + struct addrinfo hints, *res, *ai; + int error; + struct sockaddr_in *in4; +#ifdef INET6 + struct sockaddr_in6 *in6; +#endif + int port = -1; + + /* + * We check for both TCP and UDP in case there are + * ambiguous entries. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = (ipproto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM; + hints.ai_protocol = ipproto; + error = getaddrinfo(NULL, name, &hints, &res); + if (error != 0) { + switch (error) { + + case EAI_NONAME: + case EAI_SERVICE: + /* + * No such port. Just return -1. + */ + break; + +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + /* + * We don't use strerror() because it's not + * guaranteed to be thread-safe on all platforms + * (probably because it might use a non-thread-local + * buffer into which to format an error message + * if the error code isn't one for which it has + * a canned string; three cheers for C string + * handling). + */ + bpf_set_error(cstate, "getaddrinfo(\"%s\" fails with system error: %d", + name, errno); + port = -2; /* a real error */ + break; +#endif + + default: + /* + * This is a real error, not just "there's + * no such service name". + * + * We don't use gai_strerror() because it's not + * guaranteed to be thread-safe on all platforms + * (probably because it might use a non-thread-local + * buffer into which to format an error message + * if the error code isn't one for which it has + * a canned string; three cheers for C string + * handling). + */ + bpf_set_error(cstate, "getaddrinfo(\"%s\") fails with error: %d", + name, error); + port = -2; /* a real error */ + break; + } + } else { + /* + * OK, we found it. Did it find anything? + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Get a port number; we're done. + */ + if (ai->ai_addr->sa_family == AF_INET) { + in4 = (struct sockaddr_in *)ai->ai_addr; + port = ntohs(in4->sin_port); + break; + } +#ifdef INET6 + if (ai->ai_addr->sa_family == AF_INET6) { + in6 = (struct sockaddr_in6 *)ai->ai_addr; + port = ntohs(in6->sin6_port); + break; + } +#endif + } + } + freeaddrinfo(res); + } + return port; +} + +/* + * Convert a string to a port number. + */ +static bpf_u_int32 +stringtoport(compiler_state_t *cstate, const char *string, size_t string_size, + int *proto) +{ + stoulen_ret ret; + char *cpy; + bpf_u_int32 val; + int tcp_port = -1; + int udp_port = -1; + + /* + * See if it's a number. + */ + ret = stoulen(string, string_size, &val, cstate); + switch (ret) { + + case STOULEN_OK: + /* Unknown port type - it's just a number. */ + *proto = PROTO_UNDEF; + break; + + case STOULEN_NOT_OCTAL_NUMBER: + case STOULEN_NOT_HEX_NUMBER: + case STOULEN_NOT_DECIMAL_NUMBER: + /* + * Not a valid number; try looking it up as a port. + */ + cpy = malloc(string_size + 1); /* +1 for terminating '\0' */ + memcpy(cpy, string, string_size); + cpy[string_size] = '\0'; + tcp_port = nametoport(cstate, cpy, IPPROTO_TCP); + if (tcp_port == -2) { + /* + * We got a hard error; the error string has + * already been set. + */ + free(cpy); + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + } + udp_port = nametoport(cstate, cpy, IPPROTO_UDP); + if (udp_port == -2) { + /* + * We got a hard error; the error string has + * already been set. + */ + free(cpy); + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + } + + /* + * We need to check /etc/services for ambiguous entries. + * If we find an ambiguous entry, and it has the + * same port number, change the proto to PROTO_UNDEF + * so both TCP and UDP will be checked. + */ + if (tcp_port >= 0) { + val = (bpf_u_int32)tcp_port; + *proto = IPPROTO_TCP; + if (udp_port >= 0) { + if (udp_port == tcp_port) + *proto = PROTO_UNDEF; +#ifdef notdef + else + /* Can't handle ambiguous names that refer + to different port numbers. */ + warning("ambiguous port %s in /etc/services", + cpy); +#endif + } + free(cpy); + break; + } + if (udp_port >= 0) { + val = (bpf_u_int32)udp_port; + *proto = IPPROTO_UDP; + free(cpy); + break; + } +#if defined(ultrix) || defined(__osf__) + /* Special hack in case NFS isn't in /etc/services */ + if (strcmp(cpy, "nfs") == 0) { + val = 2049; + *proto = PROTO_UNDEF; + free(cpy); + break; + } +#endif + bpf_set_error(cstate, "'%s' is not a valid port", cpy); + free(cpy); + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + + case STOULEN_ERROR: + /* Error already set. */ + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + + default: + /* Should not happen */ + bpf_set_error(cstate, "stoulen returned %d - this should not happen", ret); + longjmp(cstate->top_ctx, 1); + /*NOTREACHED*/ + } + return (val); +} + +/* + * Convert a string in the form PPP-PPP, which correspond to ports, to + * a starting and ending port in a port range. + */ +static void +stringtoportrange(compiler_state_t *cstate, const char *string, + bpf_u_int32 *port1, bpf_u_int32 *port2, int *proto) +{ + char *hyphen_off; + const char *first, *second; + size_t first_size, second_size; + int save_proto; + + if ((hyphen_off = strchr(string, '-')) == NULL) + bpf_error(cstate, "port range '%s' contains no hyphen", string); + + /* + * Make sure there are no other hyphens. + * + * XXX - we support named ports, but there are some port names + * in /etc/services that include hyphens, so this would rule + * that out. + */ + if (strchr(hyphen_off + 1, '-') != NULL) + bpf_error(cstate, "port range '%s' contains more than one hyphen", + string); + + /* + * Get the length of the first port. + */ + first = string; + first_size = hyphen_off - string; + if (first_size == 0) { + /* Range of "-port", which we don't support. */ + bpf_error(cstate, "port range '%s' has no starting port", string); + } + + /* + * Try to convert it to a port. + */ + *port1 = stringtoport(cstate, first, first_size, proto); + save_proto = *proto; + + /* + * Get the length of the second port. + */ + second = hyphen_off + 1; + second_size = strlen(second); + if (second_size == 0) { + /* Range of "port-", which we don't support. */ + bpf_error(cstate, "port range '%s' has no ending port", string); + } + + /* + * Try to convert it to a port. + */ + *port2 = stringtoport(cstate, second, second_size, proto); + if (*proto != save_proto) + *proto = PROTO_UNDEF; +} + +struct block * +gen_scode(compiler_state_t *cstate, const char *name, struct qual q) +{ + int proto = q.proto; + int dir = q.dir; + int tproto; + u_char *eaddr; + bpf_u_int32 mask, addr; + struct addrinfo *res, *res0; + struct sockaddr_in *sin4; +#ifdef INET6 + int tproto6; + struct sockaddr_in6 *sin6; + struct in6_addr mask128; +#endif /*INET6*/ + struct block *b, *tmp; + int port, real_proto; + bpf_u_int32 port1, port2; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (q.addr) { + + case Q_NET: + addr = pcap_nametonetaddr(name); + if (addr == 0) + bpf_error(cstate, "unknown network '%s'", name); + /* Left justify network addr and calculate its network mask */ + mask = 0xffffffff; + while (addr && (addr & 0xff000000) == 0) { + addr <<= 8; + mask <<= 8; + } + return gen_host(cstate, addr, mask, proto, dir, q.addr); + + case Q_DEFAULT: + case Q_HOST: + if (proto == Q_LINK) { + switch (cstate->linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, + "unknown ether host '%s'", name); + tmp = gen_prevlinkhdr_check(cstate); + b = gen_ehostop(cstate, eaddr, dir); + if (tmp != NULL) + gen_and(tmp, b); + free(eaddr); + return b; + + case DLT_FDDI: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, + "unknown FDDI host '%s'", name); + b = gen_fhostop(cstate, eaddr, dir); + free(eaddr); + return b; + + case DLT_IEEE802: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, + "unknown token ring host '%s'", name); + b = gen_thostop(cstate, eaddr, dir); + free(eaddr); + return b; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, + "unknown 802.11 host '%s'", name); + b = gen_wlanhostop(cstate, eaddr, dir); + free(eaddr); + return b; + + case DLT_IP_OVER_FC: + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, + "unknown Fibre Channel host '%s'", name); + b = gen_ipfchostop(cstate, eaddr, dir); + free(eaddr); + return b; + } + + bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name"); + } else if (proto == Q_DECNET) { + unsigned short dn_addr; + + if (!__pcap_nametodnaddr(name, &dn_addr)) { +#ifdef DECNETLIB + bpf_error(cstate, "unknown decnet host name '%s'\n", name); +#else + bpf_error(cstate, "decnet name support not included, '%s' cannot be translated\n", + name); +#endif + } + /* + * I don't think DECNET hosts can be multihomed, so + * there is no need to build up a list of addresses + */ + return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr)); + } else { +#ifdef INET6 + memset(&mask128, 0xff, sizeof(mask128)); +#endif + res0 = res = pcap_nametoaddrinfo(name); + if (res == NULL) + bpf_error(cstate, "unknown host '%s'", name); + cstate->ai = res; + b = tmp = NULL; + tproto = proto; +#ifdef INET6 + tproto6 = proto; +#endif + if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && + tproto == Q_DEFAULT) { + tproto = Q_IP; +#ifdef INET6 + tproto6 = Q_IPV6; +#endif + } + for (res = res0; res; res = res->ai_next) { + switch (res->ai_family) { + case AF_INET: +#ifdef INET6 + if (tproto == Q_IPV6) + continue; +#endif + + sin4 = (struct sockaddr_in *) + res->ai_addr; + tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr), + 0xffffffff, tproto, dir, q.addr); + break; +#ifdef INET6 + case AF_INET6: + if (tproto6 == Q_IP) + continue; + + sin6 = (struct sockaddr_in6 *) + res->ai_addr; + tmp = gen_host6(cstate, &sin6->sin6_addr, + &mask128, tproto6, dir, q.addr); + break; +#endif + default: + continue; + } + if (b) + gen_or(b, tmp); + b = tmp; + } + cstate->ai = NULL; + freeaddrinfo(res0); + if (b == NULL) { + bpf_error(cstate, "unknown host '%s'%s", name, + (proto == Q_DEFAULT) + ? "" + : " for specified address family"); + } + return b; + } + + case Q_PORT: + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) + bpf_error(cstate, "illegal qualifier of 'port'"); + if (pcap_nametoport(name, &port, &real_proto) == 0) + bpf_error(cstate, "unknown port '%s'", name); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error(cstate, "port '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error(cstate, "port '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error(cstate, "port '%s' is udp", name); + + else if (real_proto == IPPROTO_SCTP) + bpf_error(cstate, "port '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error(cstate, "port '%s' is udp", name); + + else if (real_proto == IPPROTO_TCP) + bpf_error(cstate, "port '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } + if (port < 0) + bpf_error(cstate, "illegal port number %d < 0", port); + if (port > 65535) + bpf_error(cstate, "illegal port number %d > 65535", port); + b = gen_port(cstate, port, real_proto, dir); + gen_or(gen_port6(cstate, port, real_proto, dir), b); + return b; + + case Q_PORTRANGE: + if (proto != Q_DEFAULT && + proto != Q_UDP && proto != Q_TCP && proto != Q_SCTP) + bpf_error(cstate, "illegal qualifier of 'portrange'"); + stringtoportrange(cstate, name, &port1, &port2, &real_proto); + if (proto == Q_UDP) { + if (real_proto == IPPROTO_TCP) + bpf_error(cstate, "port in range '%s' is tcp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error(cstate, "port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_UDP; + } + if (proto == Q_TCP) { + if (real_proto == IPPROTO_UDP) + bpf_error(cstate, "port in range '%s' is udp", name); + else if (real_proto == IPPROTO_SCTP) + bpf_error(cstate, "port in range '%s' is sctp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_TCP; + } + if (proto == Q_SCTP) { + if (real_proto == IPPROTO_UDP) + bpf_error(cstate, "port in range '%s' is udp", name); + else if (real_proto == IPPROTO_TCP) + bpf_error(cstate, "port in range '%s' is tcp", name); + else + /* override PROTO_UNDEF */ + real_proto = IPPROTO_SCTP; + } + if (port1 > 65535) + bpf_error(cstate, "illegal port number %d > 65535", port1); + if (port2 > 65535) + bpf_error(cstate, "illegal port number %d > 65535", port2); + + b = gen_portrange(cstate, port1, port2, real_proto, dir); + gen_or(gen_portrange6(cstate, port1, port2, real_proto, dir), b); + return b; + + case Q_GATEWAY: +#ifndef INET6 + eaddr = pcap_ether_hostton(name); + if (eaddr == NULL) + bpf_error(cstate, "unknown ether host: %s", name); + + res = pcap_nametoaddrinfo(name); + cstate->ai = res; + if (res == NULL) + bpf_error(cstate, "unknown host '%s'", name); + b = gen_gateway(cstate, eaddr, res, proto, dir); + cstate->ai = NULL; + freeaddrinfo(res); + if (b == NULL) + bpf_error(cstate, "unknown host '%s'", name); + return b; +#else + bpf_error(cstate, "'gateway' not supported in this configuration"); +#endif /*INET6*/ + + case Q_PROTO: + real_proto = lookup_proto(cstate, name, proto); + if (real_proto >= 0) + return gen_proto(cstate, real_proto, proto, dir); + else + bpf_error(cstate, "unknown protocol: %s", name); + +#if !defined(NO_PROTOCHAIN) + case Q_PROTOCHAIN: + real_proto = lookup_proto(cstate, name, proto); + if (real_proto >= 0) + return gen_protochain(cstate, real_proto, proto); + else + bpf_error(cstate, "unknown protocol: %s", name); +#endif /* !defined(NO_PROTOCHAIN) */ + + case Q_UNDEF: + syntax(cstate); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +struct block * +gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, + bpf_u_int32 masklen, struct qual q) +{ + register int nlen, mlen; + bpf_u_int32 n, m; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + nlen = __pcap_atoin(s1, &n); + if (nlen < 0) + bpf_error(cstate, "invalid IPv4 address '%s'", s1); + /* Promote short ipaddr */ + n <<= 32 - nlen; + + if (s2 != NULL) { + mlen = __pcap_atoin(s2, &m); + if (mlen < 0) + bpf_error(cstate, "invalid IPv4 address '%s'", s2); + /* Promote short ipaddr */ + m <<= 32 - mlen; + if ((n & ~m) != 0) + bpf_error(cstate, "non-network bits set in \"%s mask %s\"", + s1, s2); + } else { + /* Convert mask len to mask */ + if (masklen > 32) + bpf_error(cstate, "mask length must be <= 32"); + if (masklen == 0) { + /* + * X << 32 is not guaranteed by C to be 0; it's + * undefined. + */ + m = 0; + } else + m = 0xffffffff << (32 - masklen); + if ((n & ~m) != 0) + bpf_error(cstate, "non-network bits set in \"%s/%d\"", + s1, masklen); + } + + switch (q.addr) { + + case Q_NET: + return gen_host(cstate, n, m, q.proto, q.dir, q.addr); + + default: + bpf_error(cstate, "Mask syntax for networks only"); + /*NOTREACHED*/ + } + /*NOTREACHED*/ +} + +struct block * +gen_ncode(compiler_state_t *cstate, const char *s, bpf_u_int32 v, struct qual q) +{ + bpf_u_int32 mask; + int proto; + int dir; + register int vlen; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + proto = q.proto; + dir = q.dir; + if (s == NULL) + vlen = 32; + else if (q.proto == Q_DECNET) { + vlen = __pcap_atodn(s, &v); + if (vlen == 0) + bpf_error(cstate, "malformed decnet address '%s'", s); + } else { + vlen = __pcap_atoin(s, &v); + if (vlen < 0) + bpf_error(cstate, "invalid IPv4 address '%s'", s); + } + + switch (q.addr) { + + case Q_DEFAULT: + case Q_HOST: + case Q_NET: + if (proto == Q_DECNET) + return gen_host(cstate, v, 0, proto, dir, q.addr); + else if (proto == Q_LINK) { + bpf_error(cstate, "illegal link layer address"); + } else { + mask = 0xffffffff; + if (s == NULL && q.addr == Q_NET) { + /* Promote short net number */ + while (v && (v & 0xff000000) == 0) { + v <<= 8; + mask <<= 8; + } + } else { + /* Promote short ipaddr */ + v <<= 32 - vlen; + mask <<= 32 - vlen ; + } + return gen_host(cstate, v, mask, proto, dir, q.addr); + } + + case Q_PORT: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + bpf_error(cstate, "illegal qualifier of 'port'"); + + if (v > 65535) + bpf_error(cstate, "illegal port number %u > 65535", v); + + { + struct block *b; + b = gen_port(cstate, v, proto, dir); + gen_or(gen_port6(cstate, v, proto, dir), b); + return b; + } + + case Q_PORTRANGE: + if (proto == Q_UDP) + proto = IPPROTO_UDP; + else if (proto == Q_TCP) + proto = IPPROTO_TCP; + else if (proto == Q_SCTP) + proto = IPPROTO_SCTP; + else if (proto == Q_DEFAULT) + proto = PROTO_UNDEF; + else + bpf_error(cstate, "illegal qualifier of 'portrange'"); + + if (v > 65535) + bpf_error(cstate, "illegal port number %u > 65535", v); + + { + struct block *b; + b = gen_portrange(cstate, v, v, proto, dir); + gen_or(gen_portrange6(cstate, v, v, proto, dir), b); + return b; + } + + case Q_GATEWAY: + bpf_error(cstate, "'gateway' requires a name"); + /*NOTREACHED*/ + + case Q_PROTO: + return gen_proto(cstate, v, proto, dir); + +#if !defined(NO_PROTOCHAIN) + case Q_PROTOCHAIN: + return gen_protochain(cstate, v, proto); +#endif + + case Q_UNDEF: + syntax(cstate); + /*NOTREACHED*/ + + default: + abort(); + /*NOTREACHED*/ + } + /*NOTREACHED*/ +} + +#ifdef INET6 +struct block * +gen_mcode6(compiler_state_t *cstate, const char *s, bpf_u_int32 masklen, + struct qual q) +{ + struct addrinfo *res; + struct in6_addr *addr; + struct in6_addr mask; + struct block *b; + bpf_u_int32 a[4], m[4]; /* Same as in gen_hostop6(). */ + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + res = pcap_nametoaddrinfo(s); + if (!res) + bpf_error(cstate, "invalid ip6 address %s", s); + cstate->ai = res; + if (res->ai_next) + bpf_error(cstate, "%s resolved to multiple address", s); + addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + + if (masklen > sizeof(mask.s6_addr) * 8) + bpf_error(cstate, "mask length must be <= %zu", sizeof(mask.s6_addr) * 8); + memset(&mask, 0, sizeof(mask)); + memset(&mask.s6_addr, 0xff, masklen / 8); + if (masklen % 8) { + mask.s6_addr[masklen / 8] = + (0xff << (8 - masklen % 8)) & 0xff; + } + + memcpy(a, addr, sizeof(a)); + memcpy(m, &mask, sizeof(m)); + if ((a[0] & ~m[0]) || (a[1] & ~m[1]) + || (a[2] & ~m[2]) || (a[3] & ~m[3])) { + bpf_error(cstate, "non-network bits set in \"%s/%d\"", s, masklen); + } + + switch (q.addr) { + + case Q_DEFAULT: + case Q_HOST: + if (masklen != 128) + bpf_error(cstate, "Mask syntax for networks only"); + /* FALLTHROUGH */ + + case Q_NET: + b = gen_host6(cstate, addr, &mask, q.proto, q.dir, q.addr); + cstate->ai = NULL; + freeaddrinfo(res); + return b; + + default: + bpf_error(cstate, "invalid qualifier against IPv6 address"); + /*NOTREACHED*/ + } +} +#endif /*INET6*/ + +struct block * +gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) +{ + struct block *b, *tmp; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); + switch (cstate->linktype) { + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + tmp = gen_prevlinkhdr_check(cstate); + b = gen_ehostop(cstate, cstate->e, (int)q.dir); + if (tmp != NULL) + gen_and(tmp, b); + break; + case DLT_FDDI: + b = gen_fhostop(cstate, cstate->e, (int)q.dir); + break; + case DLT_IEEE802: + b = gen_thostop(cstate, cstate->e, (int)q.dir); + break; + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + b = gen_wlanhostop(cstate, cstate->e, (int)q.dir); + break; + case DLT_IP_OVER_FC: + b = gen_ipfchostop(cstate, cstate->e, (int)q.dir); + break; + default: + free(cstate->e); + cstate->e = NULL; + bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + /*NOTREACHED*/ + } + free(cstate->e); + cstate->e = NULL; + return (b); + } + bpf_error(cstate, "ethernet address used in non-ether expression"); + /*NOTREACHED*/ +} + +void +sappend(struct slist *s0, struct slist *s1) +{ + /* + * This is definitely not the best way to do this, but the + * lists will rarely get long. + */ + while (s0->next) + s0 = s0->next; + s0->next = s1; +} + +static struct slist * +xfer_to_x(compiler_state_t *cstate, struct arth *a) +{ + struct slist *s; + + s = new_stmt(cstate, BPF_LDX|BPF_MEM); + s->s.k = a->regno; + return s; +} + +static struct slist * +xfer_to_a(compiler_state_t *cstate, struct arth *a) +{ + struct slist *s; + + s = new_stmt(cstate, BPF_LD|BPF_MEM); + s->s.k = a->regno; + return s; +} + +/* + * Modify "index" to use the value stored into its register as an + * offset relative to the beginning of the header for the protocol + * "proto", and allocate a register and put an item "size" bytes long + * (1, 2, or 4) at that offset into that register, making it the register + * for "index". + */ +static struct arth * +gen_load_internal(compiler_state_t *cstate, int proto, struct arth *inst, + bpf_u_int32 size) +{ + int size_code; + struct slist *s, *tmp; + struct block *b; + int regno = alloc_reg(cstate); + + free_reg(cstate, inst->regno); + switch (size) { + + default: + bpf_error(cstate, "data size must be 1, 2, or 4"); + /*NOTREACHED*/ + + case 1: + size_code = BPF_B; + break; + + case 2: + size_code = BPF_H; + break; + + case 4: + size_code = BPF_W; + break; + } + switch (proto) { + default: + bpf_error(cstate, "unsupported index operation"); + + case Q_RADIO: + /* + * The offset is relative to the beginning of the packet + * data, if we have a radio header. (If we don't, this + * is an error.) + */ + if (cstate->linktype != DLT_IEEE802_11_RADIO_AVS && + cstate->linktype != DLT_IEEE802_11_RADIO && + cstate->linktype != DLT_PRISM_HEADER) + bpf_error(cstate, "radio information not present in capture"); + + /* + * Load into the X register the offset computed into the + * register specified by "index". + */ + s = xfer_to_x(cstate, inst); + + /* + * Load the item at that offset. + */ + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); + sappend(s, tmp); + sappend(inst->s, s); + break; + + case Q_LINK: + /* + * The offset is relative to the beginning of + * the link-layer header. + * + * XXX - what about ATM LANE? Should the index be + * relative to the beginning of the AAL5 frame, so + * that 0 refers to the beginning of the LE Control + * field, or relative to the beginning of the LAN + * frame, so that 0 refers, for Ethernet LANE, to + * the beginning of the destination address? + */ + s = gen_abs_offset_varpart(cstate, &cstate->off_linkhdr); + + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the length of the prefix preceding + * the link-layer header. Add to it the offset computed + * into the register specified by "index", and move that + * into the X register. Otherwise, just load into the X + * register the offset computed into the register specified + * by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(cstate, inst)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + } else + s = xfer_to_x(cstate, inst); + + /* + * Load the item at the sum of the offset we've put in the + * X register and the offset of the start of the link + * layer header (which is 0 if the radio header is + * variable-length; that header length is what we put + * into the X register and then added to the index). + */ + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); + tmp->s.k = cstate->off_linkhdr.constant_part; + sappend(s, tmp); + sappend(inst->s, s); + break; + + case Q_IP: + case Q_ARP: + case Q_RARP: + case Q_ATALK: + case Q_DECNET: + case Q_SCA: + case Q_LAT: + case Q_MOPRC: + case Q_MOPDL: + case Q_IPV6: + /* + * The offset is relative to the beginning of + * the network-layer header. + * XXX - are there any cases where we want + * cstate->off_nl_nosnap? + */ + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); + + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the variable part of the offset + * of the link-layer payload. Add to it the offset + * computed into the register specified by "index", + * and move that into the X register. Otherwise, just + * load into the X register the offset computed into + * the register specified by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(cstate, inst)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + } else + s = xfer_to_x(cstate, inst); + + /* + * Load the item at the sum of the offset we've put in the + * X register, the offset of the start of the network + * layer header from the beginning of the link-layer + * payload, and the constant part of the offset of the + * start of the link-layer payload. + */ + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + sappend(s, tmp); + sappend(inst->s, s); + + /* + * Do the computation only if the packet contains + * the protocol in question. + */ + b = gen_proto_abbrev_internal(cstate, proto); + if (inst->b) + gen_and(inst->b, b); + inst->b = b; + break; + + case Q_SCTP: + case Q_TCP: + case Q_UDP: + case Q_ICMP: + case Q_IGMP: + case Q_IGRP: + case Q_PIM: + case Q_VRRP: + case Q_CARP: + /* + * The offset is relative to the beginning of + * the transport-layer header. + * + * Load the X register with the length of the IPv4 header + * (plus the offset of the link-layer header, if it's + * a variable-length header), in bytes. + * + * XXX - are there any cases where we want + * cstate->off_nl_nosnap? + * XXX - we should, if we're built with + * IPv6 support, generate code to load either + * IPv4, IPv6, or both, as appropriate. + */ + s = gen_loadx_iphdrlen(cstate); + + /* + * The X register now contains the sum of the variable + * part of the offset of the link-layer payload and the + * length of the network-layer header. + * + * Load into the A register the offset relative to + * the beginning of the transport layer header, + * add the X register to that, move that to the + * X register, and load with an offset from the + * X register equal to the sum of the constant part of + * the offset of the link-layer payload and the offset, + * relative to the beginning of the link-layer payload, + * of the network-layer header. + */ + sappend(s, xfer_to_a(cstate, inst)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + sappend(s, tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code)); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl; + sappend(inst->s, s); + + /* + * Do the computation only if the packet contains + * the protocol in question - which is true only + * if this is an IP datagram and is the first or + * only fragment of that datagram. + */ + gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate)); + if (inst->b) + gen_and(inst->b, b); + gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b); + inst->b = b; + break; + case Q_ICMPV6: + /* + * Do the computation only if the packet contains + * the protocol in question. + */ + b = gen_proto_abbrev_internal(cstate, Q_IPV6); + if (inst->b) + gen_and(inst->b, b); + inst->b = b; + + /* + * Check if we have an icmp6 next header + */ + b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58); + if (inst->b) + gen_and(inst->b, b); + inst->b = b; + + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the variable part of the offset + * of the link-layer payload. Add to it the offset + * computed into the register specified by "index", + * and move that into the X register. Otherwise, just + * load into the X register the offset computed into + * the register specified by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(cstate, inst)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + } else + s = xfer_to_x(cstate, inst); + + /* + * Load the item at the sum of the offset we've put in the + * X register, the offset of the start of the network + * layer header from the beginning of the link-layer + * payload, and the constant part of the offset of the + * start of the link-layer payload. + */ + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size_code); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40; + + sappend(s, tmp); + sappend(inst->s, s); + + break; + } + inst->regno = regno; + s = new_stmt(cstate, BPF_ST); + s->s.k = regno; + sappend(inst->s, s); + + return inst; +} + +struct arth * +gen_load(compiler_state_t *cstate, int proto, struct arth *inst, + bpf_u_int32 size) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_load_internal(cstate, proto, inst, size); +} + +static struct block * +gen_relation_internal(compiler_state_t *cstate, int code, struct arth *a0, + struct arth *a1, int reversed) +{ + struct slist *s0, *s1, *s2; + struct block *b, *tmp; + + s0 = xfer_to_x(cstate, a1); + s1 = xfer_to_a(cstate, a0); + if (code == BPF_JEQ) { + s2 = new_stmt(cstate, BPF_ALU|BPF_SUB|BPF_X); + b = new_block(cstate, JMP(code)); + sappend(s1, s2); + } + else + b = new_block(cstate, BPF_JMP|code|BPF_X); + if (reversed) + gen_not(b); + + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + b->stmts = a0->s; + + free_reg(cstate, a0->regno); + free_reg(cstate, a1->regno); + + /* 'and' together protocol checks */ + if (a0->b) { + if (a1->b) { + gen_and(a0->b, tmp = a1->b); + } + else + tmp = a0->b; + } else + tmp = a1->b; + + if (tmp) + gen_and(tmp, b); + + return b; +} + +struct block * +gen_relation(compiler_state_t *cstate, int code, struct arth *a0, + struct arth *a1, int reversed) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_relation_internal(cstate, code, a0, a1, reversed); +} + +struct arth * +gen_loadlen(compiler_state_t *cstate) +{ + int regno; + struct arth *a; + struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + regno = alloc_reg(cstate); + a = (struct arth *)newchunk(cstate, sizeof(*a)); + s = new_stmt(cstate, BPF_LD|BPF_LEN); + s->next = new_stmt(cstate, BPF_ST); + s->next->s.k = regno; + a->s = s; + a->regno = regno; + + return a; +} + +static struct arth * +gen_loadi_internal(compiler_state_t *cstate, bpf_u_int32 val) +{ + struct arth *a; + struct slist *s; + int reg; + + a = (struct arth *)newchunk(cstate, sizeof(*a)); + + reg = alloc_reg(cstate); + + s = new_stmt(cstate, BPF_LD|BPF_IMM); + s->s.k = val; + s->next = new_stmt(cstate, BPF_ST); + s->next->s.k = reg; + a->s = s; + a->regno = reg; + + return a; +} + +struct arth * +gen_loadi(compiler_state_t *cstate, bpf_u_int32 val) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_loadi_internal(cstate, val); +} + +/* + * The a_arg dance is to avoid annoying whining by compilers that + * a might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ +struct arth * +gen_neg(compiler_state_t *cstate, struct arth *a_arg) +{ + struct arth *a = a_arg; + struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + s = xfer_to_a(cstate, a); + sappend(a->s, s); + s = new_stmt(cstate, BPF_ALU|BPF_NEG); + s->s.k = 0; + sappend(a->s, s); + s = new_stmt(cstate, BPF_ST); + s->s.k = a->regno; + sappend(a->s, s); + + return a; +} + +/* + * The a0_arg dance is to avoid annoying whining by compilers that + * a0 might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ +struct arth * +gen_arth(compiler_state_t *cstate, int code, struct arth *a0_arg, + struct arth *a1) +{ + struct arth *a0 = a0_arg; + struct slist *s0, *s1, *s2; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Disallow division by, or modulus by, zero; we do this here + * so that it gets done even if the optimizer is disabled. + * + * Also disallow shifts by a value greater than 31; we do this + * here, for the same reason. + */ + if (code == BPF_DIV) { + if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) + bpf_error(cstate, "division by zero"); + } else if (code == BPF_MOD) { + if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) + bpf_error(cstate, "modulus by zero"); + } else if (code == BPF_LSH || code == BPF_RSH) { + if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k > 31) + bpf_error(cstate, "shift by more than 31 bits"); + } + s0 = xfer_to_x(cstate, a1); + s1 = xfer_to_a(cstate, a0); + s2 = new_stmt(cstate, BPF_ALU|BPF_X|code); + + sappend(s1, s2); + sappend(s0, s1); + sappend(a1->s, s0); + sappend(a0->s, a1->s); + + free_reg(cstate, a0->regno); + free_reg(cstate, a1->regno); + + s0 = new_stmt(cstate, BPF_ST); + a0->regno = s0->s.k = alloc_reg(cstate); + sappend(a0->s, s0); + + return a0; +} + +/* + * Initialize the table of used registers and the current register. + */ +static void +init_regs(compiler_state_t *cstate) +{ + cstate->curreg = 0; + memset(cstate->regused, 0, sizeof cstate->regused); +} + +/* + * Return the next free register. + */ +static int +alloc_reg(compiler_state_t *cstate) +{ + int n = BPF_MEMWORDS; + + while (--n >= 0) { + if (cstate->regused[cstate->curreg]) + cstate->curreg = (cstate->curreg + 1) % BPF_MEMWORDS; + else { + cstate->regused[cstate->curreg] = 1; + return cstate->curreg; + } + } + bpf_error(cstate, "too many registers needed to evaluate expression"); + /*NOTREACHED*/ +} + +/* + * Return a register to the table so it can + * be used later. + */ +static void +free_reg(compiler_state_t *cstate, int n) +{ + cstate->regused[n] = 0; +} + +static struct block * +gen_len(compiler_state_t *cstate, int jmp, int n) +{ + struct slist *s; + struct block *b; + + s = new_stmt(cstate, BPF_LD|BPF_LEN); + b = new_block(cstate, JMP(jmp)); + b->stmts = s; + b->s.k = n; + + return b; +} + +struct block * +gen_greater(compiler_state_t *cstate, int n) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_len(cstate, BPF_JGE, n); +} + +/* + * Actually, this is less than or equal. + */ +struct block * +gen_less(compiler_state_t *cstate, int n) +{ + struct block *b; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + b = gen_len(cstate, BPF_JGT, n); + gen_not(b); + + return b; +} + +/* + * This is for "byte {idx} {op} {val}"; "idx" is treated as relative to + * the beginning of the link-layer header. + * XXX - that means you can't test values in the radiotap header, but + * as that header is difficult if not impossible to parse generally + * without a loop, that might not be a severe problem. A new keyword + * "radio" could be added for that, although what you'd really want + * would be a way of testing particular radio header values, which + * would generate code appropriate to the radio header in question. + */ +struct block * +gen_byteop(compiler_state_t *cstate, int op, int idx, bpf_u_int32 val) +{ + struct block *b; + struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (op) { + default: + abort(); + + case '=': + return gen_cmp(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); + + case '<': + b = gen_cmp_lt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); + return b; + + case '>': + b = gen_cmp_gt(cstate, OR_LINKHDR, (u_int)idx, BPF_B, val); + return b; + + case '|': + s = new_stmt(cstate, BPF_ALU|BPF_OR|BPF_K); + break; + + case '&': + s = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + break; + } + s->s.k = val; + b = new_block(cstate, JMP(BPF_JEQ)); + b->stmts = s; + gen_not(b); + + return b; +} + +static const u_char abroadcast[] = { 0x0 }; + +struct block * +gen_broadcast(compiler_state_t *cstate, int proto) +{ + bpf_u_int32 hostmask; + struct block *b0, *b1, *b2; + static const u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + switch (cstate->linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + return gen_ahostop(cstate, abroadcast, Q_DST); + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(cstate); + b0 = gen_ehostop(cstate, ebroadcast, Q_DST); + if (b1 != NULL) + gen_and(b1, b0); + return b0; + case DLT_FDDI: + return gen_fhostop(cstate, ebroadcast, Q_DST); + case DLT_IEEE802: + return gen_thostop(cstate, ebroadcast, Q_DST); + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + return gen_wlanhostop(cstate, ebroadcast, Q_DST); + case DLT_IP_OVER_FC: + return gen_ipfchostop(cstate, ebroadcast, Q_DST); + default: + bpf_error(cstate, "not a broadcast link"); + } + /*NOTREACHED*/ + + case Q_IP: + /* + * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff) + * as an indication that we don't know the netmask, and fail + * in that case. + */ + if (cstate->netmask == PCAP_NETMASK_UNKNOWN) + bpf_error(cstate, "netmask not known, so 'ip broadcast' not supported"); + b0 = gen_linktype(cstate, ETHERTYPE_IP); + hostmask = ~cstate->netmask; + b1 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, 0, hostmask); + b2 = gen_mcmp(cstate, OR_LINKPL, 16, BPF_W, + ~0 & hostmask, hostmask); + gen_or(b1, b2); + gen_and(b0, b2); + return b2; + } + bpf_error(cstate, "only link-layer/IP broadcast filters supported"); + /*NOTREACHED*/ +} + +/* + * Generate code to test the low-order bit of a MAC address (that's + * the bottom bit of the *first* byte). + */ +static struct block * +gen_mac_multicast(compiler_state_t *cstate, int offset) +{ + register struct block *b0; + register struct slist *s; + + /* link[offset] & 1 != 0 */ + s = gen_load_a(cstate, OR_LINKHDR, offset, BPF_B); + b0 = new_block(cstate, JMP(BPF_JSET)); + b0->s.k = 1; + b0->stmts = s; + return b0; +} + +struct block * +gen_multicast(compiler_state_t *cstate, int proto) +{ + register struct block *b0, *b1, *b2; + register struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (proto) { + + case Q_DEFAULT: + case Q_LINK: + switch (cstate->linktype) { + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + /* all ARCnet multicasts use the same address */ + return gen_ahostop(cstate, abroadcast, Q_DST); + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b1 = gen_prevlinkhdr_check(cstate); + /* ether[0] & 1 != 0 */ + b0 = gen_mac_multicast(cstate, 0); + if (b1 != NULL) + gen_and(b1, b0); + return b0; + case DLT_FDDI: + /* + * XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX + * + * XXX - was that referring to bit-order issues? + */ + /* fddi[1] & 1 != 0 */ + return gen_mac_multicast(cstate, 1); + case DLT_IEEE802: + /* tr[2] & 1 != 0 */ + return gen_mac_multicast(cstate, 2); + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + case DLT_PPI: + /* + * Oh, yuk. + * + * For control frames, there is no DA. + * + * For management frames, DA is at an + * offset of 4 from the beginning of + * the packet. + * + * For data frames, DA is at an offset + * of 4 from the beginning of the packet + * if To DS is clear and at an offset of + * 16 from the beginning of the packet + * if To DS is set. + */ + + /* + * Generate the tests to be done for data frames. + * + * First, check for To DS set, i.e. "link[1] & 0x01". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x01; /* To DS */ + b1->stmts = s; + + /* + * If To DS is set, the DA is at 16. + */ + b0 = gen_mac_multicast(cstate, 16); + gen_and(b1, b0); + + /* + * Now, check for To DS not set, i.e. check + * "!(link[1] & 0x01)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 1, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x01; /* To DS */ + b2->stmts = s; + gen_not(b2); + + /* + * If To DS is not set, the DA is at 4. + */ + b1 = gen_mac_multicast(cstate, 4); + gen_and(b2, b1); + + /* + * Now OR together the last two checks. That gives + * the complete set of checks for data frames. + */ + gen_or(b1, b0); + + /* + * Now check for a data frame. + * I.e, check "link[0] & 0x08". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x08; + b1->stmts = s; + + /* + * AND that with the checks done for data frames. + */ + gen_and(b1, b0); + + /* + * If the high-order bit of the type value is 0, this + * is a management frame. + * I.e, check "!(link[0] & 0x08)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b2 = new_block(cstate, JMP(BPF_JSET)); + b2->s.k = 0x08; + b2->stmts = s; + gen_not(b2); + + /* + * For management frames, the DA is at 4. + */ + b1 = gen_mac_multicast(cstate, 4); + gen_and(b2, b1); + + /* + * OR that with the checks done for data frames. + * That gives the checks done for management and + * data frames. + */ + gen_or(b1, b0); + + /* + * If the low-order bit of the type value is 1, + * this is either a control frame or a frame + * with a reserved type, and thus not a + * frame with an SA. + * + * I.e., check "!(link[0] & 0x04)". + */ + s = gen_load_a(cstate, OR_LINKHDR, 0, BPF_B); + b1 = new_block(cstate, JMP(BPF_JSET)); + b1->s.k = 0x04; + b1->stmts = s; + gen_not(b1); + + /* + * AND that with the checks for data and management + * frames. + */ + gen_and(b1, b0); + return b0; + case DLT_IP_OVER_FC: + b0 = gen_mac_multicast(cstate, 2); + return b0; + default: + break; + } + /* Link not known to support multicasts */ + break; + + case Q_IP: + b0 = gen_linktype(cstate, ETHERTYPE_IP); + b1 = gen_cmp_ge(cstate, OR_LINKPL, 16, BPF_B, 224); + gen_and(b0, b1); + return b1; + + case Q_IPV6: + b0 = gen_linktype(cstate, ETHERTYPE_IPV6); + b1 = gen_cmp(cstate, OR_LINKPL, 24, BPF_B, 255); + gen_and(b0, b1); + return b1; + } + bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); + /*NOTREACHED*/ +} + +struct block * +gen_ifindex(compiler_state_t *cstate, int ifindex) +{ + register struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Only some data link types support ifindex qualifiers. + */ + switch (cstate->linktype) { + case DLT_LINUX_SLL2: + /* match packets on this interface */ + b0 = gen_cmp(cstate, OR_LINKHDR, 4, BPF_W, ifindex); + break; + default: +#if defined(__linux__) + /* + * This is Linux; we require PF_PACKET support. + * If this is a *live* capture, we can look at + * special meta-data in the filter expression; + * if it's a savefile, we can't. + */ + if (cstate->bpf_pcap->rfile != NULL) { + /* We have a FILE *, so this is a savefile */ + bpf_error(cstate, "ifindex not supported on %s when reading savefiles", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } + /* match ifindex */ + b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_IFINDEX, BPF_W, + ifindex); +#else /* defined(__linux__) */ + bpf_error(cstate, "ifindex not supported on %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ +#endif /* defined(__linux__) */ + } + return (b0); +} + +/* + * Filter on inbound (dir == 0) or outbound (dir == 1) traffic. + * Outbound traffic is sent by this machine, while inbound traffic is + * sent by a remote machine (and may include packets destined for a + * unicast or multicast link-layer address we are not subscribing to). + * These are the same definitions implemented by pcap_setdirection(). + * Capturing only unicast traffic destined for this host is probably + * better accomplished using a higher-layer filter. + */ +struct block * +gen_inbound(compiler_state_t *cstate, int dir) +{ + register struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Only some data link types support inbound/outbound qualifiers. + */ + switch (cstate->linktype) { + case DLT_SLIP: + b0 = gen_relation_internal(cstate, BPF_JEQ, + gen_load_internal(cstate, Q_LINK, gen_loadi_internal(cstate, 0), 1), + gen_loadi_internal(cstate, 0), + dir); + break; + + case DLT_IPNET: + if (dir) { + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_OUTBOUND); + } else { + /* match incoming packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 2, BPF_H, IPNET_INBOUND); + } + break; + + case DLT_LINUX_SLL: + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_H, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } + break; + + case DLT_LINUX_SLL2: + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } + break; + + case DLT_PFLOG: + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, + ((dir == 0) ? PF_IN : PF_OUT)); + break; + + case DLT_PPP_PPPD: + if (dir) { + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_OUT); + } else { + /* match incoming packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 0, BPF_B, PPP_PPPD_IN); + } + break; + + case DLT_JUNIPER_MFR: + case DLT_JUNIPER_MLFR: + case DLT_JUNIPER_MLPPP: + case DLT_JUNIPER_ATM1: + case DLT_JUNIPER_ATM2: + case DLT_JUNIPER_PPPOE: + case DLT_JUNIPER_PPPOE_ATM: + case DLT_JUNIPER_GGSN: + case DLT_JUNIPER_ES: + case DLT_JUNIPER_MONITOR: + case DLT_JUNIPER_SERVICES: + case DLT_JUNIPER_ETHER: + case DLT_JUNIPER_PPP: + case DLT_JUNIPER_FRELAY: + case DLT_JUNIPER_CHDLC: + case DLT_JUNIPER_VP: + case DLT_JUNIPER_ST: + case DLT_JUNIPER_ISM: + case DLT_JUNIPER_VS: + case DLT_JUNIPER_SRX_E2E: + case DLT_JUNIPER_FIBRECHANNEL: + case DLT_JUNIPER_ATM_CEMIC: + + /* juniper flags (including direction) are stored + * the byte after the 3-byte magic number */ + if (dir) { + /* match outgoing packets */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 0, 0x01); + } else { + /* match incoming packets */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 3, BPF_B, 1, 0x01); + } + break; + + default: + /* + * If we have packet meta-data indicating a direction, + * and that metadata can be checked by BPF code, check + * it. Otherwise, give up, as this link-layer type has + * nothing in the packet data. + * + * Currently, the only platform where a BPF filter can + * check that metadata is Linux with the in-kernel + * BPF interpreter. If other packet capture mechanisms + * and BPF filters also supported this, it would be + * nice. It would be even better if they made that + * metadata available so that we could provide it + * with newer capture APIs, allowing it to be saved + * in pcapng files. + */ +#if defined(__linux__) + /* + * This is Linux; we require PF_PACKET support. + * If this is a *live* capture, we can look at + * special meta-data in the filter expression; + * if it's a savefile, we can't. + */ + if (cstate->bpf_pcap->rfile != NULL) { + /* We have a FILE *, so this is a savefile */ + bpf_error(cstate, "inbound/outbound not supported on %s when reading savefiles", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, SKF_AD_OFF + SKF_AD_PKTTYPE, BPF_H, + PACKET_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } +#else /* defined(__linux__) */ + bpf_error(cstate, "inbound/outbound not supported on %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ +#endif /* defined(__linux__) */ + } + return (b0); +} + +/* PF firewall log matched interface */ +struct block * +gen_pf_ifname(compiler_state_t *cstate, const char *ifname) +{ + struct block *b0; + u_int len, off; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "ifname supported only on PF linktype"); + /*NOTREACHED*/ + } + len = sizeof(((struct pfloghdr *)0)->ifname); + off = offsetof(struct pfloghdr, ifname); + if (strlen(ifname) >= len) { + bpf_error(cstate, "ifname interface names can only be %d characters", + len-1); + /*NOTREACHED*/ + } + b0 = gen_bcmp(cstate, OR_LINKHDR, off, (u_int)strlen(ifname), + (const u_char *)ifname); + return (b0); +} + +/* PF firewall log ruleset name */ +struct block * +gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "ruleset supported only on PF linktype"); + /*NOTREACHED*/ + } + + if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { + bpf_error(cstate, "ruleset names can only be %ld characters", + (long)(sizeof(((struct pfloghdr *)0)->ruleset) - 1)); + /*NOTREACHED*/ + } + + b0 = gen_bcmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, ruleset), + (u_int)strlen(ruleset), (const u_char *)ruleset); + return (b0); +} + +/* PF firewall log rule number */ +struct block * +gen_pf_rnr(compiler_state_t *cstate, int rnr) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "rnr supported only on PF linktype"); + /*NOTREACHED*/ + } + + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, rulenr), BPF_W, + (bpf_u_int32)rnr); + return (b0); +} + +/* PF firewall log sub-rule number */ +struct block * +gen_pf_srnr(compiler_state_t *cstate, int srnr) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "srnr supported only on PF linktype"); + /*NOTREACHED*/ + } + + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, subrulenr), BPF_W, + (bpf_u_int32)srnr); + return (b0); +} + +/* PF firewall log reason code */ +struct block * +gen_pf_reason(compiler_state_t *cstate, int reason) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "reason supported only on PF linktype"); + /*NOTREACHED*/ + } + + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, reason), BPF_B, + (bpf_u_int32)reason); + return (b0); +} + +/* PF firewall log action */ +struct block * +gen_pf_action(compiler_state_t *cstate, int action) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->linktype != DLT_PFLOG) { + bpf_error(cstate, "action supported only on PF linktype"); + /*NOTREACHED*/ + } + + b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, action), BPF_B, + (bpf_u_int32)action); + return (b0); +} + +/* IEEE 802.11 wireless header */ +struct block * +gen_p80211_type(compiler_state_t *cstate, bpf_u_int32 type, bpf_u_int32 mask) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (cstate->linktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, type, mask); + break; + + default: + bpf_error(cstate, "802.11 link-layer types supported only on 802.11"); + /*NOTREACHED*/ + } + + return (b0); +} + +struct block * +gen_p80211_fcdir(compiler_state_t *cstate, bpf_u_int32 fcdir) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (cstate->linktype) { + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + break; + + default: + bpf_error(cstate, "frame direction supported only with 802.11 headers"); + /*NOTREACHED*/ + } + + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, fcdir, + IEEE80211_FC1_DIR_MASK); + + return (b0); +} + +struct block * +gen_acode(compiler_state_t *cstate, const char *s, struct qual q) +{ + struct block *b; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (cstate->linktype) { + + case DLT_ARCNET: + case DLT_ARCNET_LINUX: + if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && + q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); + b = gen_ahostop(cstate, cstate->e, (int)q.dir); + free(cstate->e); + cstate->e = NULL; + return (b); + } else + bpf_error(cstate, "ARCnet address used in non-arc expression"); + /*NOTREACHED*/ + + default: + bpf_error(cstate, "aid supported only on ARCnet"); + /*NOTREACHED*/ + } +} + +static struct block * +gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) +{ + register struct block *b0, *b1; + + switch (dir) { + /* src comes first, different from Ethernet */ + case Q_SRC: + return gen_bcmp(cstate, OR_LINKHDR, 0, 1, eaddr); + + case Q_DST: + return gen_bcmp(cstate, OR_LINKHDR, 1, 1, eaddr); + + case Q_AND: + b0 = gen_ahostop(cstate, eaddr, Q_SRC); + b1 = gen_ahostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_ahostop(cstate, eaddr, Q_SRC); + b1 = gen_ahostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); + /*NOTREACHED*/ + + case Q_RA: + bpf_error(cstate, "'ra' is only supported on 802.11"); + /*NOTREACHED*/ + + case Q_TA: + bpf_error(cstate, "'ta' is only supported on 802.11"); + /*NOTREACHED*/ + } + abort(); + /*NOTREACHED*/ +} + +static struct block * +gen_vlan_tpid_test(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + /* check for VLAN, including 802.1ad and QinQ */ + b0 = gen_linktype(cstate, ETHERTYPE_8021Q); + b1 = gen_linktype(cstate, ETHERTYPE_8021AD); + gen_or(b0,b1); + b0 = b1; + b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ); + gen_or(b0,b1); + + return b1; +} + +static struct block * +gen_vlan_vid_test(compiler_state_t *cstate, bpf_u_int32 vlan_num) +{ + if (vlan_num > 0x0fff) { + bpf_error(cstate, "VLAN tag %u greater than maximum %u", + vlan_num, 0x0fff); + } + return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, vlan_num, 0x0fff); +} + +static struct block * +gen_vlan_no_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, + int has_vlan_tag) +{ + struct block *b0, *b1; + + b0 = gen_vlan_tpid_test(cstate); + + if (has_vlan_tag) { + b1 = gen_vlan_vid_test(cstate, vlan_num); + gen_and(b0, b1); + b0 = b1; + } + + /* + * Both payload and link header type follow the VLAN tags so that + * both need to be updated. + */ + cstate->off_linkpl.constant_part += 4; + cstate->off_linktype.constant_part += 4; + + return b0; +} + +#if defined(SKF_AD_VLAN_TAG_PRESENT) +/* add v to variable part of off */ +static void +gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, + bpf_u_int32 v, struct slist *s) +{ + struct slist *s2; + + if (!off->is_variable) + off->is_variable = 1; + if (off->reg == -1) + off->reg = alloc_reg(cstate); + + s2 = new_stmt(cstate, BPF_LD|BPF_MEM); + s2->s.k = off->reg; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = v; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = off->reg; + sappend(s, s2); +} + +/* + * patch block b_tpid (VLAN TPID test) to update variable parts of link payload + * and link type offsets first + */ +static void +gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid) +{ + struct slist s; + + /* offset determined at run time, shift variable part */ + s.next = NULL; + cstate->is_vlan_vloffset = 1; + gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s); + gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s); + + /* we get a pointer to a chain of or-ed blocks, patch first of them */ + sappend(s.next, b_tpid->head->stmts); + b_tpid->head->stmts = s.next; +} + +/* + * patch block b_vid (VLAN id test) to load VID value either from packet + * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true + */ +static void +gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid) +{ + struct slist *s, *s2, *sjeq; + unsigned cnt; + + s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; + + /* true -> next instructions, false -> beginning of b_vid */ + sjeq = new_stmt(cstate, JMP(BPF_JEQ)); + sjeq->s.k = 1; + sjeq->s.jf = b_vid->stmts; + sappend(s, sjeq); + + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; + sappend(s, s2); + sjeq->s.jt = s2; + + /* Jump to the test in b_vid. We need to jump one instruction before + * the end of the b_vid block so that we only skip loading the TCI + * from packet data and not the 'and' instruction extracting VID. + */ + cnt = 0; + for (s2 = b_vid->stmts; s2; s2 = s2->next) + cnt++; + s2 = new_stmt(cstate, JMP(BPF_JA)); + s2->s.k = cnt - 1; + sappend(s, s2); + + /* insert our statements at the beginning of b_vid */ + sappend(s, b_vid->stmts); + b_vid->stmts = s; +} + +/* + * Generate check for "vlan" or "vlan " on systems with support for BPF + * extensions. Even if kernel supports VLAN BPF extensions, (outermost) VLAN + * tag can be either in metadata or in packet data; therefore if the + * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link + * header for VLAN tag. As the decision is done at run time, we need + * update variable part of the offsets + */ +static struct block * +gen_vlan_bpf_extensions(compiler_state_t *cstate, bpf_u_int32 vlan_num, + int has_vlan_tag) +{ + struct block *b0, *b_tpid, *b_vid = NULL; + struct slist *s; + + /* generate new filter code based on extracting packet + * metadata */ + s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; + + b0 = new_block(cstate, JMP(BPF_JEQ)); + b0->stmts = s; + b0->s.k = 1; + + /* + * This is tricky. We need to insert the statements updating variable + * parts of offsets before the traditional TPID and VID tests so + * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but + * we do not want this update to affect those checks. That's why we + * generate both test blocks first and insert the statements updating + * variable parts of both offsets after that. This wouldn't work if + * there already were variable length link header when entering this + * function but gen_vlan_bpf_extensions() isn't called in that case. + */ + b_tpid = gen_vlan_tpid_test(cstate); + if (has_vlan_tag) + b_vid = gen_vlan_vid_test(cstate, vlan_num); + + gen_vlan_patch_tpid_test(cstate, b_tpid); + gen_or(b0, b_tpid); + b0 = b_tpid; + + if (has_vlan_tag) { + gen_vlan_patch_vid_test(cstate, b_vid); + gen_and(b0, b_vid); + b0 = b_vid; + } + + return b0; +} +#endif + +/* + * support IEEE 802.1Q VLAN trunk over ethernet + */ +struct block * +gen_vlan(compiler_state_t *cstate, bpf_u_int32 vlan_num, int has_vlan_tag) +{ + struct block *b0; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* can't check for VLAN-encapsulated packets inside MPLS */ + if (cstate->label_stack_depth > 0) + bpf_error(cstate, "no VLAN match after MPLS"); + + /* + * Check for a VLAN packet, and then change the offsets to point + * to the type and data fields within the VLAN packet. Just + * increment the offsets, so that we can support a hierarchy, e.g. + * "vlan 300 && vlan 200" to capture VLAN 200 encapsulated within + * VLAN 100. + * + * XXX - this is a bit of a kludge. If we were to split the + * compiler into a parser that parses an expression and + * generates an expression tree, and a code generator that + * takes an expression tree (which could come from our + * parser or from some other parser) and generates BPF code, + * we could perhaps make the offsets parameters of routines + * and, in the handler for an "AND" node, pass to subnodes + * other than the VLAN node the adjusted offsets. + * + * This would mean that "vlan" would, instead of changing the + * behavior of *all* tests after it, change only the behavior + * of tests ANDed with it. That would change the documented + * semantics of "vlan", which might break some expressions. + * However, it would mean that "(vlan and ip) or ip" would check + * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than + * checking only for VLAN-encapsulated IP, so that could still + * be considered worth doing; it wouldn't break expressions + * that are of the form "vlan and ..." or "vlan N and ...", + * which I suspect are the most common expressions involving + * "vlan". "vlan or ..." doesn't necessarily do what the user + * would really want, now, as all the "or ..." tests would + * be done assuming a VLAN, even though the "or" could be viewed + * as meaning "or, if this isn't a VLAN packet...". + */ + switch (cstate->linktype) { + + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: +#if defined(SKF_AD_VLAN_TAG_PRESENT) + /* Verify that this is the outer part of the packet and + * not encapsulated somehow. */ + if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable && + cstate->off_linkhdr.constant_part == + cstate->off_outermostlinkhdr.constant_part) { + /* + * Do we need special VLAN handling? + */ + if (cstate->bpf_pcap->bpf_codegen_flags & BPF_SPECIAL_VLAN_HANDLING) + b0 = gen_vlan_bpf_extensions(cstate, vlan_num, + has_vlan_tag); + else + b0 = gen_vlan_no_bpf_extensions(cstate, + vlan_num, has_vlan_tag); + } else +#endif + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, + has_vlan_tag); + break; + + case DLT_IEEE802_11: + case DLT_PRISM_HEADER: + case DLT_IEEE802_11_RADIO_AVS: + case DLT_IEEE802_11_RADIO: + b0 = gen_vlan_no_bpf_extensions(cstate, vlan_num, has_vlan_tag); + break; + + default: + bpf_error(cstate, "no VLAN support for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } + + cstate->vlan_stack_depth++; + + return (b0); +} + +/* + * support for MPLS + * + * The label_num_arg dance is to avoid annoying whining by compilers that + * label_num might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ +struct block * +gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num_arg, + int has_label_num) +{ + volatile bpf_u_int32 label_num = label_num_arg; + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + if (cstate->label_stack_depth > 0) { + /* just match the bottom-of-stack bit clear */ + b0 = gen_mcmp(cstate, OR_PREVMPLSHDR, 2, BPF_B, 0, 0x01); + } else { + /* + * We're not in an MPLS stack yet, so check the link-layer + * type against MPLS. + */ + switch (cstate->linktype) { + + case DLT_C_HDLC: /* fall through */ + case DLT_HDLC: + case DLT_EN10MB: + case DLT_NETANALYZER: + case DLT_NETANALYZER_TRANSPARENT: + b0 = gen_linktype(cstate, ETHERTYPE_MPLS); + break; + + case DLT_PPP: + b0 = gen_linktype(cstate, PPP_MPLS_UCAST); + break; + + /* FIXME add other DLT_s ... + * for Frame-Relay/and ATM this may get messy due to SNAP headers + * leave it for now */ + + default: + bpf_error(cstate, "no MPLS support for %s", + pcap_datalink_val_to_description_or_dlt(cstate->linktype)); + /*NOTREACHED*/ + } + } + + /* If a specific MPLS label is requested, check it */ + if (has_label_num) { + if (label_num > 0xFFFFF) { + bpf_error(cstate, "MPLS label %u greater than maximum %u", + label_num, 0xFFFFF); + } + label_num = label_num << 12; /* label is shifted 12 bits on the wire */ + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, label_num, + 0xfffff000); /* only compare the first 20 bits */ + gen_and(b0, b1); + b0 = b1; + } + + /* + * Change the offsets to point to the type and data fields within + * the MPLS packet. Just increment the offsets, so that we + * can support a hierarchy, e.g. "mpls 100000 && mpls 1024" to + * capture packets with an outer label of 100000 and an inner + * label of 1024. + * + * Increment the MPLS stack depth as well; this indicates that + * we're checking MPLS-encapsulated headers, to make sure higher + * level code generators don't try to match against IP-related + * protocols such as Q_ARP, Q_RARP etc. + * + * XXX - this is a bit of a kludge. See comments in gen_vlan(). + */ + cstate->off_nl_nosnap += 4; + cstate->off_nl += 4; + cstate->label_stack_depth++; + return (b0); +} + +/* + * Support PPPOE discovery and session. + */ +struct block * +gen_pppoed(compiler_state_t *cstate) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* check for PPPoE discovery */ + return gen_linktype(cstate, ETHERTYPE_PPPOED); +} + +struct block * +gen_pppoes(compiler_state_t *cstate, bpf_u_int32 sess_num, int has_sess_num) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + /* + * Test against the PPPoE session link-layer type. + */ + b0 = gen_linktype(cstate, ETHERTYPE_PPPOES); + + /* If a specific session is requested, check PPPoE session id */ + if (has_sess_num) { + if (sess_num > 0x0000ffff) { + bpf_error(cstate, "PPPoE session number %u greater than maximum %u", + sess_num, 0x0000ffff); + } + b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, sess_num, 0x0000ffff); + gen_and(b0, b1); + b0 = b1; + } + + /* + * Change the offsets to point to the type and data fields within + * the PPP packet, and note that this is PPPoE rather than + * raw PPP. + * + * XXX - this is a bit of a kludge. See the comments in + * gen_vlan(). + * + * The "network-layer" protocol is PPPoE, which has a 6-byte + * PPPoE header, followed by a PPP packet. + * + * There is no HDLC encapsulation for the PPP packet (it's + * encapsulated in PPPoES instead), so the link-layer type + * starts at the first byte of the PPP packet. For PPPoE, + * that offset is relative to the beginning of the total + * link-layer payload, including any 802.2 LLC header, so + * it's 6 bytes past cstate->off_nl. + */ + PUSH_LINKHDR(cstate, DLT_PPP, cstate->off_linkpl.is_variable, + cstate->off_linkpl.constant_part + cstate->off_nl + 6, /* 6 bytes past the PPPoE header */ + cstate->off_linkpl.reg); + + cstate->off_linktype = cstate->off_linkhdr; + cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 2; + + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + + return b0; +} + +/* Check that this is Geneve and the VNI is correct if + * specified. Parameterized to handle both IPv4 and IPv6. */ +static struct block * +gen_geneve_check(compiler_state_t *cstate, + struct block *(*gen_portfn)(compiler_state_t *, u_int, int, int), + enum e_offrel offrel, bpf_u_int32 vni, int has_vni) +{ + struct block *b0, *b1; + + b0 = gen_portfn(cstate, GENEVE_PORT, IPPROTO_UDP, Q_DST); + + /* Check that we are operating on version 0. Otherwise, we + * can't decode the rest of the fields. The version is 2 bits + * in the first byte of the Geneve header. */ + b1 = gen_mcmp(cstate, offrel, 8, BPF_B, 0, 0xc0); + gen_and(b0, b1); + b0 = b1; + + if (has_vni) { + if (vni > 0xffffff) { + bpf_error(cstate, "Geneve VNI %u greater than maximum %u", + vni, 0xffffff); + } + vni <<= 8; /* VNI is in the upper 3 bytes */ + b1 = gen_mcmp(cstate, offrel, 12, BPF_W, vni, 0xffffff00); + gen_and(b0, b1); + b0 = b1; + } + + return b0; +} + +/* The IPv4 and IPv6 Geneve checks need to do two things: + * - Verify that this actually is Geneve with the right VNI. + * - Place the IP header length (plus variable link prefix if + * needed) into register A to be used later to compute + * the inner packet offsets. */ +static struct block * +gen_geneve4(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(cstate, gen_port, OR_TRAN_IPV4, vni, has_vni); + + /* Load the IP header length into A. */ + s = gen_loadx_iphdrlen(cstate); + + s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); + sappend(s, s1); + + /* Forcibly append these statements to the true condition + * of the protocol check by creating a new block that is + * always true and ANDing them. */ + b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); + b1->stmts = s; + b1->s.k = 0; + + gen_and(b0, b1); + + return b1; +} + +static struct block * +gen_geneve6(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) +{ + struct block *b0, *b1; + struct slist *s, *s1; + + b0 = gen_geneve_check(cstate, gen_port6, OR_TRAN_IPV6, vni, has_vni); + + /* Load the IP header length. We need to account for a + * variable length link prefix if there is one. */ + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); + if (s) { + s1 = new_stmt(cstate, BPF_LD|BPF_IMM); + s1->s.k = 40; + sappend(s, s1); + + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); + s1->s.k = 0; + sappend(s, s1); + } else { + s = new_stmt(cstate, BPF_LD|BPF_IMM); + s->s.k = 40; + } + + /* Forcibly append these statements to the true condition + * of the protocol check by creating a new block that is + * always true and ANDing them. */ + s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s, s1); + + b1 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); + b1->stmts = s; + b1->s.k = 0; + + gen_and(b0, b1); + + return b1; +} + +/* We need to store three values based on the Geneve header:: + * - The offset of the linktype. + * - The offset of the end of the Geneve header. + * - The offset of the end of the encapsulated MAC header. */ +static struct slist * +gen_geneve_offsets(compiler_state_t *cstate) +{ + struct slist *s, *s1, *s_proto; + + /* First we need to calculate the offset of the Geneve header + * itself. This is composed of the IP header previously calculated + * (include any variable link prefix) and stored in A plus the + * fixed sized headers (fixed link prefix, MAC length, and UDP + * header). */ + s = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 8; + + /* Stash this in X since we'll need it later. */ + s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s, s1); + + /* The EtherType in Geneve is 2 bytes in. Calculate this and + * store it. */ + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 2; + sappend(s, s1); + + cstate->off_linktype.reg = alloc_reg(cstate); + cstate->off_linktype.is_variable = 1; + cstate->off_linktype.constant_part = 0; + + s1 = new_stmt(cstate, BPF_ST); + s1->s.k = cstate->off_linktype.reg; + sappend(s, s1); + + /* Load the Geneve option length and mask and shift to get the + * number of bytes. It is stored in the first byte of the Geneve + * header. */ + s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B); + s1->s.k = 0; + sappend(s, s1); + + s1 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K); + s1->s.k = 0x3f; + sappend(s, s1); + + s1 = new_stmt(cstate, BPF_ALU|BPF_MUL|BPF_K); + s1->s.k = 4; + sappend(s, s1); + + /* Add in the rest of the Geneve base header. */ + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 8; + sappend(s, s1); + + /* Add the Geneve header length to its offset and store. */ + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X); + s1->s.k = 0; + sappend(s, s1); + + /* Set the encapsulated type as Ethernet. Even though we may + * not actually have Ethernet inside there are two reasons this + * is useful: + * - The linktype field is always in EtherType format regardless + * of whether it is in Geneve or an inner Ethernet frame. + * - The only link layer that we have specific support for is + * Ethernet. We will confirm that the packet actually is + * Ethernet at runtime before executing these checks. */ + PUSH_LINKHDR(cstate, DLT_EN10MB, 1, 0, alloc_reg(cstate)); + + s1 = new_stmt(cstate, BPF_ST); + s1->s.k = cstate->off_linkhdr.reg; + sappend(s, s1); + + /* Calculate whether we have an Ethernet header or just raw IP/ + * MPLS/etc. If we have Ethernet, advance the end of the MAC offset + * and linktype by 14 bytes so that the network header can be found + * seamlessly. Otherwise, keep what we've calculated already. */ + + /* We have a bare jmp so we can't use the optimizer. */ + cstate->no_optimize = 1; + + /* Load the EtherType in the Geneve header, 2 bytes in. */ + s1 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_H); + s1->s.k = 2; + sappend(s, s1); + + /* Load X with the end of the Geneve header. */ + s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); + s1->s.k = cstate->off_linkhdr.reg; + sappend(s, s1); + + /* Check if the EtherType is Transparent Ethernet Bridging. At the + * end of this check, we should have the total length in X. In + * the non-Ethernet case, it's already there. */ + s_proto = new_stmt(cstate, JMP(BPF_JEQ)); + s_proto->s.k = ETHERTYPE_TEB; + sappend(s, s_proto); + + s1 = new_stmt(cstate, BPF_MISC|BPF_TXA); + sappend(s, s1); + s_proto->s.jt = s1; + + /* Since this is Ethernet, use the EtherType of the payload + * directly as the linktype. Overwrite what we already have. */ + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 12; + sappend(s, s1); + + s1 = new_stmt(cstate, BPF_ST); + s1->s.k = cstate->off_linktype.reg; + sappend(s, s1); + + /* Advance two bytes further to get the end of the Ethernet + * header. */ + s1 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K); + s1->s.k = 2; + sappend(s, s1); + + /* Move the result to X. */ + s1 = new_stmt(cstate, BPF_MISC|BPF_TAX); + sappend(s, s1); + + /* Store the final result of our linkpl calculation. */ + cstate->off_linkpl.reg = alloc_reg(cstate); + cstate->off_linkpl.is_variable = 1; + cstate->off_linkpl.constant_part = 0; + + s1 = new_stmt(cstate, BPF_STX); + s1->s.k = cstate->off_linkpl.reg; + sappend(s, s1); + s_proto->s.jf = s1; + + cstate->off_nl = 0; + + return s; +} + +/* Check to see if this is a Geneve packet. */ +struct block * +gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni) +{ + struct block *b0, *b1; + struct slist *s; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + b0 = gen_geneve4(cstate, vni, has_vni); + b1 = gen_geneve6(cstate, vni, has_vni); + + gen_or(b0, b1); + b0 = b1; + + /* Later filters should act on the payload of the Geneve frame, + * update all of the header pointers. Attach this code so that + * it gets executed in the event that the Geneve filter matches. */ + s = gen_geneve_offsets(cstate); + + b1 = gen_true(cstate); + sappend(s, b1->stmts); + b1->stmts = s; + + gen_and(b0, b1); + + cstate->is_geneve = 1; + + return b1; +} + +/* Check that the encapsulated frame has a link layer header + * for Ethernet filters. */ +static struct block * +gen_geneve_ll_check(compiler_state_t *cstate) +{ + struct block *b0; + struct slist *s, *s1; + + /* The easiest way to see if there is a link layer present + * is to check if the link layer header and payload are not + * the same. */ + + /* Geneve always generates pure variable offsets so we can + * compare only the registers. */ + s = new_stmt(cstate, BPF_LD|BPF_MEM); + s->s.k = cstate->off_linkhdr.reg; + + s1 = new_stmt(cstate, BPF_LDX|BPF_MEM); + s1->s.k = cstate->off_linkpl.reg; + sappend(s, s1); + + b0 = new_block(cstate, BPF_JMP|BPF_JEQ|BPF_X); + b0->stmts = s; + b0->s.k = 0; + gen_not(b0); + + return b0; +} + +static struct block * +gen_atmfield_code_internal(compiler_state_t *cstate, int atmfield, + bpf_u_int32 jvalue, int jtype, int reverse) +{ + struct block *b0; + + switch (atmfield) { + + case A_VPI: + if (!cstate->is_atm) + bpf_error(cstate, "'vpi' supported only on raw ATM"); + if (cstate->off_vpi == OFFSET_NOT_SET) + abort(); + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, + 0xffffffffU, jtype, reverse, jvalue); + break; + + case A_VCI: + if (!cstate->is_atm) + bpf_error(cstate, "'vci' supported only on raw ATM"); + if (cstate->off_vci == OFFSET_NOT_SET) + abort(); + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, + 0xffffffffU, jtype, reverse, jvalue); + break; + + case A_PROTOTYPE: + if (cstate->off_proto == OFFSET_NOT_SET) + abort(); /* XXX - this isn't on FreeBSD */ + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, + 0x0fU, jtype, reverse, jvalue); + break; + + case A_MSGTYPE: + if (cstate->off_payload == OFFSET_NOT_SET) + abort(); + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B, + 0xffffffffU, jtype, reverse, jvalue); + break; + + case A_CALLREFTYPE: + if (!cstate->is_atm) + bpf_error(cstate, "'callref' supported only on raw ATM"); + if (cstate->off_proto == OFFSET_NOT_SET) + abort(); + b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, + 0xffffffffU, jtype, reverse, jvalue); + break; + + default: + abort(); + } + return b0; +} + +static struct block * +gen_atmtype_metac(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 1, BPF_JEQ, 0); + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_atmtype_sc(compiler_state_t *cstate) +{ + struct block *b0, *b1; + + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 5, BPF_JEQ, 0); + gen_and(b0, b1); + return b1; +} + +static struct block * +gen_atmtype_llc(compiler_state_t *cstate) +{ + struct block *b0; + + b0 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LLC, BPF_JEQ, 0); + cstate->linktype = cstate->prevlinktype; + return b0; +} + +struct block * +gen_atmfield_code(compiler_state_t *cstate, int atmfield, + bpf_u_int32 jvalue, int jtype, int reverse) +{ + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + return gen_atmfield_code_internal(cstate, atmfield, jvalue, jtype, + reverse); +} + +struct block * +gen_atmtype_abbrev(compiler_state_t *cstate, int type) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (type) { + + case A_METAC: + /* Get all packets in Meta signalling Circuit */ + if (!cstate->is_atm) + bpf_error(cstate, "'metac' supported only on raw ATM"); + b1 = gen_atmtype_metac(cstate); + break; + + case A_BCC: + /* Get all packets in Broadcast Circuit*/ + if (!cstate->is_atm) + bpf_error(cstate, "'bcc' supported only on raw ATM"); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 2, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4SC: + /* Get all cells in Segment OAM F4 circuit*/ + if (!cstate->is_atm) + bpf_error(cstate, "'oam4sc' supported only on raw ATM"); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4EC: + /* Get all cells in End-to-End OAM F4 Circuit*/ + if (!cstate->is_atm) + bpf_error(cstate, "'oam4ec' supported only on raw ATM"); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_SC: + /* Get all packets in connection Signalling Circuit */ + if (!cstate->is_atm) + bpf_error(cstate, "'sc' supported only on raw ATM"); + b1 = gen_atmtype_sc(cstate); + break; + + case A_ILMIC: + /* Get all packets in ILMI Circuit */ + if (!cstate->is_atm) + bpf_error(cstate, "'ilmic' supported only on raw ATM"); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 16, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_LANE: + /* Get all LANE packets */ + if (!cstate->is_atm) + bpf_error(cstate, "'lane' supported only on raw ATM"); + b1 = gen_atmfield_code_internal(cstate, A_PROTOTYPE, PT_LANE, BPF_JEQ, 0); + + /* + * Arrange that all subsequent tests assume LANE + * rather than LLC-encapsulated packets, and set + * the offsets appropriately for LANE-encapsulated + * Ethernet. + * + * We assume LANE means Ethernet, not Token Ring. + */ + PUSH_LINKHDR(cstate, DLT_EN10MB, 0, + cstate->off_payload + 2, /* Ethernet header */ + -1); + cstate->off_linktype.constant_part = cstate->off_linkhdr.constant_part + 12; + cstate->off_linkpl.constant_part = cstate->off_linkhdr.constant_part + 14; /* Ethernet */ + cstate->off_nl = 0; /* Ethernet II */ + cstate->off_nl_nosnap = 3; /* 802.3+802.2 */ + break; + + case A_LLC: + /* Get all LLC-encapsulated packets */ + if (!cstate->is_atm) + bpf_error(cstate, "'llc' supported only on raw ATM"); + b1 = gen_atmtype_llc(cstate); + break; + + default: + abort(); + } + return b1; +} + +/* + * Filtering for MTP2 messages based on li value + * FISU, length is null + * LSSU, length is 1 or 2 + * MSU, length is 3 or more + * For MTP2_HSL, sequences are on 2 bytes, and length on 9 bits + */ +struct block * +gen_mtp2type_abbrev(compiler_state_t *cstate, int type) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (type) { + + case M_FISU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'fisu' supported only on MTP2"); + /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, + 0x3fU, BPF_JEQ, 0, 0U); + break; + + case M_LSSU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'lssu' supported only on MTP2"); + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, + 0x3fU, BPF_JGT, 1, 2U); + b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, + 0x3fU, BPF_JGT, 0, 0U); + gen_and(b1, b0); + break; + + case M_MSU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'msu' supported only on MTP2"); + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li, BPF_B, + 0x3fU, BPF_JGT, 0, 2U); + break; + + case MH_FISU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'hfisu' supported only on MTP2_HSL"); + /* gen_ncmp(cstate, offrel, offset, size, mask, jtype, reverse, value) */ + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, + 0xff80U, BPF_JEQ, 0, 0U); + break; + + case MH_LSSU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'hlssu' supported only on MTP2_HSL"); + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, + 0xff80U, BPF_JGT, 1, 0x0100U); + b1 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, + 0xff80U, BPF_JGT, 0, 0U); + gen_and(b1, b0); + break; + + case MH_MSU: + if ( (cstate->linktype != DLT_MTP2) && + (cstate->linktype != DLT_ERF) && + (cstate->linktype != DLT_MTP2_WITH_PHDR) ) + bpf_error(cstate, "'hmsu' supported only on MTP2_HSL"); + b0 = gen_ncmp(cstate, OR_PACKET, cstate->off_li_hsl, BPF_H, + 0xff80U, BPF_JGT, 0, 0x0100U); + break; + + default: + abort(); + } + return b0; +} + +/* + * The jvalue_arg dance is to avoid annoying whining by compilers that + * jvalue might be clobbered by longjmp - yeah, it might, but *WHO CARES*? + * It's not *used* after setjmp returns. + */ +struct block * +gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, + bpf_u_int32 jvalue_arg, int jtype, int reverse) +{ + volatile bpf_u_int32 jvalue = jvalue_arg; + struct block *b0; + bpf_u_int32 val1 , val2 , val3; + u_int newoff_sio; + u_int newoff_opc; + u_int newoff_dpc; + u_int newoff_sls; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + newoff_sio = cstate->off_sio; + newoff_opc = cstate->off_opc; + newoff_dpc = cstate->off_dpc; + newoff_sls = cstate->off_sls; + switch (mtp3field) { + + case MH_SIO: + newoff_sio += 3; /* offset for MTP2_HSL */ + /* FALLTHROUGH */ + + case M_SIO: + if (cstate->off_sio == OFFSET_NOT_SET) + bpf_error(cstate, "'sio' supported only on SS7"); + /* sio coded on 1 byte so max value 255 */ + if(jvalue > 255) + bpf_error(cstate, "sio value %u too big; max value = 255", + jvalue); + b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU, + jtype, reverse, jvalue); + break; + + case MH_OPC: + newoff_opc += 3; + + /* FALLTHROUGH */ + case M_OPC: + if (cstate->off_opc == OFFSET_NOT_SET) + bpf_error(cstate, "'opc' supported only on SS7"); + /* opc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error(cstate, "opc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the form used to write opc in an ss7 message*/ + val1 = jvalue & 0x00003c00; + val1 = val1 >>10; + val2 = jvalue & 0x000003fc; + val2 = val2 <<6; + val3 = jvalue & 0x00000003; + val3 = val3 <<22; + jvalue = val1 + val2 + val3; + b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU, + jtype, reverse, jvalue); + break; + + case MH_DPC: + newoff_dpc += 3; + /* FALLTHROUGH */ + + case M_DPC: + if (cstate->off_dpc == OFFSET_NOT_SET) + bpf_error(cstate, "'dpc' supported only on SS7"); + /* dpc coded on 14 bits so max value 16383 */ + if (jvalue > 16383) + bpf_error(cstate, "dpc value %u too big; max value = 16383", + jvalue); + /* the following instructions are made to convert jvalue + * to the forme used to write dpc in an ss7 message*/ + val1 = jvalue & 0x000000ff; + val1 = val1 << 24; + val2 = jvalue & 0x00003f00; + val2 = val2 << 8; + jvalue = val1 + val2; + b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U, + jtype, reverse, jvalue); + break; + + case MH_SLS: + newoff_sls += 3; + /* FALLTHROUGH */ + + case M_SLS: + if (cstate->off_sls == OFFSET_NOT_SET) + bpf_error(cstate, "'sls' supported only on SS7"); + /* sls coded on 4 bits so max value 15 */ + if (jvalue > 15) + bpf_error(cstate, "sls value %u too big; max value = 15", + jvalue); + /* the following instruction is made to convert jvalue + * to the forme used to write sls in an ss7 message*/ + jvalue = jvalue << 4; + b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U, + jtype, reverse, jvalue); + break; + + default: + abort(); + } + return b0; +} + +static struct block * +gen_msg_abbrev(compiler_state_t *cstate, int type) +{ + struct block *b1; + + /* + * Q.2931 signalling protocol messages for handling virtual circuits + * establishment and teardown + */ + switch (type) { + + case A_SETUP: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, SETUP, BPF_JEQ, 0); + break; + + case A_CALLPROCEED: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CALL_PROCEED, BPF_JEQ, 0); + break; + + case A_CONNECT: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT, BPF_JEQ, 0); + break; + + case A_CONNECTACK: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, CONNECT_ACK, BPF_JEQ, 0); + break; + + case A_RELEASE: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE, BPF_JEQ, 0); + break; + + case A_RELEASE_DONE: + b1 = gen_atmfield_code_internal(cstate, A_MSGTYPE, RELEASE_DONE, BPF_JEQ, 0); + break; + + default: + abort(); + } + return b1; +} + +struct block * +gen_atmmulti_abbrev(compiler_state_t *cstate, int type) +{ + struct block *b0, *b1; + + /* + * Catch errors reported by us and routines below us, and return NULL + * on an error. + */ + if (setjmp(cstate->top_ctx)) + return (NULL); + + switch (type) { + + case A_OAM: + if (!cstate->is_atm) + bpf_error(cstate, "'oam' supported only on raw ATM"); + /* OAM F4 type */ + b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); + gen_or(b0, b1); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_OAMF4: + if (!cstate->is_atm) + bpf_error(cstate, "'oamf4' supported only on raw ATM"); + /* OAM F4 type */ + b0 = gen_atmfield_code_internal(cstate, A_VCI, 3, BPF_JEQ, 0); + b1 = gen_atmfield_code_internal(cstate, A_VCI, 4, BPF_JEQ, 0); + gen_or(b0, b1); + b0 = gen_atmfield_code_internal(cstate, A_VPI, 0, BPF_JEQ, 0); + gen_and(b0, b1); + break; + + case A_CONNECTMSG: + /* + * Get Q.2931 signalling messages for switched + * virtual connection + */ + if (!cstate->is_atm) + bpf_error(cstate, "'connectmsg' supported only on raw ATM"); + b0 = gen_msg_abbrev(cstate, A_SETUP); + b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_CONNECTACK); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_sc(cstate); + gen_and(b0, b1); + break; + + case A_METACONNECT: + if (!cstate->is_atm) + bpf_error(cstate, "'metaconnect' supported only on raw ATM"); + b0 = gen_msg_abbrev(cstate, A_SETUP); + b1 = gen_msg_abbrev(cstate, A_CALLPROCEED); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_CONNECT); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_RELEASE); + gen_or(b0, b1); + b0 = gen_msg_abbrev(cstate, A_RELEASE_DONE); + gen_or(b0, b1); + b0 = gen_atmtype_metac(cstate); + gen_and(b0, b1); + break; + + default: + abort(); + } + return b1; +} diff --git a/src/libpcap-1.10.5/gencode.h b/src/libpcap-1.10.5/gencode.h new file mode 100644 index 0000000000..b8296ab2fb --- /dev/null +++ b/src/libpcap-1.10.5/gencode.h @@ -0,0 +1,416 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef gencode_h +#define gencode_h + +#include "pcap/funcattrs.h" +/* + * pcap/bpf.h (a public header) needs u_char, u_short and u_int, which can be + * made available via either pcap-types.h (a private header) or pcap/pcap.h + * (a public header), none of which pcap/bpf.h includes. Include the private + * header to keep things simple, this way this private header should compile + * even if included early from another file. + */ +#include "pcap-types.h" +#include "pcap/bpf.h" /* bpf_u_int32 and BPF_MEMWORDS */ + +/* + * ATM support: + * + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + * North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Address qualifiers. */ + +#define Q_HOST 1 +#define Q_NET 2 +#define Q_PORT 3 +#define Q_GATEWAY 4 +#define Q_PROTO 5 +#define Q_PROTOCHAIN 6 +#define Q_PORTRANGE 7 + +/* Protocol qualifiers. */ + +#define Q_LINK 1 +#define Q_IP 2 +#define Q_ARP 3 +#define Q_RARP 4 +#define Q_SCTP 5 +#define Q_TCP 6 +#define Q_UDP 7 +#define Q_ICMP 8 +#define Q_IGMP 9 +#define Q_IGRP 10 + + +#define Q_ATALK 11 +#define Q_DECNET 12 +#define Q_LAT 13 +#define Q_SCA 14 +#define Q_MOPRC 15 +#define Q_MOPDL 16 + + +#define Q_IPV6 17 +#define Q_ICMPV6 18 +#define Q_AH 19 +#define Q_ESP 20 + +#define Q_PIM 21 +#define Q_VRRP 22 + +#define Q_AARP 23 + +#define Q_ISO 24 +#define Q_ESIS 25 +#define Q_ISIS 26 +#define Q_CLNP 27 + +#define Q_STP 28 + +#define Q_IPX 29 + +#define Q_NETBEUI 30 + +/* IS-IS Levels */ +#define Q_ISIS_L1 31 +#define Q_ISIS_L2 32 +/* PDU types */ +#define Q_ISIS_IIH 33 +#define Q_ISIS_SNP 34 +#define Q_ISIS_CSNP 35 +#define Q_ISIS_PSNP 36 +#define Q_ISIS_LSP 37 + +#define Q_RADIO 38 + +#define Q_CARP 39 + +/* Directional qualifiers. */ + +#define Q_SRC 1 +#define Q_DST 2 +#define Q_OR 3 +#define Q_AND 4 +#define Q_ADDR1 5 +#define Q_ADDR2 6 +#define Q_ADDR3 7 +#define Q_ADDR4 8 +#define Q_RA 9 +#define Q_TA 10 + +#define Q_DEFAULT 0 +#define Q_UNDEF 255 + +/* ATM types */ +#define A_METAC 22 /* Meta signalling Circuit */ +#define A_BCC 23 /* Broadcast Circuit */ +#define A_OAMF4SC 24 /* Segment OAM F4 Circuit */ +#define A_OAMF4EC 25 /* End-to-End OAM F4 Circuit */ +#define A_SC 26 /* Signalling Circuit*/ +#define A_ILMIC 27 /* ILMI Circuit */ +#define A_OAM 28 /* OAM cells : F4 only */ +#define A_OAMF4 29 /* OAM F4 cells: Segment + End-to-end */ +#define A_LANE 30 /* LANE traffic */ +#define A_LLC 31 /* LLC-encapsulated traffic */ + +/* Based on Q.2931 signalling protocol */ +#define A_SETUP 41 /* Setup message */ +#define A_CALLPROCEED 42 /* Call proceeding message */ +#define A_CONNECT 43 /* Connect message */ +#define A_CONNECTACK 44 /* Connect Ack message */ +#define A_RELEASE 45 /* Release message */ +#define A_RELEASE_DONE 46 /* Release message */ + +/* ATM field types */ +#define A_VPI 51 +#define A_VCI 52 +#define A_PROTOTYPE 53 +#define A_MSGTYPE 54 +#define A_CALLREFTYPE 55 + +#define A_CONNECTMSG 70 /* returns Q.2931 signalling messages for + establishing and destroying switched + virtual connection */ +#define A_METACONNECT 71 /* returns Q.2931 signalling messages for + establishing and destroying predefined + virtual circuits, such as broadcast + circuit, oamf4 segment circuit, oamf4 + end-to-end circuits, ILMI circuits or + connection signalling circuit. */ + +/* MTP2 types */ +#define M_FISU 22 /* FISU */ +#define M_LSSU 23 /* LSSU */ +#define M_MSU 24 /* MSU */ + +/* MTP2 HSL types */ +#define MH_FISU 25 /* FISU for HSL */ +#define MH_LSSU 26 /* LSSU */ +#define MH_MSU 27 /* MSU */ + +/* MTP3 field types */ +#define M_SIO 1 +#define M_OPC 2 +#define M_DPC 3 +#define M_SLS 4 + +/* MTP3 field types in case of MTP2 HSL */ +#define MH_SIO 5 +#define MH_OPC 6 +#define MH_DPC 7 +#define MH_SLS 8 + + +struct slist; + +/* + * A single statement, corresponding to an instruction in a block. + */ +struct stmt { + int code; /* opcode */ + struct slist *jt; /* only for relative jump in block */ + struct slist *jf; /* only for relative jump in block */ + bpf_u_int32 k; /* k field */ +}; + +struct slist { + struct stmt s; + struct slist *next; +}; + +/* + * A bit vector to represent definition sets. We assume TOT_REGISTERS + * is smaller than 8*sizeof(atomset). + */ +typedef bpf_u_int32 atomset; +#define ATOMMASK(n) (1 << (n)) +#define ATOMELEM(d, n) (d & ATOMMASK(n)) + +/* + * An unbounded set. + */ +typedef bpf_u_int32 *uset; + +/* + * Total number of atomic entities, including accumulator (A) and index (X). + * We treat all these guys similarly during flow analysis. + */ +#define N_ATOMS (BPF_MEMWORDS+2) + +/* + * Control flow graph of a program. + * This corresponds to an edge in the CFG. + * It's a directed graph, so an edge has a predecessor and a successor. + */ +struct edge { + u_int id; + int code; /* opcode for branch corresponding to this edge */ + uset edom; + struct block *succ; /* successor vertex */ + struct block *pred; /* predecessor vertex */ + struct edge *next; /* link list of incoming edges for a node */ +}; + +/* + * A block is a vertex in the CFG. + * It has a list of statements, with the final statement being a + * branch to successor blocks. + */ +struct block { + u_int id; + struct slist *stmts; /* side effect stmts */ + struct stmt s; /* branch stmt */ + int mark; + u_int longjt; /* jt branch requires long jump */ + u_int longjf; /* jf branch requires long jump */ + int level; + int offset; + int sense; + struct edge et; /* edge corresponding to the jt branch */ + struct edge ef; /* edge corresponding to the jf branch */ + struct block *head; + struct block *link; /* link field used by optimizer */ + uset dom; + uset closure; + struct edge *in_edges; /* first edge in the set (linked list) of edges with this as a successor */ + atomset def, kill; + atomset in_use; + atomset out_use; + int oval; /* value ID for value tested in branch stmt */ + bpf_u_int32 val[N_ATOMS]; +}; + +/* + * A value of 0 for val[i] means the value is unknown. + */ +#define VAL_UNKNOWN 0 + +struct arth { + struct block *b; /* protocol checks */ + struct slist *s; /* stmt list */ + int regno; /* virtual register number of result */ +}; + +struct qual { + unsigned char addr; + unsigned char proto; + unsigned char dir; + unsigned char pad; +}; + +struct _compiler_state; + +typedef struct _compiler_state compiler_state_t; + +struct arth *gen_loadi(compiler_state_t *, bpf_u_int32); +struct arth *gen_load(compiler_state_t *, int, struct arth *, bpf_u_int32); +struct arth *gen_loadlen(compiler_state_t *); +struct arth *gen_neg(compiler_state_t *, struct arth *); +struct arth *gen_arth(compiler_state_t *, int, struct arth *, struct arth *); + +void gen_and(struct block *, struct block *); +void gen_or(struct block *, struct block *); +void gen_not(struct block *); + +struct block *gen_scode(compiler_state_t *, const char *, struct qual); +struct block *gen_ecode(compiler_state_t *, const char *, struct qual); +struct block *gen_acode(compiler_state_t *, const char *, struct qual); +struct block *gen_mcode(compiler_state_t *, const char *, const char *, + bpf_u_int32, struct qual); +#ifdef INET6 +struct block *gen_mcode6(compiler_state_t *, const char *, bpf_u_int32, + struct qual); +#endif +struct block *gen_ncode(compiler_state_t *, const char *, bpf_u_int32, + struct qual); +struct block *gen_proto_abbrev(compiler_state_t *, int); +struct block *gen_relation(compiler_state_t *, int, struct arth *, + struct arth *, int); +struct block *gen_less(compiler_state_t *, int); +struct block *gen_greater(compiler_state_t *, int); +struct block *gen_byteop(compiler_state_t *, int, int, bpf_u_int32); +struct block *gen_broadcast(compiler_state_t *, int); +struct block *gen_multicast(compiler_state_t *, int); +struct block *gen_ifindex(compiler_state_t *, int); +struct block *gen_inbound(compiler_state_t *, int); + +struct block *gen_llc(compiler_state_t *); +struct block *gen_llc_i(compiler_state_t *); +struct block *gen_llc_s(compiler_state_t *); +struct block *gen_llc_u(compiler_state_t *); +struct block *gen_llc_s_subtype(compiler_state_t *, bpf_u_int32); +struct block *gen_llc_u_subtype(compiler_state_t *, bpf_u_int32); + +struct block *gen_vlan(compiler_state_t *, bpf_u_int32, int); +struct block *gen_mpls(compiler_state_t *, bpf_u_int32, int); + +struct block *gen_pppoed(compiler_state_t *); +struct block *gen_pppoes(compiler_state_t *, bpf_u_int32, int); + +struct block *gen_geneve(compiler_state_t *, bpf_u_int32, int); + +struct block *gen_atmfield_code(compiler_state_t *, int, bpf_u_int32, + int, int); +struct block *gen_atmtype_abbrev(compiler_state_t *, int); +struct block *gen_atmmulti_abbrev(compiler_state_t *, int); + +struct block *gen_mtp2type_abbrev(compiler_state_t *, int); +struct block *gen_mtp3field_code(compiler_state_t *, int, bpf_u_int32, + int, int); + +struct block *gen_pf_ifname(compiler_state_t *, const char *); +struct block *gen_pf_rnr(compiler_state_t *, int); +struct block *gen_pf_srnr(compiler_state_t *, int); +struct block *gen_pf_ruleset(compiler_state_t *, char *); +struct block *gen_pf_reason(compiler_state_t *, int); +struct block *gen_pf_action(compiler_state_t *, int); + +struct block *gen_p80211_type(compiler_state_t *, bpf_u_int32, bpf_u_int32); +struct block *gen_p80211_fcdir(compiler_state_t *, bpf_u_int32); + +/* + * Representation of a program as a tree of blocks, plus current mark. + * A block is marked if only if its mark equals the current mark. + * Rather than traverse the code array, marking each item, 'cur_mark' + * is incremented. This automatically makes each element unmarked. + */ +#define isMarked(icp, p) ((p)->mark == (icp)->cur_mark) +#define unMarkAll(icp) (icp)->cur_mark += 1 +#define Mark(icp, p) ((p)->mark = (icp)->cur_mark) + +struct icode { + struct block *root; + int cur_mark; +}; + +int bpf_optimize(struct icode *, char *); +void bpf_set_error(compiler_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + +int finish_parse(compiler_state_t *, struct block *); +char *sdup(compiler_state_t *, const char *); + +struct bpf_insn *icode_to_fcode(struct icode *, struct block *, u_int *, + char *); +void sappend(struct slist *, struct slist *); + +/* + * Older versions of Bison don't put this declaration in + * grammar.h. + */ +int pcap_parse(void *, compiler_state_t *); + +/* XXX */ +#define JT(b) ((b)->et.succ) +#define JF(b) ((b)->ef.succ) + +#endif /* gencode_h */ diff --git a/src/libpcap-1.10.5/grammar.y.in b/src/libpcap-1.10.5/grammar.y.in new file mode 100644 index 0000000000..87706fa89c --- /dev/null +++ b/src/libpcap-1.10.5/grammar.y.in @@ -0,0 +1,949 @@ +/* + * We want a reentrant parser. + */ +@REENTRANT_PARSER@ + +/* + * We also want a reentrant scanner, so we have to pass the + * handle for the reentrant scanner to the parser, and the + * parser has to pass it to the lexical analyzer. + * + * We use void * rather than yyscan_t because, at least with some + * versions of Flex and Bison, if you use yyscan_t in %parse-param and + * %lex-param, you have to include scanner.h before grammar.h to get + * yyscan_t declared, and you have to include grammar.h before scanner.h + * to get YYSTYPE declared. Using void * breaks the cycle; the Flex + * documentation says yyscan_t is just a void *. + */ +%parse-param {void *yyscanner} +%lex-param {void *yyscanner} + +/* + * According to bison documentation, shift/reduce conflicts are not an issue + * in most parsers as long as the number does not evolve over time: + * https://www.gnu.org/software/bison/manual/html_node/Expect-Decl.html + * So, following the advice use %expect to check the amount of shift/reduce + * warnings. + * + * This doesn't appear to work in Berkeley YACC - 1.9 20170709; it still + * warns of 38 shift/reduce conflicts. + * + * The Berkeley YACC documentation: + * + * https://invisible-island.net/byacc/manpage/yacc.html + * + * claims that "Bison's support for "%expect" is broken in more than one + * release.", but doesn't give details. Hopefully, that only means that + * you get warnings even if you have the expected number of shift/reduce + * conflicts, not that anything else fails. + */ +%expect 38 + +/* + * And we need to pass the compiler state to the scanner. + */ +%parse-param { compiler_state_t *cstate } + +%{ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include + +/* + * grammar.h requires gencode.h and sometimes breaks in a polluted namespace + * (see ftmacros.h), so include it early. + */ +#include "gencode.h" +#include "grammar.h" + +#include + +#ifndef _WIN32 +#include +#include + +#if __STDC__ +struct mbuf; +struct rtentry; +#endif + +#include +#include +#endif /* _WIN32 */ + +#include + +#include "diag-control.h" + +#include "pcap-int.h" + +#include "scanner.h" + +#include "llc.h" +#include "ieee80211.h" +#include "pflog.h" +#include + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Work around some bugs in Berkeley YACC prior to the 2017-07-09 + * release. + * + * The 2005-05-05 release was the first one to define YYPATCH, so + * we treat any release that either 1) doesn't define YYPATCH or + * 2) defines it to a value < 20170709 as being buggy. + */ +#if defined(YYBYACC) && (!defined(YYPATCH) || YYPATCH < 20170709) +/* + * Both Berkeley YACC and Bison define yydebug (under whatever name + * it has) as a global, but Bison does so only if YYDEBUG is defined. + * Berkeley YACC, prior to the 2017-07-09 release, defines it even if + * YYDEBUG isn't defined; declare it here to suppress a warning. The + * 2017-07-09 release fixes that. + */ +#if !defined(YYDEBUG) +extern int yydebug; +#endif + +/* + * In Berkeley YACC, prior to the 2017-07-09 release, yynerrs (under + * whatever name it has) is global, even if it's building a reentrant + * parser. In Bison, and in the Berkeley YACC 2017-07-09 release and + * later, it's local in reentrant parsers. + * + * Declare it to squelch a warning. + */ +extern int yynerrs; +#endif + +#define QSET(q, p, d, a) (q).proto = (unsigned char)(p),\ + (q).dir = (unsigned char)(d),\ + (q).addr = (unsigned char)(a) + +struct tok { + int v; /* value */ + const char *s; /* string */ +}; + +static const struct tok ieee80211_types[] = { + { IEEE80211_FC0_TYPE_DATA, "data" }, + { IEEE80211_FC0_TYPE_MGT, "mgt" }, + { IEEE80211_FC0_TYPE_MGT, "management" }, + { IEEE80211_FC0_TYPE_CTL, "ctl" }, + { IEEE80211_FC0_TYPE_CTL, "control" }, + { 0, NULL } +}; +static const struct tok ieee80211_mgt_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assocreq" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_REQ, "assoc-req" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assocresp" }, + { IEEE80211_FC0_SUBTYPE_ASSOC_RESP, "assoc-resp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassocreq" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_REQ, "reassoc-req" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassocresp" }, + { IEEE80211_FC0_SUBTYPE_REASSOC_RESP, "reassoc-resp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probereq" }, + { IEEE80211_FC0_SUBTYPE_PROBE_REQ, "probe-req" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "proberesp" }, + { IEEE80211_FC0_SUBTYPE_PROBE_RESP, "probe-resp" }, + { IEEE80211_FC0_SUBTYPE_BEACON, "beacon" }, + { IEEE80211_FC0_SUBTYPE_ATIM, "atim" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassoc" }, + { IEEE80211_FC0_SUBTYPE_DISASSOC, "disassociation" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "auth" }, + { IEEE80211_FC0_SUBTYPE_AUTH, "authentication" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauth" }, + { IEEE80211_FC0_SUBTYPE_DEAUTH, "deauthentication" }, + { 0, NULL } +}; +static const struct tok ieee80211_ctl_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_PS_POLL, "ps-poll" }, + { IEEE80211_FC0_SUBTYPE_RTS, "rts" }, + { IEEE80211_FC0_SUBTYPE_CTS, "cts" }, + { IEEE80211_FC0_SUBTYPE_ACK, "ack" }, + { IEEE80211_FC0_SUBTYPE_CF_END, "cf-end" }, + { IEEE80211_FC0_SUBTYPE_CF_END_ACK, "cf-end-ack" }, + { 0, NULL } +}; +static const struct tok ieee80211_data_subtypes[] = { + { IEEE80211_FC0_SUBTYPE_DATA, "data" }, + { IEEE80211_FC0_SUBTYPE_CF_ACK, "data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_CF_POLL, "data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_CF_ACPL, "data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA, "null" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK, "cf-ack" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "cf-poll" }, + { IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_DATA, "qos-data" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACK, "qos-data-cf-ack" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_POLL, "qos-data-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_CF_ACPL, "qos-data-cf-ack-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA, "qos" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL, "qos-cf-poll" }, + { IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL, "qos-cf-ack-poll" }, + { 0, NULL } +}; +static const struct tok llc_s_subtypes[] = { + { LLC_RR, "rr" }, + { LLC_RNR, "rnr" }, + { LLC_REJ, "rej" }, + { 0, NULL } +}; +static const struct tok llc_u_subtypes[] = { + { LLC_UI, "ui" }, + { LLC_UA, "ua" }, + { LLC_DISC, "disc" }, + { LLC_DM, "dm" }, + { LLC_SABME, "sabme" }, + { LLC_TEST, "test" }, + { LLC_XID, "xid" }, + { LLC_FRMR, "frmr" }, + { 0, NULL } +}; +struct type2tok { + int type; + const struct tok *tok; +}; +static const struct type2tok ieee80211_type_subtypes[] = { + { IEEE80211_FC0_TYPE_MGT, ieee80211_mgt_subtypes }, + { IEEE80211_FC0_TYPE_CTL, ieee80211_ctl_subtypes }, + { IEEE80211_FC0_TYPE_DATA, ieee80211_data_subtypes }, + { 0, NULL } +}; + +static int +str2tok(const char *str, const struct tok *toks) +{ + int i; + + for (i = 0; toks[i].s != NULL; i++) { + if (pcapint_strcasecmp(toks[i].s, str) == 0) { + /* + * Just in case somebody is using this to + * generate values of -1/0xFFFFFFFF. + * That won't work, as it's indistinguishable + * from an error. + */ + if (toks[i].v == -1) + abort(); + return (toks[i].v); + } + } + return (-1); +} + +static const struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF }; + +static void +yyerror(void *yyscanner _U_, compiler_state_t *cstate, const char *msg) +{ + bpf_set_error(cstate, "can't parse filter expression: %s", msg); +} + +static const struct tok pflog_reasons[] = { + { PFRES_MATCH, "match" }, + { PFRES_BADOFF, "bad-offset" }, + { PFRES_FRAG, "fragment" }, + { PFRES_SHORT, "short" }, + { PFRES_NORM, "normalize" }, + { PFRES_MEMORY, "memory" }, + { PFRES_TS, "bad-timestamp" }, + { PFRES_CONGEST, "congestion" }, + { PFRES_IPOPTIONS, "ip-option" }, + { PFRES_PROTCKSUM, "proto-cksum" }, + { PFRES_BADSTATE, "state-mismatch" }, + { PFRES_STATEINS, "state-insert" }, + { PFRES_MAXSTATES, "state-limit" }, + { PFRES_SRCLIMIT, "src-limit" }, + { PFRES_SYNPROXY, "synproxy" }, +#if defined(__FreeBSD__) + { PFRES_MAPFAILED, "map-failed" }, +#elif defined(__NetBSD__) + { PFRES_STATELOCKED, "state-locked" }, +#elif defined(__OpenBSD__) + { PFRES_TRANSLATE, "translate" }, + { PFRES_NOROUTE, "no-route" }, +#elif defined(__APPLE__) + { PFRES_DUMMYNET, "dummynet" }, +#endif + { 0, NULL } +}; + +static int +pfreason_to_num(compiler_state_t *cstate, const char *reason) +{ + int i; + + i = str2tok(reason, pflog_reasons); + if (i == -1) + bpf_set_error(cstate, "unknown PF reason \"%s\"", reason); + return (i); +} + +static const struct tok pflog_actions[] = { + { PF_PASS, "pass" }, + { PF_PASS, "accept" }, /* alias for "pass" */ + { PF_DROP, "drop" }, + { PF_DROP, "block" }, /* alias for "drop" */ + { PF_SCRUB, "scrub" }, + { PF_NOSCRUB, "noscrub" }, + { PF_NAT, "nat" }, + { PF_NONAT, "nonat" }, + { PF_BINAT, "binat" }, + { PF_NOBINAT, "nobinat" }, + { PF_RDR, "rdr" }, + { PF_NORDR, "nordr" }, + { PF_SYNPROXY_DROP, "synproxy-drop" }, +#if defined(__FreeBSD__) + { PF_DEFER, "defer" }, +#elif defined(__OpenBSD__) + { PF_DEFER, "defer" }, + { PF_MATCH, "match" }, + { PF_DIVERT, "divert" }, + { PF_RT, "rt" }, + { PF_AFRT, "afrt" }, +#elif defined(__APPLE__) + { PF_DUMMYNET, "dummynet" }, + { PF_NODUMMYNET, "nodummynet" }, + { PF_NAT64, "nat64" }, + { PF_NONAT64, "nonat64" }, +#endif + { 0, NULL }, +}; + +static int +pfaction_to_num(compiler_state_t *cstate, const char *action) +{ + int i; + + i = str2tok(action, pflog_actions); + if (i == -1) + bpf_set_error(cstate, "unknown PF action \"%s\"", action); + return (i); +} + +/* + * For calls that might return an "an error occurred" value. + */ +#define CHECK_INT_VAL(val) if (val == -1) YYABORT +#define CHECK_PTR_VAL(val) if (val == NULL) YYABORT + +DIAG_OFF_BISON_BYACC +%} + +%union { + int i; + bpf_u_int32 h; + char *s; + struct stmt *stmt; + struct arth *a; + struct { + struct qual q; + int atmfieldtype; + int mtp3fieldtype; + struct block *b; + } blk; + struct block *rblk; +} + +%type expr id nid pid term rterm qid +%type head +%type pqual dqual aqual ndaqual +%type arth narth +%type byteop pname relop irelop +%type pnum +%type and or paren not null prog +%type other pfvar p80211 pllc +%type atmtype atmmultitype +%type atmfield +%type atmfieldvalue atmvalue atmlistvalue +%type mtp2type +%type mtp3field +%type mtp3fieldvalue mtp3value mtp3listvalue + + +%token DST SRC HOST GATEWAY +%token NET NETMASK PORT PORTRANGE LESS GREATER PROTO PROTOCHAIN CBYTE +%token ARP RARP IP SCTP TCP UDP ICMP IGMP IGRP PIM VRRP CARP +%token ATALK AARP DECNET LAT SCA MOPRC MOPDL +%token TK_BROADCAST TK_MULTICAST +%token NUM INBOUND OUTBOUND +%token IFINDEX +%token PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION +%token TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4 RA TA +%token LINK +%token GEQ LEQ NEQ +%token ID EID HID HID6 AID +%token LSH RSH +%token LEN +%token IPV6 ICMPV6 AH ESP +%token VLAN MPLS +%token PPPOED PPPOES GENEVE +%token ISO ESIS CLNP ISIS L1 L2 IIH LSP SNP CSNP PSNP +%token STP +%token IPX +%token NETBEUI +%token LANE LLC METAC BCC SC ILMIC OAMF4EC OAMF4SC +%token OAM OAMF4 CONNECTMSG METACONNECT +%token VPI VCI +%token RADIO +%token FISU LSSU MSU HFISU HLSSU HMSU +%token SIO OPC DPC SLS HSIO HOPC HDPC HSLS +%token LEX_ERROR + +%type ID EID AID +%type HID HID6 +%type NUM +%type action reason type subtype type_subtype dir + +%left OR AND +%nonassoc '!' +%left '|' +%left '&' +%left LSH RSH +%left '+' '-' +%left '*' '/' +%nonassoc UMINUS +%% +prog: null expr +{ + /* + * I'm not sure we have a reason to use yynerrs, but it's + * declared, and incremented, whether we need it or not, + * which means that Clang 15 will give a "used but not + * set" warning. This should suppress the warning for + * yynerrs without suppressing it for other variables. + */ + (void) yynerrs; + CHECK_INT_VAL(finish_parse(cstate, $2.b)); +} + | null + ; +null: /* null */ { $$.q = qerr; } + ; +expr: term + | expr and term { gen_and($1.b, $3.b); $$ = $3; } + | expr and id { gen_and($1.b, $3.b); $$ = $3; } + | expr or term { gen_or($1.b, $3.b); $$ = $3; } + | expr or id { gen_or($1.b, $3.b); $$ = $3; } + ; +and: AND { $$ = $0; } + ; +or: OR { $$ = $0; } + ; +id: nid + | pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1, + $$.q = $0.q))); } + | paren pid ')' { $$ = $2; } + ; +nid: ID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_scode(cstate, $1, $$.q = $0.q))); } + | HID '/' NUM { + CHECK_PTR_VAL($1); + /* Check whether HID/NUM is being used when appropriate */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to IP address and prefix length"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to IP address and prefix length"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to IP address and prefix length"); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to IP address and prefix length"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, NULL, $3, $$.q))); + } + | HID NETMASK HID { + CHECK_PTR_VAL($1); + /* Check whether HID mask HID is being used when appropriate */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to IP address and netmask"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to IP address and netmask"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to IP address and netmask"); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to IP address and netmask"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_mcode(cstate, $1, $3, 0, $$.q))); + } + | HID { + CHECK_PTR_VAL($1); + /* Check whether HID is being used when appropriate */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to IP address"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to IP address"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to IP address"); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to IP address"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_ncode(cstate, $1, 0, $$.q))); + } + | HID6 '/' NUM { + CHECK_PTR_VAL($1); +#ifdef INET6 + /* Check whether HID6/NUM is being used when appropriate */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to IP address and prefix length"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to IP address and prefix length"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to IP address and prefix length "); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to IP address and prefix length"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, $3, $$.q))); +#else + bpf_set_error(cstate, "IPv6 addresses not supported " + "in this configuration"); + YYABORT; +#endif /*INET6*/ + } + | HID6 { + CHECK_PTR_VAL($1); +#ifdef INET6 + /* Check whether HID6 is being used when appropriate */ + $$.q = $0.q; + if ($$.q.addr == Q_PORT) { + bpf_set_error(cstate, "'port' modifier applied to IP address"); + YYABORT; + } else if ($$.q.addr == Q_PORTRANGE) { + bpf_set_error(cstate, "'portrange' modifier applied to IP address"); + YYABORT; + } else if ($$.q.addr == Q_PROTO) { + bpf_set_error(cstate, "'proto' modifier applied to 'ip6addr/prefixlen"); + YYABORT; + } else if ($$.q.addr == Q_PROTOCHAIN) { + bpf_set_error(cstate, "'protochain' modifier applied to IP address"); + YYABORT; + } + CHECK_PTR_VAL(($$.b = gen_mcode6(cstate, $1, 128, $$.q))); +#else + bpf_set_error(cstate, "IPv6 addresses not supported " + "in this configuration"); + YYABORT; +#endif /*INET6*/ + } + | EID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_ecode(cstate, $1, $$.q = $0.q))); } + | AID { CHECK_PTR_VAL($1); CHECK_PTR_VAL(($$.b = gen_acode(cstate, $1, $$.q = $0.q))); } + | not id { gen_not($2.b); $$ = $2; } + ; +not: '!' { $$ = $0; } + ; +paren: '(' { $$ = $0; } + ; +pid: nid + | qid and id { gen_and($1.b, $3.b); $$ = $3; } + | qid or id { gen_or($1.b, $3.b); $$ = $3; } + ; +qid: pnum { CHECK_PTR_VAL(($$.b = gen_ncode(cstate, NULL, $1, + $$.q = $0.q))); } + | pid + ; +term: rterm + | not term { gen_not($2.b); $$ = $2; } + ; +head: pqual dqual aqual { QSET($$.q, $1, $2, $3); } + | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); } + | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); } + | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); } + | pqual PROTOCHAIN { +#ifdef NO_PROTOCHAIN + bpf_set_error(cstate, "protochain not supported"); + YYABORT; +#else + QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); +#endif + } + | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); } + ; +rterm: head id { $$ = $2; } + | paren expr ')' { $$.b = $2.b; $$.q = $1.q; } + | pname { CHECK_PTR_VAL(($$.b = gen_proto_abbrev(cstate, $1))); $$.q = qerr; } + | arth relop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 0))); + $$.q = qerr; } + | arth irelop arth { CHECK_PTR_VAL(($$.b = gen_relation(cstate, $2, $1, $3, 1))); + $$.q = qerr; } + | other { $$.b = $1; $$.q = qerr; } + | atmtype { CHECK_PTR_VAL(($$.b = gen_atmtype_abbrev(cstate, $1))); $$.q = qerr; } + | atmmultitype { CHECK_PTR_VAL(($$.b = gen_atmmulti_abbrev(cstate, $1))); $$.q = qerr; } + | atmfield atmvalue { $$.b = $2.b; $$.q = qerr; } + | mtp2type { CHECK_PTR_VAL(($$.b = gen_mtp2type_abbrev(cstate, $1))); $$.q = qerr; } + | mtp3field mtp3value { $$.b = $2.b; $$.q = qerr; } + ; +/* protocol level qualifiers */ +pqual: pname + | { $$ = Q_DEFAULT; } + ; +/* 'direction' qualifiers */ +dqual: SRC { $$ = Q_SRC; } + | DST { $$ = Q_DST; } + | SRC OR DST { $$ = Q_OR; } + | DST OR SRC { $$ = Q_OR; } + | SRC AND DST { $$ = Q_AND; } + | DST AND SRC { $$ = Q_AND; } + | ADDR1 { $$ = Q_ADDR1; } + | ADDR2 { $$ = Q_ADDR2; } + | ADDR3 { $$ = Q_ADDR3; } + | ADDR4 { $$ = Q_ADDR4; } + | RA { $$ = Q_RA; } + | TA { $$ = Q_TA; } + ; +/* address type qualifiers */ +aqual: HOST { $$ = Q_HOST; } + | NET { $$ = Q_NET; } + | PORT { $$ = Q_PORT; } + | PORTRANGE { $$ = Q_PORTRANGE; } + ; +/* non-directional address type qualifiers */ +ndaqual: GATEWAY { $$ = Q_GATEWAY; } + ; +pname: LINK { $$ = Q_LINK; } + | IP { $$ = Q_IP; } + | ARP { $$ = Q_ARP; } + | RARP { $$ = Q_RARP; } + | SCTP { $$ = Q_SCTP; } + | TCP { $$ = Q_TCP; } + | UDP { $$ = Q_UDP; } + | ICMP { $$ = Q_ICMP; } + | IGMP { $$ = Q_IGMP; } + | IGRP { $$ = Q_IGRP; } + | PIM { $$ = Q_PIM; } + | VRRP { $$ = Q_VRRP; } + | CARP { $$ = Q_CARP; } + | ATALK { $$ = Q_ATALK; } + | AARP { $$ = Q_AARP; } + | DECNET { $$ = Q_DECNET; } + | LAT { $$ = Q_LAT; } + | SCA { $$ = Q_SCA; } + | MOPDL { $$ = Q_MOPDL; } + | MOPRC { $$ = Q_MOPRC; } + | IPV6 { $$ = Q_IPV6; } + | ICMPV6 { $$ = Q_ICMPV6; } + | AH { $$ = Q_AH; } + | ESP { $$ = Q_ESP; } + | ISO { $$ = Q_ISO; } + | ESIS { $$ = Q_ESIS; } + | ISIS { $$ = Q_ISIS; } + | L1 { $$ = Q_ISIS_L1; } + | L2 { $$ = Q_ISIS_L2; } + | IIH { $$ = Q_ISIS_IIH; } + | LSP { $$ = Q_ISIS_LSP; } + | SNP { $$ = Q_ISIS_SNP; } + | PSNP { $$ = Q_ISIS_PSNP; } + | CSNP { $$ = Q_ISIS_CSNP; } + | CLNP { $$ = Q_CLNP; } + | STP { $$ = Q_STP; } + | IPX { $$ = Q_IPX; } + | NETBEUI { $$ = Q_NETBEUI; } + | RADIO { $$ = Q_RADIO; } + ; +other: pqual TK_BROADCAST { CHECK_PTR_VAL(($$ = gen_broadcast(cstate, $1))); } + | pqual TK_MULTICAST { CHECK_PTR_VAL(($$ = gen_multicast(cstate, $1))); } + | LESS NUM { CHECK_PTR_VAL(($$ = gen_less(cstate, $2))); } + | GREATER NUM { CHECK_PTR_VAL(($$ = gen_greater(cstate, $2))); } + | CBYTE NUM byteop NUM { CHECK_PTR_VAL(($$ = gen_byteop(cstate, $3, $2, $4))); } + | INBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 0))); } + | OUTBOUND { CHECK_PTR_VAL(($$ = gen_inbound(cstate, 1))); } + | IFINDEX NUM { CHECK_PTR_VAL(($$ = gen_ifindex(cstate, $2))); } + | VLAN pnum { CHECK_PTR_VAL(($$ = gen_vlan(cstate, $2, 1))); } + | VLAN { CHECK_PTR_VAL(($$ = gen_vlan(cstate, 0, 0))); } + | MPLS pnum { CHECK_PTR_VAL(($$ = gen_mpls(cstate, $2, 1))); } + | MPLS { CHECK_PTR_VAL(($$ = gen_mpls(cstate, 0, 0))); } + | PPPOED { CHECK_PTR_VAL(($$ = gen_pppoed(cstate))); } + | PPPOES pnum { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, $2, 1))); } + | PPPOES { CHECK_PTR_VAL(($$ = gen_pppoes(cstate, 0, 0))); } + | GENEVE pnum { CHECK_PTR_VAL(($$ = gen_geneve(cstate, $2, 1))); } + | GENEVE { CHECK_PTR_VAL(($$ = gen_geneve(cstate, 0, 0))); } + | pfvar { $$ = $1; } + | pqual p80211 { $$ = $2; } + | pllc { $$ = $1; } + ; + +pfvar: PF_IFNAME ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ifname(cstate, $2))); } + | PF_RSET ID { CHECK_PTR_VAL($2); CHECK_PTR_VAL(($$ = gen_pf_ruleset(cstate, $2))); } + | PF_RNR NUM { CHECK_PTR_VAL(($$ = gen_pf_rnr(cstate, $2))); } + | PF_SRNR NUM { CHECK_PTR_VAL(($$ = gen_pf_srnr(cstate, $2))); } + | PF_REASON reason { CHECK_PTR_VAL(($$ = gen_pf_reason(cstate, $2))); } + | PF_ACTION action { CHECK_PTR_VAL(($$ = gen_pf_action(cstate, $2))); } + ; + +p80211: TYPE type SUBTYPE subtype + { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2 | $4, + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK))); + } + | TYPE type { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2, + IEEE80211_FC0_TYPE_MASK))); + } + | SUBTYPE type_subtype { CHECK_PTR_VAL(($$ = gen_p80211_type(cstate, $2, + IEEE80211_FC0_TYPE_MASK | + IEEE80211_FC0_SUBTYPE_MASK))); + } + | DIR dir { CHECK_PTR_VAL(($$ = gen_p80211_fcdir(cstate, $2))); } + ; + +type: NUM { if (($1 & (~IEEE80211_FC0_TYPE_MASK)) != 0) { + bpf_set_error(cstate, "invalid 802.11 type value 0x%02x", $1); + YYABORT; + } + $$ = (int)$1; + } + | ID { CHECK_PTR_VAL($1); + $$ = str2tok($1, ieee80211_types); + if ($$ == -1) { + bpf_set_error(cstate, "unknown 802.11 type name \"%s\"", $1); + YYABORT; + } + } + ; + +subtype: NUM { if (($1 & (~IEEE80211_FC0_SUBTYPE_MASK)) != 0) { + bpf_set_error(cstate, "invalid 802.11 subtype value 0x%02x", $1); + YYABORT; + } + $$ = (int)$1; + } + | ID { const struct tok *types = NULL; + int i; + CHECK_PTR_VAL($1); + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_set_error(cstate, "unknown 802.11 type"); + YYABORT; + } + if ($-1 == ieee80211_type_subtypes[i].type) { + types = ieee80211_type_subtypes[i].tok; + break; + } + } + + $$ = str2tok($1, types); + if ($$ == -1) { + bpf_set_error(cstate, "unknown 802.11 subtype name \"%s\"", $1); + YYABORT; + } + } + ; + +type_subtype: ID { int i; + CHECK_PTR_VAL($1); + for (i = 0;; i++) { + if (ieee80211_type_subtypes[i].tok == NULL) { + /* Ran out of types */ + bpf_set_error(cstate, "unknown 802.11 type name"); + YYABORT; + } + $$ = str2tok($1, ieee80211_type_subtypes[i].tok); + if ($$ != -1) { + $$ |= ieee80211_type_subtypes[i].type; + break; + } + } + } + ; + +pllc: LLC { CHECK_PTR_VAL(($$ = gen_llc(cstate))); } + | LLC ID { CHECK_PTR_VAL($2); + if (pcapint_strcasecmp($2, "i") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_i(cstate))); + } else if (pcapint_strcasecmp($2, "s") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_s(cstate))); + } else if (pcapint_strcasecmp($2, "u") == 0) { + CHECK_PTR_VAL(($$ = gen_llc_u(cstate))); + } else { + int subtype; + + subtype = str2tok($2, llc_s_subtypes); + if (subtype != -1) { + CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, subtype))); + } else { + subtype = str2tok($2, llc_u_subtypes); + if (subtype == -1) { + bpf_set_error(cstate, "unknown LLC type name \"%s\"", $2); + YYABORT; + } + CHECK_PTR_VAL(($$ = gen_llc_u_subtype(cstate, subtype))); + } + } + } + /* sigh, "rnr" is already a keyword for PF */ + | LLC PF_RNR { CHECK_PTR_VAL(($$ = gen_llc_s_subtype(cstate, LLC_RNR))); } + ; + +dir: NUM { $$ = (int)$1; } + | ID { CHECK_PTR_VAL($1); + if (pcapint_strcasecmp($1, "nods") == 0) + $$ = IEEE80211_FC1_DIR_NODS; + else if (pcapint_strcasecmp($1, "tods") == 0) + $$ = IEEE80211_FC1_DIR_TODS; + else if (pcapint_strcasecmp($1, "fromds") == 0) + $$ = IEEE80211_FC1_DIR_FROMDS; + else if (pcapint_strcasecmp($1, "dstods") == 0) + $$ = IEEE80211_FC1_DIR_DSTODS; + else { + bpf_set_error(cstate, "unknown 802.11 direction"); + YYABORT; + } + } + ; + +reason: NUM { $$ = $1; } + | ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfreason_to_num(cstate, $1))); } + ; + +action: ID { CHECK_PTR_VAL($1); CHECK_INT_VAL(($$ = pfaction_to_num(cstate, $1))); } + ; + +relop: '>' { $$ = BPF_JGT; } + | GEQ { $$ = BPF_JGE; } + | '=' { $$ = BPF_JEQ; } + ; +irelop: LEQ { $$ = BPF_JGT; } + | '<' { $$ = BPF_JGE; } + | NEQ { $$ = BPF_JEQ; } + ; +arth: pnum { CHECK_PTR_VAL(($$ = gen_loadi(cstate, $1))); } + | narth + ; +narth: pname '[' arth ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, 1))); } + | pname '[' arth ':' NUM ']' { CHECK_PTR_VAL(($$ = gen_load(cstate, $1, $3, $5))); } + | arth '+' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_ADD, $1, $3))); } + | arth '-' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_SUB, $1, $3))); } + | arth '*' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MUL, $1, $3))); } + | arth '/' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_DIV, $1, $3))); } + | arth '%' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_MOD, $1, $3))); } + | arth '&' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_AND, $1, $3))); } + | arth '|' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_OR, $1, $3))); } + | arth '^' arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_XOR, $1, $3))); } + | arth LSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_LSH, $1, $3))); } + | arth RSH arth { CHECK_PTR_VAL(($$ = gen_arth(cstate, BPF_RSH, $1, $3))); } + | '-' arth %prec UMINUS { CHECK_PTR_VAL(($$ = gen_neg(cstate, $2))); } + | paren narth ')' { $$ = $2; } + | LEN { CHECK_PTR_VAL(($$ = gen_loadlen(cstate))); } + ; +byteop: '&' { $$ = '&'; } + | '|' { $$ = '|'; } + | '<' { $$ = '<'; } + | '>' { $$ = '>'; } + | '=' { $$ = '='; } + ; +pnum: NUM + | paren pnum ')' { $$ = $2; } + ; +atmtype: LANE { $$ = A_LANE; } + | METAC { $$ = A_METAC; } + | BCC { $$ = A_BCC; } + | OAMF4EC { $$ = A_OAMF4EC; } + | OAMF4SC { $$ = A_OAMF4SC; } + | SC { $$ = A_SC; } + | ILMIC { $$ = A_ILMIC; } + ; +atmmultitype: OAM { $$ = A_OAM; } + | OAMF4 { $$ = A_OAMF4; } + | CONNECTMSG { $$ = A_CONNECTMSG; } + | METACONNECT { $$ = A_METACONNECT; } + ; + /* ATM field types quantifier */ +atmfield: VPI { $$.atmfieldtype = A_VPI; } + | VCI { $$.atmfieldtype = A_VCI; } + ; +atmvalue: atmfieldvalue + | relop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $0.atmfieldtype, $2, $1, 0))); } + | irelop NUM { CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $0.atmfieldtype, $2, $1, 1))); } + | paren atmlistvalue ')' { $$.b = $2.b; $$.q = qerr; } + ; +atmfieldvalue: NUM { + $$.atmfieldtype = $0.atmfieldtype; + if ($$.atmfieldtype == A_VPI || + $$.atmfieldtype == A_VCI) + CHECK_PTR_VAL(($$.b = gen_atmfield_code(cstate, $$.atmfieldtype, $1, BPF_JEQ, 0))); + } + ; +atmlistvalue: atmfieldvalue + | atmlistvalue or atmfieldvalue { gen_or($1.b, $3.b); $$ = $3; } + ; + /* MTP2 types quantifier */ +mtp2type: FISU { $$ = M_FISU; } + | LSSU { $$ = M_LSSU; } + | MSU { $$ = M_MSU; } + | HFISU { $$ = MH_FISU; } + | HLSSU { $$ = MH_LSSU; } + | HMSU { $$ = MH_MSU; } + ; + /* MTP3 field types quantifier */ +mtp3field: SIO { $$.mtp3fieldtype = M_SIO; } + | OPC { $$.mtp3fieldtype = M_OPC; } + | DPC { $$.mtp3fieldtype = M_DPC; } + | SLS { $$.mtp3fieldtype = M_SLS; } + | HSIO { $$.mtp3fieldtype = MH_SIO; } + | HOPC { $$.mtp3fieldtype = MH_OPC; } + | HDPC { $$.mtp3fieldtype = MH_DPC; } + | HSLS { $$.mtp3fieldtype = MH_SLS; } + ; +mtp3value: mtp3fieldvalue + | relop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, $2, $1, 0))); } + | irelop NUM { CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $0.mtp3fieldtype, $2, $1, 1))); } + | paren mtp3listvalue ')' { $$.b = $2.b; $$.q = qerr; } + ; +mtp3fieldvalue: NUM { + $$.mtp3fieldtype = $0.mtp3fieldtype; + if ($$.mtp3fieldtype == M_SIO || + $$.mtp3fieldtype == M_OPC || + $$.mtp3fieldtype == M_DPC || + $$.mtp3fieldtype == M_SLS || + $$.mtp3fieldtype == MH_SIO || + $$.mtp3fieldtype == MH_OPC || + $$.mtp3fieldtype == MH_DPC || + $$.mtp3fieldtype == MH_SLS) + CHECK_PTR_VAL(($$.b = gen_mtp3field_code(cstate, $$.mtp3fieldtype, $1, BPF_JEQ, 0))); + } + ; +mtp3listvalue: mtp3fieldvalue + | mtp3listvalue or mtp3fieldvalue { gen_or($1.b, $3.b); $$ = $3; } + ; +%% diff --git a/src/libpcap-1.10.5/ieee80211.h b/src/libpcap-1.10.5/ieee80211.h new file mode 100644 index 0000000000..473803d8a2 --- /dev/null +++ b/src/libpcap-1.10.5/ieee80211.h @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2001 Atsushi Onoe + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/net80211/ieee80211.h,v 1.10 2005/07/22 16:55:27 sam Exp $ + */ +#ifndef _NET80211_IEEE80211_H_ +#define _NET80211_IEEE80211_H_ + +/* + * 802.11 protocol definitions. + */ + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +/* for TYPE_CTL */ +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK 0x50 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL 0x60 +#define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACPL 0x70 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 +#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 + +#define IEEE80211_NWID_LEN 32 + +#define IEEE80211_QOS_TXOP 0x00ff +/* bit 8 is reserved */ +#define IEEE80211_QOS_ACKPOLICY 0x60 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_ESOP 0x10 +#define IEEE80211_QOS_ESOP_S 4 +#define IEEE80211_QOS_TID 0x0f + +#define IEEE80211_MGT_SUBTYPE_NAMES { \ + "assoc-req", "assoc-resp", \ + "reassoc-req", "reassoc-resp", \ + "probe-req", "probe-resp", \ + "reserved#6", "reserved#7", \ + "beacon", "atim", \ + "disassoc", "auth", \ + "deauth", "reserved#13", \ + "reserved#14", "reserved#15" \ +} + +#define IEEE80211_CTL_SUBTYPE_NAMES { \ + "reserved#0", "reserved#1", \ + "reserved#2", "reserved#3", \ + "reserved#3", "reserved#5", \ + "reserved#6", "reserved#7", \ + "reserved#8", "reserved#9", \ + "ps-poll", "rts", \ + "cts", "ack", \ + "cf-end", "cf-end-ack" \ +} + +#define IEEE80211_DATA_SUBTYPE_NAMES { \ + "data", "data-cf-ack", \ + "data-cf-poll", "data-cf-ack-poll", \ + "null", "cf-ack", \ + "cf-poll", "cf-ack-poll", \ + "qos-data", "qos-data-cf-ack", \ + "qos-data-cf-poll", "qos-data-cf-ack-poll", \ + "qos", "reserved#13", \ + "qos-cf-poll", "qos-cf-ack-poll" \ +} + +#define IEEE80211_TYPE_NAMES { "mgt", "ctl", "data", "reserved#4" } + +#endif /* _NET80211_IEEE80211_H_ */ diff --git a/src/libpcap-1.10.5/install-sh b/src/libpcap-1.10.5/install-sh new file mode 100755 index 0000000000..ec298b5374 --- /dev/null +++ b/src/libpcap-1.10.5/install-sh @@ -0,0 +1,541 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2020-11-14.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -p) cpprog="$cpprog -p";; + + -s) stripcmd=$stripprog;; + + -S) backupsuffix="$2" + shift;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/src/libpcap-1.10.5/lbl/os-aix4.h b/src/libpcap-1.10.5/lbl/os-aix4.h new file mode 100644 index 0000000000..5cf458627e --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-aix4.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in AIX 4.x */ +int ffs(int i); diff --git a/src/libpcap-1.10.5/lbl/os-aix7.h b/src/libpcap-1.10.5/lbl/os-aix7.h new file mode 100644 index 0000000000..93b12f2d26 --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-aix7.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in AIX 7.x */ +int ffs(int i); diff --git a/src/libpcap-1.10.5/lbl/os-hpux11.h b/src/libpcap-1.10.5/lbl/os-hpux11.h new file mode 100644 index 0000000000..42c6b60d49 --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-hpux11.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in HP-UX 11.x */ +int ffs(int i); diff --git a/src/libpcap-1.10.5/lbl/os-osf4.h b/src/libpcap-1.10.5/lbl/os-osf4.h new file mode 100644 index 0000000000..f461eeaff5 --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-osf4.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in Digital UNIX 4.x */ +int snprintf(char *, size_t, const char *, ...); +int vsnprintf(char *, size_t, const char *, va_list); +int pfopen(char *, int); + diff --git a/src/libpcap-1.10.5/lbl/os-osf5.h b/src/libpcap-1.10.5/lbl/os-osf5.h new file mode 100644 index 0000000000..52ab1750e1 --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-osf5.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Prototypes missing in Tru64 UNIX 5.x + * XXX - "snprintf()" and "vsnprintf()" aren't missing, but you have to + * #define the right value to get them defined by . + */ +int snprintf(char *, size_t, const char *, ...); +int vsnprintf(char *, size_t, const char *, va_list); +int pfopen(char *, int); + diff --git a/src/libpcap-1.10.5/lbl/os-solaris2.h b/src/libpcap-1.10.5/lbl/os-solaris2.h new file mode 100644 index 0000000000..22948b4a26 --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-solaris2.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in SunOS 5 */ +char *strerror(int); +int snprintf(char *, size_t, const char *, ...); diff --git a/src/libpcap-1.10.5/lbl/os-sunos4.h b/src/libpcap-1.10.5/lbl/os-sunos4.h new file mode 100644 index 0000000000..ab032ef98d --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-sunos4.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1989, 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in SunOS 4 */ +#ifdef FILE +int _filbuf(FILE *); +int _flsbuf(u_char, FILE *); +int fclose(FILE *); +int fflush(FILE *); +int fgetc(FILE *); +int fprintf(FILE *, const char *, ...); +int fputc(int, FILE *); +int fputs(const char *, FILE *); +u_int fread(void *, u_int, u_int, FILE *); +int fseek(FILE *, long, int); +u_int fwrite(const void *, u_int, u_int, FILE *); +int pclose(FILE *); +void rewind(FILE *); +void setbuf(FILE *, char *); +int setlinebuf(FILE *); +int ungetc(int, FILE *); +int vfprintf(FILE *, const char *, ...); +int vprintf(const char *, ...); +#endif + +#if __GNUC__ <= 1 +int read(int, char *, u_int); +int write(int, char *, u_int); +#endif + +long a64l(const char *); +#ifdef __STDC__ +struct sockaddr; +#endif +int accept(int, struct sockaddr *, int *); +int bind(int, struct sockaddr *, int); +int bcmp(const void *, const void *, u_int); +void bcopy(const void *, void *, u_int); +void bzero(void *, int); +int chroot(const char *); +int close(int); +void closelog(void); +int connect(int, struct sockaddr *, int); +char *crypt(const char *, const char *); +int daemon(int, int); +int fchmod(int, int); +int fchown(int, int, int); +void endgrent(void); +void endpwent(void); +#ifdef __STDC__ +struct ether_addr; +#endif +struct ether_addr *ether_aton(const char *); +int flock(int, int); +#ifdef __STDC__ +struct stat; +#endif +int fstat(int, struct stat *); +#ifdef __STDC__ +struct statfs; +#endif +int fstatfs(int, struct statfs *); +int fsync(int); +#ifdef __STDC__ +struct timeb; +#endif +int ftime(struct timeb *); +int ftruncate(int, off_t); +int getdtablesize(void); +long gethostid(void); +int gethostname(char *, int); +int getopt(int, char * const *, const char *); +int getpagesize(void); +char *getpass(char *); +int getpeername(int, struct sockaddr *, int *); +int getpriority(int, int); +#ifdef __STDC__ +struct rlimit; +#endif +int getrlimit(int, struct rlimit *); +int getsockname(int, struct sockaddr *, int *); +int getsockopt(int, int, int, char *, int *); +#ifdef __STDC__ +struct timeval; +struct timezone; +#endif +int gettimeofday(struct timeval *, struct timezone *); +char *getusershell(void); +char *getwd(char *); +int initgroups(const char *, int); +int ioctl(int, int, caddr_t); +int iruserok(u_long, int, char *, char *); +int isatty(int); +int killpg(int, int); +int listen(int, int); +#ifdef __STDC__ +struct utmp; +#endif +void login(struct utmp *); +int logout(const char *); +off_t lseek(int, off_t, int); +int lstat(const char *, struct stat *); +int mkstemp(char *); +char *mktemp(char *); +int munmap(caddr_t, int); +void openlog(const char *, int, int); +void perror(const char *); +int printf(const char *, ...); +int puts(const char *); +long random(void); +int readlink(const char *, char *, int); +#ifdef __STDC__ +struct iovec; +#endif +int readv(int, struct iovec *, int); +int recv(int, char *, u_int, int); +int recvfrom(int, char *, u_int, int, struct sockaddr *, int *); +int rename(const char *, const char *); +int rcmd(char **, u_short, char *, char *, char *, int *); +int rresvport(int *); +int send(int, char *, u_int, int); +int sendto(int, char *, u_int, int, struct sockaddr *, int); +int setenv(const char *, const char *, int); +int seteuid(int); +int setpriority(int, int, int); +int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +int setpgrp(int, int); +void setpwent(void); +int setrlimit(int, struct rlimit *); +int setsockopt(int, int, int, char *, int); +int shutdown(int, int); +int sigblock(int); +void (*signal (int, void (*) (int))) (int); +int sigpause(int); +int sigsetmask(int); +#ifdef __STDC__ +struct sigvec; +#endif +int sigvec(int, struct sigvec *, struct sigvec*); +int snprintf(char *, size_t, const char *, ...); +int socket(int, int, int); +int socketpair(int, int, int, int *); +int symlink(const char *, const char *); +void srandom(int); +int sscanf(char *, const char *, ...); +int stat(const char *, struct stat *); +int statfs(char *, struct statfs *); +char *strerror(int); +int strcasecmp(const char *, const char *); +#ifdef __STDC__ +struct tm; +#endif +int strftime(char *, int, char *, struct tm *); +int strncasecmp(const char *, const char *, int); +long strtol(const char *, char **, int); +void sync(void); +void syslog(int, const char *, ...); +int system(const char *); +long tell(int); +time_t time(time_t *); +char *timezone(int, int); +int tolower(int); +int toupper(int); +int truncate(char *, off_t); +void unsetenv(const char *); +int vfork(void); +int vsprintf(char *, const char *, ...); +int writev(int, struct iovec *, int); +#ifdef __STDC__ +struct rusage; +#endif +int utimes(const char *, struct timeval *); +#if __GNUC__ <= 1 +int wait(int *); +pid_t wait3(int *, int, struct rusage *); +#endif + +/* Ugly signal hacking */ +#ifdef SIG_ERR +#undef SIG_ERR +#define SIG_ERR (void (*)(int))-1 +#undef SIG_DFL +#define SIG_DFL (void (*)(int))0 +#undef SIG_IGN +#define SIG_IGN (void (*)(int))1 + +#ifdef KERNEL +#undef SIG_CATCH +#define SIG_CATCH (void (*)(int))2 +#endif +#undef SIG_HOLD +#define SIG_HOLD (void (*)(int))3 +#endif diff --git a/src/libpcap-1.10.5/lbl/os-ultrix4.h b/src/libpcap-1.10.5/lbl/os-ultrix4.h new file mode 100644 index 0000000000..21e570234b --- /dev/null +++ b/src/libpcap-1.10.5/lbl/os-ultrix4.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Prototypes missing in Ultrix 4 */ +int bcmp(const char *, const char *, u_int); +void bcopy(const void *, void *, u_int); +void bzero(void *, u_int); +int getopt(int, char * const *, const char *); +#ifdef __STDC__ +struct timeval; +struct timezone; +#endif +int gettimeofday(struct timeval *, struct timezone *); +int ioctl(int, int, caddr_t); +int pfopen(char *, int); +int setlinebuf(FILE *); +int socket(int, int, int); +int strcasecmp(const char *, const char *); diff --git a/src/libpcap-1.10.5/libpcap.pc.in b/src/libpcap-1.10.5/libpcap.pc.in new file mode 100644 index 0000000000..629e662ab0 --- /dev/null +++ b/src/libpcap-1.10.5/libpcap.pc.in @@ -0,0 +1,19 @@ +# +# pkg-config file for libpcap. +# +# These variables come from the configure script, so includedir and +# libdir may be defined in terms of prefix and exec_prefix, so the +# latter must be defined as well. +# +prefix="@prefix@" +exec_prefix="@exec_prefix@" +includedir="@includedir@" +libdir="@libdir@" + +Name: libpcap +Description: Platform-independent network traffic capture library +Version: @PACKAGE_VERSION@ +Requires.private: @REQUIRES_PRIVATE@ +Libs: -L${libdir} @RPATH@ -l@PACKAGE_NAME@ +Libs.private: @LIBS_PRIVATE@ +Cflags: -I${includedir} diff --git a/src/libpcap-1.10.5/llc.h b/src/libpcap-1.10.5/llc.h new file mode 100644 index 0000000000..b0cf881ca1 --- /dev/null +++ b/src/libpcap-1.10.5/llc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Definitions for information in the LLC header. + */ + +#define LLC_U_FMT 3 +#define LLC_GSAP 1 +#define LLC_IG 1 /* Individual / Group */ +#define LLC_S_FMT 1 + +#define LLC_U_POLL 0x10 +#define LLC_IS_POLL 0x0100 +#define LLC_XID_FI 0x81 + +#define LLC_U_CMD_MASK 0xef +#define LLC_UI 0x03 +#define LLC_UA 0x63 +#define LLC_DISC 0x43 +#define LLC_DM 0x0f +#define LLC_SABME 0x6f +#define LLC_TEST 0xe3 +#define LLC_XID 0xaf +#define LLC_FRMR 0x87 + +#define LLC_S_CMD_MASK 0x0f +#define LLC_RR 0x0001 +#define LLC_RNR 0x0005 +#define LLC_REJ 0x0009 + +#define LLC_IS_NR(is) (((is) >> 9) & 0x7f) +#define LLC_I_NS(is) (((is) >> 1) & 0x7f) + +/* + * 802.2 LLC SAP values. + */ + +#ifndef LLCSAP_NULL +#define LLCSAP_NULL 0x00 +#endif +#ifndef LLCSAP_GLOBAL +#define LLCSAP_GLOBAL 0xff +#endif +#ifndef LLCSAP_8021B_I +#define LLCSAP_8021B_I 0x02 +#endif +#ifndef LLCSAP_8021B_G +#define LLCSAP_8021B_G 0x03 +#endif +#ifndef LLCSAP_IP +#define LLCSAP_IP 0x06 +#endif +#ifndef LLCSAP_PROWAYNM +#define LLCSAP_PROWAYNM 0x0e +#endif +#ifndef LLCSAP_8021D +#define LLCSAP_8021D 0x42 +#endif +#ifndef LLCSAP_RS511 +#define LLCSAP_RS511 0x4e +#endif +#ifndef LLCSAP_ISO8208 +#define LLCSAP_ISO8208 0x7e +#endif +#ifndef LLCSAP_PROWAY +#define LLCSAP_PROWAY 0x8e +#endif +#ifndef LLCSAP_SNAP +#define LLCSAP_SNAP 0xaa +#endif +#ifndef LLCSAP_IPX +#define LLCSAP_IPX 0xe0 +#endif +#ifndef LLCSAP_NETBEUI +#define LLCSAP_NETBEUI 0xf0 +#endif +#ifndef LLCSAP_ISONS +#define LLCSAP_ISONS 0xfe +#endif diff --git a/src/libpcap-1.10.5/missing/asprintf.c b/src/libpcap-1.10.5/missing/asprintf.c new file mode 100644 index 0000000000..7c636927d8 --- /dev/null +++ b/src/libpcap-1.10.5/missing/asprintf.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include "portability.h" + +/* + * vasprintf() and asprintf() for platforms with a C99-compliant + * snprintf() - so that, if you format into a 1-byte buffer, it + * will return how many characters it would have produced had + * it been given an infinite-sized buffer. + */ +int +pcapint_vasprintf(char **strp, const char *format, va_list args) +{ + char buf; + int len; + size_t str_size; + char *str; + int ret; + + /* + * XXX - the C99 standard says, in section 7.19.6.5 "The + * snprintf function": + * + * The snprintf function is equivalent to fprintf, except that + * the output is written into an array (specified by argument s) + * rather than to a stream. If n is zero, nothing is written, + * and s may be a null pointer. Otherwise, output characters + * beyond the n-1st are discarded rather than being written + * to the array, and a null character is written at the end + * of the characters actually written into the array. + * + * ... + * + * The snprintf function returns the number of characters that + * would have been written had n been sufficiently large, not + * counting the terminating null character, or a negative value + * if an encoding error occurred. Thus, the null-terminated + * output has been completely written if and only if the returned + * value is nonnegative and less than n. + * + * That doesn't make it entirely clear whether, if a null buffer + * pointer and a zero count are passed, it will return the number + * of characters that would have been written had a buffer been + * passed. + * + * And, even if C99 *does*, in fact, say it has to work, it + * doesn't work in Solaris 8, for example - it returns -1 for + * NULL/0, but returns the correct character count for a 1-byte + * buffer. + * + * So we pass a one-character pointer in order to find out how + * many characters this format and those arguments will need + * without actually generating any more of those characters + * than we need. + * + * (The fact that it might happen to work with GNU libc or with + * various BSD libcs is completely uninteresting, as those tend + * to have asprintf() already and thus don't even *need* this + * code; this is for use in those UN*Xes that *don't* have + * asprintf().) + */ + len = vsnprintf(&buf, sizeof buf, format, args); + if (len == -1) { + *strp = NULL; + return (-1); + } + str_size = len + 1; + str = malloc(str_size); + if (str == NULL) { + *strp = NULL; + return (-1); + } + ret = vsnprintf(str, str_size, format, args); + if (ret == -1) { + free(str); + *strp = NULL; + return (-1); + } + *strp = str; + /* + * vsnprintf() shouldn't truncate the string, as we have + * allocated a buffer large enough to hold the string, so its + * return value should be the number of characters written. + */ + return (ret); +} + +int +pcapint_asprintf(char **strp, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = pcapint_vasprintf(strp, format, args); + va_end(args); + return (ret); +} + diff --git a/src/libpcap-1.10.5/missing/getopt.c b/src/libpcap-1.10.5/missing/getopt.c new file mode 100644 index 0000000000..c535776d84 --- /dev/null +++ b/src/libpcap-1.10.5/missing/getopt.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const *nargv, const char *ostr) +{ + char *cp; + static char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (__progname == NULL) { + if ((cp = strrchr(nargv[0], '/')) != NULL) + __progname = cp + 1; + else + __progname = nargv[0]; + } + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } + optopt = (int)*place++; + if (optopt == (int)':') { /* option letter okay? */ + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + oli = strchr(ostr, optopt); + if (!oli) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/src/libpcap-1.10.5/missing/getopt.h b/src/libpcap-1.10.5/missing/getopt.h new file mode 100644 index 0000000000..fc83c944d7 --- /dev/null +++ b/src/libpcap-1.10.5/missing/getopt.h @@ -0,0 +1,7 @@ +/* + * Header for the getopt() we supply if the platform doesn't supply it. + */ +extern char *optarg; /* getopt(3) external variables */ +extern int optind, opterr, optreset, optopt; + +extern int getopt(int nargc, char * const *nargv, const char *ostr); diff --git a/src/libpcap-1.10.5/missing/strlcat.c b/src/libpcap-1.10.5/missing/strlcat.c new file mode 100644 index 0000000000..f96d37b387 --- /dev/null +++ b/src/libpcap-1.10.5/missing/strlcat.c @@ -0,0 +1,59 @@ +/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "portability.h" + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +pcapint_strlcat(char * restrict dst, const char * restrict src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/src/libpcap-1.10.5/missing/strlcpy.c b/src/libpcap-1.10.5/missing/strlcpy.c new file mode 100644 index 0000000000..494ff77390 --- /dev/null +++ b/src/libpcap-1.10.5/missing/strlcpy.c @@ -0,0 +1,54 @@ +/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "portability.h" + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +pcapint_strlcpy(char * restrict dst, const char * restrict src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/src/libpcap-1.10.5/missing/strtok_r.c b/src/libpcap-1.10.5/missing/strtok_r.c new file mode 100644 index 0000000000..0534e49ace --- /dev/null +++ b/src/libpcap-1.10.5/missing/strtok_r.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1998 Softweyr LLC. All rights reserved. + * + * strtok_r, from Berkeley strtok + * Oct 13, 1998 by Wes Peters + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE + * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: @(#)strtok.c 8.1 (Berkeley) 6/4/93 + */ + +#include + +#include "portability.h" + +char * +pcapint_strtok_r(char *s, const char *delim, char **last) +{ + char *spanp, *tok; + int c, sc; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = '\0'; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/src/libpcap-1.10.5/missing/win_asprintf.c b/src/libpcap-1.10.5/missing/win_asprintf.c new file mode 100644 index 0000000000..076bc562da --- /dev/null +++ b/src/libpcap-1.10.5/missing/win_asprintf.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "portability.h" + +int +pcapint_vasprintf(char **strp, const char *format, va_list args) +{ + int len; + size_t str_size; + char *str; + int ret; + + len = _vscprintf(format, args); + if (len == -1) { + *strp = NULL; + return (-1); + } + str_size = len + 1; + str = malloc(str_size); + if (str == NULL) { + *strp = NULL; + return (-1); + } + ret = vsnprintf(str, str_size, format, args); + if (ret == -1) { + free(str); + *strp = NULL; + return (-1); + } + *strp = str; + /* + * vsnprintf() shouldn't truncate the string, as we have + * allocated a buffer large enough to hold the string, so its + * return value should be the number of characters printed. + */ + return (ret); +} + +int +pcapint_asprintf(char **strp, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = pcapint_vasprintf(strp, format, args); + va_end(args); + return (ret); +} diff --git a/src/libpcap-1.10.5/mkdep b/src/libpcap-1.10.5/mkdep new file mode 100755 index 0000000000..1bc1d0cf6e --- /dev/null +++ b/src/libpcap-1.10.5/mkdep @@ -0,0 +1,123 @@ +#!/bin/sh -e +# +# Copyright (c) 1994, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that this notice is preserved and that due credit is given +# to the University of California at Berkeley. The name of the University +# may not be used to endorse or promote products derived from this +# software without specific prior written permission. This software +# is provided ``as is'' without express or implied warranty. +# +# @(#)mkdep.sh 5.11 (Berkeley) 5/5/88 +# + +MAKE=Makefile # default makefile name is "Makefile" +CC=cc # default C compiler is "cc" +DEPENDENCY_CFLAG=-M # default dependency-generation flag is -M +SOURCE_DIRECTORY=. # default source directory is the current directory + +# No command-line flags seen yet. +flags="" +while : + do case "$1" in + # -c allows you to specify the C compiler + -c) + CC=$2 + shift; shift ;; + + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # -m allows you to specify the dependency-generation flag + -m) + DEPENDENCY_CFLAG=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + + # -s allows you to specify the source directory + -s) + SOURCE_DIRECTORY=$2 + shift; shift ;; + + # -include takes an argument + -include) + flags="$flags $1 $2" + shift; shift ;; + + # other command-line flag + -*) + flags="$flags $1" + shift ;; + + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-c cc] [-f makefile] [-m dependency-cflag] [-s source-directory] [flags] file ...' + exit 1 +fi + +if [ ! -w "$MAKE" ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=${TMPDIR:-/tmp}/mkdep$$ + +trap 'rm -f "$TMP" ; exit 1' HUP INT QUIT PIPE TERM + +cp "$MAKE" "${MAKE}.bak" + +sed -e '/DO NOT DELETE THIS LINE/,$d' < "$MAKE" > "$TMP" + +cat << _EOF_ >> "$TMP" +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + +# If your compiler doesn't have -M, add it. If you can't, the next two +# lines will try and replace the "cc -M". The real problem is that this +# hack can't deal with anything that requires a search path, and doesn't +# even try for anything using bracket (<>) syntax. +# +# grep -E '^#include[[:blank:]]*".*"' /dev/null $* | +# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | + +# +# Construct a list of source files with paths relative to the source directory. +# +sources="" +for srcfile in "$@" +do + sources="$sources $SOURCE_DIRECTORY/$srcfile" +done + +# XXX this doesn't work with things like "-DDECLWAITSTATUS=union\ wait" +# $flags and $sources are meant to expand +# shellcheck disable=SC2086 +"$CC" "$DEPENDENCY_CFLAG" $flags $sources | +sed " + s; \./; ;g + $SED" >> "$TMP" + +cat << _EOF_ >> "$TMP" + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp "$TMP" "$MAKE" +rm -f "${MAKE}.bak" "$TMP" +exit 0 diff --git a/src/libpcap-1.10.5/msdos/bin2c.c b/src/libpcap-1.10.5/msdos/bin2c.c new file mode 100644 index 0000000000..26d90083fb --- /dev/null +++ b/src/libpcap-1.10.5/msdos/bin2c.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +static void Abort (const char *fmt,...) +{ + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + exit (1); +} + +int main (int argc, char **argv) +{ + FILE *inFile; + FILE *outFile = stdout; + time_t now = time (NULL); + int ch, i; + + if (argc != 2) + Abort ("Usage: %s bin-file [> result]", argv[0]); + + if ((inFile = fopen(argv[1],"rb")) == NULL) + Abort ("Cannot open %s\n", argv[1]); + + fprintf (outFile, + "/* data statements for file %s at %.24s */\n" + "/* Generated by BIN2C, G. Vanem 1995 */\n", + argv[1], ctime(&now)); + + i = 0; + while ((ch = fgetc(inFile)) != EOF) + { + if (i++ % 12 == 0) + fputs ("\n ", outFile); + fprintf (outFile, "0x%02X,", ch); + } + fputc ('\n', outFile); + fclose (inFile); + return (0); +} diff --git a/src/libpcap-1.10.5/msdos/makefile b/src/libpcap-1.10.5/msdos/makefile new file mode 100644 index 0000000000..f14ed1ec8a --- /dev/null +++ b/src/libpcap-1.10.5/msdos/makefile @@ -0,0 +1,180 @@ +# +# Makefile for dos-libpcap. NB. This makefile requires a Borland +# compatible make tool. +# +# Targets: +# Borland C 4.0+ (DOS large model) +# Metaware HighC 3.3+ (PharLap 386|DosX) +# + +.AUTODEPEND +.SWAP + +!if "$(WATT_ROOT)" == "" +!error Environment variable "WATT_ROOT" not set. +!endif + +WATT_INC = $(WATT_ROOT)\inc + +DEFS = -DMSDOS -DDEBUG -DNDIS_DEBUG -D_U_= -Dinline= \ + -DHAVE_STRERROR -DHAVE_LIMITS_H + +ASM = tasm.exe -t -l -mx -m2 -DDEBUG + +SOURCE = grammar.c scanner.c bpf_filt.c bpf_imag.c bpf_dump.c \ + etherent.c gencode.c nametoad.c pcap-dos.c optimize.c \ + savefile.c pcap.c msdos\ndis2.c msdos\pktdrvr.c \ + missing\snprintf.c + +BORLAND_OBJ = $(SOURCE:.c=.obj) msdos\pkt_rx0.obj msdos\ndis_0.obj + +HIGHC_OBJ = $(SOURCE:.c=.o32) msdos\pkt_rx0.o32 + +all: + @echo Usage: make pcap_bc.lib or pcap_hc.lib + + +pcap_bc.lib: bcc.arg $(BORLAND_OBJ) pcap_bc + + +pcap_hc.lib: hc386.arg $(HIGHC_OBJ) + 386lib $< @&&| + -nowarn -nobackup -twocase -replace $(HIGHC_OBJ) +| + +pcap_bc: $(BORLAND_OBJ) + @tlib pcap_bc.lib /C @&&| + -+$(**:.obj=-+) +| + +.c.obj: + bcc.exe @bcc.arg -o$*.obj $*.c + +.c.o32: + hc386.exe @hc386.arg -o $*.o32 $*.c + +.asm.obj: + $(ASM) $*.asm, $*.obj + +.asm.o32: + $(ASM) -DDOSX=1 $*.asm, $*.o32 + +scanner.c: scanner.l + flex -Ppcap_ -7 -oscanner.c scanner.l + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines grammar.y + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +bcc.arg: msdos\Makefile + @copy &&| + $(DEFS) -ml -c -v -3 -O2 -po -RT- -w- + -I$(WATT_INC) -I. -I.\msdos\pm_drvr -H=$(TEMP)\bcc.sym +| $< + +hc386.arg: msdos\Makefile + @copy &&| + # -DUSE_32BIT_DRIVERS + $(DEFS) -DDOSX=1 -w3 -c -g -O5 + -I$(WATT_INC) -I. -I.\msdos\pm_drvr + -Hsuffix=.o32 + -Hnocopyr + -Hpragma=Offwarn(491,553,572) + -Hon=Recognize_library # make memcpy/strlen etc. inline + -Hoff=Behaved # turn off some optimizer warnings +| $< + +clean: + @del *.obj + @del *.o32 + @del *.lst + @del *.map + @del bcc.arg + @del hc386.arg + @del grammar.c + @del tokdefs.h + @del scanner.c + @echo Cleaned + +# +# dependencies +# +pkt_rx0.obj: msdos\pkt_rx0.asm + +bpf_filt.obj: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h + +bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.obj: msdos\pktdrvr.c pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + +pkt_rx0.o32: msdos\pkt_rx0.asm + +bpf_filt.o32: bpf_filt.c pcap-int.h pcap.h pcap-bpf.h + +bpf_imag.o32: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +bpf_dump.o32: bpf_dump.c pcap.h pcap-bpf.h + +etherent.o32: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +optimize.o32: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +savefile.o32: savefile.c pcap-int.h pcap.h pcap-bpf.h + +pcap.o32: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +grammar.o32: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pf.h pcap-namedb.h + +scanner.o32: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h tokdefs.h + +gencode.o32: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + ethertype.h nlpid.h llc.h gencode.h atmuni31.h sunatmpos.h ppp.h sll.h \ + arcnet.h pf.h pcap-namedb.h + +nametoad.o32: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h \ + pcap-namedb.h ethertype.h + +pcap-dos.o32: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h \ + msdos\pktdrvr.h + +pktdrvr.o32: msdos\pktdrvr.c pcap-dos.h pcap-int.h \ + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +ndis2.o32: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h \ + msdos\ndis2.h + diff --git a/src/libpcap-1.10.5/msdos/makefile.dj b/src/libpcap-1.10.5/msdos/makefile.dj new file mode 100644 index 0000000000..3b6f31bda9 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/makefile.dj @@ -0,0 +1,127 @@ +# +# GNU Makefile for DOS-libpcap. djgpp version. +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> make -f msdos/makefile.dj +# +# Note: you should do a "set LFN=y" before running this makefile. +# + +VPATH = missing msdos + +PREREQUISITES = scanner.c grammar.c tokdefs.h version.h msdos/pkt_stub.inc + +include ./msdos/common.dj + +DRIVER_DIR = ./msdos/pm_drvr + +CFLAGS += -DDEBUG -DNDIS_DEBUG -DHAVE_LIMITS_H -DHAVE_STRERROR -DHAVE_SNPRINTF -DHAVE_VSNPRINTF\ + -D_U_='__attribute__((unused))' + +CFLAGS += -Dyylval=pcap_lval # -DBDEBUG -DNDEBUG + +SOURCES = grammar.c scanner.c bpf_filter.c bpf_image.c bpf_dump.c \ + etherent.c gencode.c nametoaddr.c pcap-common.c pcap-dos.c optimize.c \ + savefile.c pcap.c sf-pcap.c sf-pcapng.c \ + msdos/pktdrvr.c msdos/ndis2.c # missing/snprintf.c + +OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:.c=.o))) +TEMPBIN = tmp.bin + +ifeq ($(USE_32BIT_DRIVERS),1) + PM_OBJECTS = $(addprefix $(OBJ_DIR)/, \ + printk.o pci.o pci-scan.o bios32.o dma.o irq.o intwrap.o \ + lock.o kmalloc.o quirks.o timer.o net_init.o) + # + # Static link of drivers + # + ifeq ($(USE_32BIT_MODULES),0) + PM_OBJECTS += $(addprefix $(OBJ_DIR)/, \ + accton.o 8390.o 3c503.o 3c509.o 3c59x.o 3c515.o \ + 3c575_cb.o 3c90x.o ne.o wd.o cs89x0.o rtl8139.o) + endif +endif + +TARGETS = msdos/bin2c.exe libpcap.a filtertest.exe findalldevstest.exe \ + nonblocktest.exe opentest.exe + +all: $(TARGETS) + @echo 'Welcome to libpcap/djgpp with samples.' + +ifeq ($(USE_32BIT_DRIVERS),1) +$(PM_OBJECTS): + $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) $(notdir $@) +endif + +libpcap.a: version.h $(OBJECTS) $(PM_OBJECTS) + rm -f $@ + ar rs $@ $^ + +filtertest.exe: tests/filtertest.c libpcap.a + $(CC) $(CFLAGS) -Din_addr_t=u_long -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a + @echo + +findalldevstest.exe: tests/findalldevstest.c libpcap.a + $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a + @echo + +nonblocktest.exe: tests/nonblocktest.c libpcap.a + $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a + @echo + +opentest.exe: tests/opentest.c libpcap.a + $(CC) $(CFLAGS) -o $@ $^ $(WATT32_ROOT)/lib/libwatt.a + @echo + +msdos/pkt_stub.inc: msdos/bin2c.exe msdos/pkt_rx1.S + $(ASM) -o $(TEMPBIN) -lmsdos/pkt_rx1.lst msdos/pkt_rx1.S + ./msdos/bin2c $(TEMPBIN) > $@ + rm -f $(TEMPBIN) + +grammar.c tokdefs.h: grammar.y + rm -f grammar.c tokdefs.h + $(YACC) --name-prefix=pcap_ --yacc --defines grammar.y + mv -f y.tab.c grammar.c + mv -f y.tab.h tokdefs.h + +version.h: ./VERSION + @echo '/* Generated from VERSION. Do not edit */' > $@ + sed -e 's/.*/static char pcap_version_string[] = "libpcap (&)";/' ./VERSION >> $@ + +scanner.c: scanner.l + $(LEX) -Ppcap_ -7 -t $^ > $@ + @echo + +msdos/bin2c.exe: msdos/bin2c.c + $(CC) $*.c -o $*.exe + +clean: + rm -f $(OBJECTS) msdos/pkt_rx1.lst Makefile.bak .depend.dj $(PREREQUISITES) +# $(MAKE) -f Makefile.dj -C $(DRIVER_DIR) clean + +vclean: clean + rm -f $(TARGETS) + -rmdir $(OBJ_DIR) + +# +# Manually generated dependencies +# +msdos/pktdrvr.c: msdos/pkt_stub.inc +scanner.c: scanner.l +grammar.c tokdefs.h: grammar.y +grammar.h: grammar.y +scanner.l: pcap-int.h pcap-namedb.h gencode.h grammar.h +grammar.y: pcap-int.h gencode.h pcap-namedb.h + +# +# Generate dependencies. +# +REPLACE = sed -e 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/\1.o: /' + +depend: $(PREREQUISITES) + $(CC) -MM $(CFLAGS) $(SOURCES) | $(REPLACE) > .depend.dj + +-include .depend.dj + diff --git a/src/libpcap-1.10.5/msdos/makefile.wc b/src/libpcap-1.10.5/msdos/makefile.wc new file mode 100644 index 0000000000..a0aa71fc46 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/makefile.wc @@ -0,0 +1,132 @@ +# +# Watcom Makefile for dos-libpcap. +# +# Specify MODEL = `3r' or `3s' +# Specify TARGET = `pharlap' or `dos4g' +# +# Use this makefile from the libpcap root directory. +# E.g. like this: +# +# c:\net\pcap> wmake -f msdos\makefile.wc +# + +MODEL = 3s +TARGET = dos4g + +OBJDIR = msdos\$(TARGET).w$(MODEL) +LIB = $(OBJDIR)\pcap.lib + +.EXTENSIONS: .l .y + +DEFS = -dDEBUG -dNDIS_DEBUG -d_U_= -dHAVE_LIMITS_H -dHAVE_STRERROR & + -dHAVE_SNPRINTF -dHAVE_VSNPRINTF + +CC = wcc386.exe +ASM = wasm.exe -$(MODEL) $(DEFS) -dDOSX -dDOS4GW -zq -bt=dos -fr=nul -d3 -s + +OBJS = $(OBJDIR)\grammar.obj $(OBJDIR)\scanner.obj $(OBJDIR)\pcap.obj & + $(OBJDIR)\bpf_filter.obj $(OBJDIR)\bpf_imag.obj $(OBJDIR)\bpf_dump.obj & + $(OBJDIR)\etherent.obj $(OBJDIR)\gencode.obj $(OBJDIR)\nametoad.obj & + $(OBJDIR)\pcap-dos.obj $(OBJDIR)\pktdrvr.obj $(OBJDIR)\optimize.obj & + $(OBJDIR)\savefile.obj $(OBJDIR)\ndis2.obj + +CFLAGS = $(DEFS) $(YYDEFS) -I. -I$(%watt_root)\inc -I.\msdos\pm_drvr & + -$(MODEL) -mf -zff -zgf -zq -bt=dos -fr=nul -w6 -fpi & + -oilrtf -zm + +TEMPBIN = tmp.bin + +all: $(OBJDIR) $(OBJDIR)\pcap.lib + +$(OBJDIR): + - mkdir $(OBJDIR) + +$(OBJDIR)\pcap.lib: $(OBJS) wlib.arg + wlib -q -b -c $(OBJDIR)\pcap.lib @wlib.arg + +wlib.arg: msdos\makefile.wc + %create $^@ + for %f in ($(OBJS)) do %append $^@ +- %f + +$(OBJDIR)\pktdrvr.obj: msdos\pkt_stub.inc msdos\pktdrvr.c & + pcap-dos.h pcap-int.h pcap.h msdos\pktdrvr.h + *$(CC) $(CFLAGS) msdos\pktdrvr.c -fo=$@ + +$(OBJDIR)\bpf_filter.obj: bpf_filter.c + *$(CC) $(CFLAGS) bpf_filter.c -fo=$@ + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c + *$(CC) $(CFLAGS) msdos\ndis2.c -fo=$@ + +.ERASE +.c{$(OBJDIR)}.obj: + *$(CC) $(CFLAGS) $[@ -fo=$@ + +grammar.c tokdefs.h: grammar.y + bison --name-prefix=pcap_ --yacc --defines $[@ + - @del grammar.c + - @del tokdefs.h + ren y_tab.c grammar.c + ren y_tab.h tokdefs.h + +scanner.c: scanner.l + flex -Ppcap_ -7 -o$@ $[@ + +msdos\pkt_stub.inc: bin2c.exe msdos\pkt_rx1.S + nasm -fbin -dDEBUG -o $(TEMPBIN) -lmsdos\pkt_rx1.lst msdos\pkt_rx1.S + bin2c.exe $(TEMPBIN) > $@ + @del $(TEMPBIN) + +bin2c.exe: msdos\bin2c.c + wcl $[@ + +clean realclean vclean: .SYMBOLIC + for %f in (dos4g.w3r dos4g.w3s pharlap.w3r pharlap.w3s) do & + @del %f\*.obj + @del grammar.c + @del tokdefs.h + @del scanner.c + @del bin2c.exe + @del bin2c.obj + @del msdos\pkt_stub.inc + @echo Cleaned + +# +# dependencies +# +$(OBJDIR)\bpf_filter.obj: bpf_filter.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\bpf_imag.obj: bpf_imag.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\bpf_dump.obj: bpf_dump.c pcap.h pcap-bpf.h + +$(OBJDIR)\etherent.obj: etherent.c pcap-int.h pcap.h pcap-bpf.h pcap-namedb.h + +$(OBJDIR)\optimize.obj: optimize.c pcap-int.h pcap.h pcap-bpf.h gencode.h + +$(OBJDIR)\savefile.obj: savefile.c pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\pcap.obj: pcap.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h + +$(OBJDIR)\grammar.obj: grammar.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-namedb.h + +$(OBJDIR)\scanner.obj: scanner.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-namedb.h tokdefs.h + +$(OBJDIR)\gencode.obj: gencode.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + ethertyp.h nlpid.h llc.h gencode.h atmuni31.h sunatmpo.h ppp.h sll.h & + arcnet.h pcap-namedb.h + +$(OBJDIR)\nametoad.obj: nametoad.c pcap-int.h pcap.h pcap-bpf.h gencode.h & + pcap-namedb.h ethertyp.h + +$(OBJDIR)\pcap-dos.obj: pcap-dos.c pcap.h pcap-bpf.h pcap-dos.h pcap-int.h & + msdos\pktdrvr.h + +$(OBJDIR)\pktdrvr.obj: msdos\pktdrvr.c pcap-dos.h pcap-int.h & + pcap.h pcap-bpf.h msdos\pktdrvr.h msdos\pkt_stub.inc + +$(OBJDIR)\ndis2.obj: msdos\ndis2.c pcap-dos.h pcap-int.h pcap.h pcap-bpf.h & + msdos\ndis2.h + diff --git a/src/libpcap-1.10.5/msdos/pkt_rx0.asm b/src/libpcap-1.10.5/msdos/pkt_rx0.asm new file mode 100644 index 0000000000..d604fa14be --- /dev/null +++ b/src/libpcap-1.10.5/msdos/pkt_rx0.asm @@ -0,0 +1,197 @@ +PAGE 60,132 +NAME PKT_RX + +ifdef ??version ; using TASM + masm + jumps +endif + +PUBLIC _pktDrop, _pktRxBuf, _pktTxBuf, _pktTemp +PUBLIC _rxOutOfs, _rxInOfs, _PktReceiver, _pktRxEnd + +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; + +RX_BUF_SIZE = 1500 ; max message size on Ethernet +TX_BUF_SIZE = 1500 + +ifdef DOSX + .386 + NUM_RX_BUF = 32 ; # of RX element buffers + _TEXT SEGMENT PUBLIC DWORD USE16 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD USE16 'CODE' + _DATA ENDS + D_SEG EQU <_TEXT SEGMENT> + D_END EQU <_TEXT ENDS> + ASSUME CS:_TEXT,DS:_TEXT +else + .286 + NUM_RX_BUF = 10 + _TEXT SEGMENT PUBLIC DWORD 'CODE' + _TEXT ENDS + _DATA SEGMENT PUBLIC DWORD 'DATA' + _DATA ENDS + D_SEG EQU <_DATA SEGMENT> + D_END EQU <_DATA ENDS> + ASSUME CS:_TEXT,DS:_DATA +endif + +;------------------------------------------- + +D_SEG + +RX_ELEMENT STRUC + firstCount dw 0 ; # of bytes on 1st call + secondCount dw 0 ; # of bytes on 2nd call + handle dw 0 ; handle for upcall + destinAdr db 6 dup (0) ; packet destination address + sourceAdr db 6 dup (0) ; packet source address + protocol dw 0 ; packet protocol number + rxBuffer db RX_BUF_SIZE dup (0) ; RX buffer +ENDS + align 4 +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp db 20 dup (0) ; temp work area +_pktTxBuf db (TX_BUF_SIZE+14) dup (0) ; TX buffer +_pktRxBuf RX_ELEMENT NUM_RX_BUF dup (<>) ; RX structures + LAST_OFS = offset $ + + screenSeg dw 0B800h + newInOffset dw 0 + + fanChars db '-\|/' + fanIndex dw 0 + +D_END + +_TEXT SEGMENT + + +SHOW_RX MACRO + push es + push bx + mov bx, screenSeg + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, fanIndex + mov al, fanChars[bx] ;; get write char + mov ah, 15 ;; and white colour + stosw ;; write to screen at ES:EDI + inc fanIndex ;; update next index + and fanIndex, 3 + pop bx + pop es +ENDM + +;------------------------------------------------------------------------ +; +; This macro return ES:DI to tail of Rx queue + +ENQUEUE MACRO + LOCAL @noWrap + mov ax, _rxInOfs ;; DI = current in-offset + add ax, SIZE RX_ELEMENT ;; point to next _pktRxBuf buffer + cmp ax, LAST_OFS ;; pointing past last ? + jb @noWrap ;; no - jump + lea ax, _pktRxBuf ;; yes, point to 1st buffer + align 4 +@noWrap: cmp ax, _rxOutOfs ;; in-ofs = out-ofs ? + je @dump ;; yes, queue is full + mov di, _rxInOfs ;; ES:DI -> buffer at queue input + mov newInOffset, ax ;; remember new input offset + + ;; NOTE. rxInOfs is updated after the packet has been copied + ;; to ES:DI (= DS:SI on 2nd call) by the packet driver + +ENDM + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx +ifdef DOSX + mov bx, cs +else + mov bx, SEG _DATA +endif + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +ifdef DEBUG + SHOW_RX ; show that a packet is received +endif + cmp cx, RX_BUF_SIZE+14 ; size OK ? + ja @skip ; no, packet to large for us + + ENQUEUE ; ES:DI -> _pktRxBuf[n] + + mov [di].firstCount, cx ; remember the first count. + mov [di].handle, bx ; remember the handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + + align 4 +@dump: inc _pktDrop[0] ; discard the packet on 1st call + adc _pktDrop[2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + + align 4 +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + sub si, 6 ; DS:SI -> _pktRxBuf[n].destinAdr + ; + ; push si + ; push [si].firstCount + ; call bpf_filter_match ; run the filter here some day? + ; add sp, 4 + ; cmp ax, 0 + ; je @discard + + mov [si].secondCount, cx + mov ax, newInOffset + mov _rxInOfs, ax ; update _pktRxBuf input offset + + align 4 +@discard:pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +_TEXT ENDS + +END diff --git a/src/libpcap-1.10.5/msdos/pkt_rx1.s b/src/libpcap-1.10.5/msdos/pkt_rx1.s new file mode 100644 index 0000000000..654e657779 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/pkt_rx1.s @@ -0,0 +1,155 @@ +; +; This file requires NASM 0.97+ to assemble +; +; Currently used only for djgpp + DOS4GW targets +; +; these sizes MUST be equal to the sizes in PKTDRVR.H +; +%define ETH_MTU 1500 ; max data size on Ethernet +%define ETH_MIN 60 ; min/max total frame size +%define ETH_MAX (ETH_MTU+2*6+2) ; =1514 +%define NUM_RX_BUF 32 ; # of RX element buffers +%define RX_SIZE (ETH_MAX+6) ; sizeof(RX_ELEMENT) = 1514+6 +%idefine offset + +struc RX_ELEMENT + .firstCount resw 1 ; # of bytes on 1st call + .secondCount resw 1 ; # of bytes on 2nd call + .handle resw 1 ; handle for upcall + ; .timeStamp resw 4 ; 64-bit RDTSC value + .destinAdr resb 6 ; packet destination address + .sourceAdr resb 6 ; packet source address + .protocol resw 1 ; packet protocol number + .rxBuffer resb ETH_MTU ; RX buffer +endstruc + +;------------------------------------------- + +[org 0] ; assemble to .bin file + +_rxOutOfs dw offset _pktRxBuf ; ring buffer offsets +_rxInOfs dw offset _pktRxBuf ; into _pktRxBuf +_pktDrop dw 0,0 ; packet drop counter +_pktTemp resb 20 ; temp work area +_pktTxBuf resb (ETH_MAX) ; TX buffer +_pktRxBuf resb (RX_SIZE*NUM_RX_BUF) ; RX structures + LAST_OFS equ $ + +screenSeg dw 0B800h +newInOffset dw 0 + +fanChars db '-\|/' +fanIndex dw 0 + +%macro SHOW_RX 0 + push es + push bx + mov bx, [screenSeg] + mov es, bx ;; r-mode segment of colour screen + mov di, 158 ;; upper right corner - 1 + mov bx, [fanIndex] + mov al, [fanChars+bx] ;; get write char + mov ah, 15 ;; and white colour + cld ;; Needed? + stosw ;; write to screen at ES:EDI + inc word [fanIndex] ;; update next index + and word [fanIndex], 3 + pop bx + pop es +%endmacro + +;PutTimeStamp +; rdtsc +; mov [si].timeStamp, eax +; mov [si+4].timeStamp, edx +; ret + + +;------------------------------------------------------------------------ +; +; This routine gets called by the packet driver twice: +; 1st time (AX=0) it requests an address where to put the packet +; +; 2nd time (AX=1) the packet has been copied to this location (DS:SI) +; BX has client handle (stored in RX_ELEMENT.handle). +; CX has # of bytes in packet on both call. They should be equal. +; A test for equality is done by putting CX in _pktRxBuf [n].firstCount +; and _pktRxBuf[n].secondCount, and CL on first call in +; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive" +; (PKTDRVR.C) +; +;--------------------------------------------------------------------- + +_PktReceiver: + pushf + cli ; no distraction wanted ! + push ds + push bx + mov bx, cs + mov ds, bx + mov es, bx ; ES = DS = CS or seg _DATA + pop bx ; restore handle + + cmp ax, 0 ; first call? (AX=0) + jne @post ; AX=1: second call, do post process + +%ifdef DEBUG + SHOW_RX ; show that a packet is received +%endif + + cmp cx, ETH_MAX ; size OK ? + ja @skip ; no, too big + + mov ax, [_rxInOfs] + add ax, RX_SIZE + cmp ax, LAST_OFS + jb @noWrap + mov ax, offset _pktRxBuf +@noWrap: + cmp ax, [_rxOutOfs] + je @dump + mov di, [_rxInOfs] ; ES:DI -> _pktRxBuf[n] + mov [newInOffset], ax + + mov [di], cx ; remember firstCount. + mov [di+4], bx ; remember handle. + add di, 6 ; ES:DI -> _pktRxBuf[n].destinAdr + pop ds + popf + retf ; far return to driver with ES:DI + +@dump: add word [_pktDrop+0], 1 ; discard the packet on 1st call + adc word [_pktDrop+2], 0 ; increment packets lost + +@skip: xor di, di ; return ES:DI = NIL pointer + xor ax, ax + mov es, ax + pop ds + popf + retf + +@post: or si, si ; DS:SI->_pktRxBuf[n][n].destinAdr + jz @discard ; make sure we don't use NULL-pointer + + ; + ; push si + ; call bpf_filter_match ; run the filter here some day + ; pop si + ; cmp ax, 0 + ; je @discard + + mov [si-6+2], cx ; store _pktRxBuf[n].secondCount + mov ax, [newInOffset] + mov [_rxInOfs], ax ; update _pktRxBuf input offset + + ; call PutTimeStamp + +@discard: + pop ds + popf + retf + +_pktRxEnd db 0 ; marker for end of r-mode code/data + +END + diff --git a/src/libpcap-1.10.5/msdos/pktdrvr.c b/src/libpcap-1.10.5/msdos/pktdrvr.c new file mode 100644 index 0000000000..8ee5f92017 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/pktdrvr.c @@ -0,0 +1,1436 @@ +/* + * File.........: pktdrvr.c + * + * Responsible..: Gisle Vanem, giva@bgnett.no + * + * Created......: 26.Sept 1995 + * + * Description..: Packet-driver interface for 16/32-bit C : + * Borland C/C++ 3.0+ small/large model + * Watcom C/C++ 11+, DOS4GW flat model + * Metaware HighC 3.1+ and PharLap 386|DosX + * GNU C/C++ 2.7+ and djgpp 2.x extender + * + * References...: PC/TCP Packet driver Specification. rev 1.09 + * FTP Software Inc. + * + */ + +#include +#include +#include +#include + +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#if (DOSX) +#define NUM_RX_BUF 32 /* # of buffers in Rx FIFO queue */ +#else +#define NUM_RX_BUF 10 +#endif + +#define DIM(x) (sizeof((x)) / sizeof(x[0])) +#define PUTS(s) do { \ + if (!pktInfo.quiet) \ + pktInfo.error ? \ + printf ("%s: %s\n", s, pktInfo.error) : \ + printf ("%s\n", pktInfo.error = s); \ + } while (0) + +#if defined(__HIGHC__) + extern UINT _mwenv; + +#elif defined(__DJGPP__) + #include + #include + #include + #include + #include + +#elif defined(__WATCOMC__) + #include + #include + extern char _Extender; + +#else + extern void far PktReceiver (void); +#endif + + +#if (DOSX & (DJGPP|DOS4GW)) + #include + + struct DPMI_regs { + DWORD r_di; + DWORD r_si; + DWORD r_bp; + DWORD reserved; + DWORD r_bx; + DWORD r_dx; + DWORD r_cx; + DWORD r_ax; + WORD r_flags; + WORD r_es, r_ds, r_fs, r_gs; + WORD r_ip, r_cs, r_sp, r_ss; + }; + + /* Data located in a real-mode segment. This becomes far at runtime + */ + typedef struct { /* must match data/code in pkt_rx1.s */ + WORD _rxOutOfs; + WORD _rxInOfs; + DWORD _pktDrop; + BYTE _pktTemp [20]; + TX_ELEMENT _pktTxBuf[1]; + RX_ELEMENT _pktRxBuf[NUM_RX_BUF]; + WORD _dummy[2]; /* screenSeg,newInOffset */ + BYTE _fanChars[4]; + WORD _fanIndex; + BYTE _PktReceiver[15]; /* starts on a paragraph (16byte) */ + } PktRealStub; + #include + + static BYTE real_stub_array [] = { + #include "pkt_stub.inc" /* generated opcode array */ + }; + + #define rxOutOfs offsetof (PktRealStub,_rxOutOfs) + #define rxInOfs offsetof (PktRealStub,_rxInOfs) + #define PktReceiver offsetof (PktRealStub,_PktReceiver [para_skip]) + #define pktDrop offsetof (PktRealStub,_pktDrop) + #define pktTemp offsetof (PktRealStub,_pktTemp) + #define pktTxBuf offsetof (PktRealStub,_pktTxBuf) + #define FIRST_RX_BUF offsetof (PktRealStub,_pktRxBuf [0]) + #define LAST_RX_BUF offsetof (PktRealStub,_pktRxBuf [NUM_RX_BUF-1]) + +#else + extern WORD rxOutOfs; /* offsets into pktRxBuf FIFO queue */ + extern WORD rxInOfs; + extern DWORD pktDrop; /* # packets dropped in PktReceiver() */ + extern BYTE pktRxEnd; /* marks the end of r-mode code/data */ + + extern RX_ELEMENT pktRxBuf [NUM_RX_BUF]; /* PktDrvr Rx buffers */ + extern TX_ELEMENT pktTxBuf; /* PktDrvr Tx buffer */ + extern char pktTemp[20]; /* PktDrvr temp area */ + + #define FIRST_RX_BUF (WORD) &pktRxBuf [0] + #define LAST_RX_BUF (WORD) &pktRxBuf [NUM_RX_BUF-1] +#endif + + +#ifdef __BORLANDC__ /* Use Borland's inline functions */ + #define memcpy __memcpy__ + #define memcmp __memcmp__ + #define memset __memset__ +#endif + + +#if (DOSX & PHARLAP) + extern void PktReceiver (void); /* in pkt_rx0.asm */ + static int RealCopy (ULONG, ULONG, REALPTR*, FARPTR*, USHORT*); + + #undef FP_SEG + #undef FP_OFF + #define FP_OFF(x) ((WORD)(x)) + #define FP_SEG(x) ((WORD)(realBase >> 16)) + #define DOS_ADDR(s,o) (((DWORD)(s) << 16) + (WORD)(o)) + #define r_ax eax + #define r_bx ebx + #define r_dx edx + #define r_cx ecx + #define r_si esi + #define r_di edi + #define r_ds ds + #define r_es es + LOCAL FARPTR protBase; + LOCAL REALPTR realBase; + LOCAL WORD realSeg; /* DOS para-address of allocated area */ + LOCAL SWI_REGS reg; + + static WORD _far *rxOutOfsFp, *rxInOfsFp; + +#elif (DOSX & DJGPP) + static _go32_dpmi_seginfo rm_mem; + static __dpmi_regs reg; + static DWORD realBase; + static int para_skip = 0; + + #define DOS_ADDR(s,o) (((WORD)(s) << 4) + (o)) + #define r_ax x.ax + #define r_bx x.bx + #define r_dx x.dx + #define r_cx x.cx + #define r_si x.si + #define r_di x.di + #define r_ds x.ds + #define r_es x.es + +#elif (DOSX & DOS4GW) + LOCAL struct DPMI_regs reg; + LOCAL WORD rm_base_seg, rm_base_sel; + LOCAL DWORD realBase; + LOCAL int para_skip = 0; + + LOCAL DWORD dpmi_get_real_vector (int intr); + LOCAL WORD dpmi_real_malloc (int size, WORD *selector); + LOCAL void dpmi_real_free (WORD selector); + #define DOS_ADDR(s,o) (((DWORD)(s) << 4) + (WORD)(o)) + +#else /* real-mode Borland etc. */ + static struct { + WORD r_ax, r_bx, r_cx, r_dx, r_bp; + WORD r_si, r_di, r_ds, r_es, r_flags; + } reg; +#endif + +#ifdef __HIGHC__ + #pragma Alias (pktDrop, "_pktDrop") + #pragma Alias (pktRxBuf, "_pktRxBuf") + #pragma Alias (pktTxBuf, "_pktTxBuf") + #pragma Alias (pktTemp, "_pktTemp") + #pragma Alias (rxOutOfs, "_rxOutOfs") + #pragma Alias (rxInOfs, "_rxInOfs") + #pragma Alias (pktRxEnd, "_pktRxEnd") + #pragma Alias (PktReceiver,"_PktReceiver") +#endif + + +PUBLIC PKT_STAT pktStat; /* statistics for packets */ +PUBLIC PKT_INFO pktInfo; /* packet-driver information */ + +PUBLIC PKT_RX_MODE receiveMode = PDRX_DIRECT; +PUBLIC ETHER myAddress = { 0, 0, 0, 0, 0, 0 }; +PUBLIC ETHER ethBroadcast = { 255,255,255,255,255,255 }; + +LOCAL struct { /* internal statistics */ + DWORD tooSmall; /* size < ETH_MIN */ + DWORD tooLarge; /* size > ETH_MAX */ + DWORD badSync; /* count_1 != count_2 */ + DWORD wrongHandle; /* upcall to wrong handle */ + } intStat; + +/***************************************************************************/ + +PUBLIC const char *PktGetErrorStr (int errNum) +{ + static const char *errStr[] = { + "", + "Invalid handle number", + "No interfaces of specified class found", + "No interfaces of specified type found", + "No interfaces of specified number found", + "Bad packet type specified", + "Interface does not support multicast", + "Packet driver cannot terminate", + "Invalid receiver mode specified", + "Insufficient memory space", + "Type previously accessed, and not released", + "Command out of range, or not implemented", + "Cannot send packet (usually hardware error)", + "Cannot change hardware address ( > 1 handle open)", + "Hardware address has bad length or format", + "Cannot reset interface (more than 1 handle open)", + "Bad Check-sum", + "Bad size", + "Bad sync" , + "Source hit" + }; + + if (errNum < 0 || errNum >= DIM(errStr)) + return ("Unknown driver error."); + return (errStr [errNum]); +} + +/**************************************************************************/ + +PUBLIC const char *PktGetClassName (WORD class) +{ + switch (class) + { + case PD_ETHER: + return ("DIX-Ether"); + case PD_PRONET10: + return ("ProNET-10"); + case PD_IEEE8025: + return ("IEEE 802.5"); + case PD_OMNINET: + return ("OmniNet"); + case PD_APPLETALK: + return ("AppleTalk"); + case PD_SLIP: + return ("SLIP"); + case PD_STARTLAN: + return ("StartLAN"); + case PD_ARCNET: + return ("ArcNet"); + case PD_AX25: + return ("AX.25"); + case PD_KISS: + return ("KISS"); + case PD_IEEE8023_2: + return ("IEEE 802.3 w/802.2 hdr"); + case PD_FDDI8022: + return ("FDDI w/802.2 hdr"); + case PD_X25: + return ("X.25"); + case PD_LANstar: + return ("LANstar"); + case PD_PPP: + return ("PPP"); + default: + return ("unknown"); + } +} + +/**************************************************************************/ + +PUBLIC char const *PktRXmodeStr (PKT_RX_MODE mode) +{ + static const char *modeStr [] = { + "Receiver turned off", + "Receive only directly addressed packets", + "Receive direct & broadcast packets", + "Receive direct,broadcast and limited multicast packets", + "Receive direct,broadcast and all multicast packets", + "Receive all packets (promiscuous mode)" + }; + + if (mode > DIM(modeStr)) + return ("??"); + return (modeStr [mode-1]); +} + +/**************************************************************************/ + +LOCAL __inline BOOL PktInterrupt (void) +{ + BOOL okay; + +#if (DOSX & PHARLAP) + _dx_real_int ((UINT)pktInfo.intr, ®); + okay = ((reg.flags & 1) == 0); /* OK if carry clear */ + +#elif (DOSX & DJGPP) + __dpmi_int ((int)pktInfo.intr, ®); + okay = ((reg.x.flags & 1) == 0); + +#elif (DOSX & DOS4GW) + union REGS r; + struct SREGS s; + + memset (&r, 0, sizeof(r)); + segread (&s); + r.w.ax = 0x300; + r.x.ebx = pktInfo.intr; + r.w.cx = 0; + s.es = FP_SEG (®); + r.x.edi = FP_OFF (®); + reg.r_flags = 0; + reg.r_ss = reg.r_sp = 0; /* DPMI host provides stack */ + + int386x (0x31, &r, &r, &s); + okay = (!r.w.cflag); + +#else + reg.r_flags = 0; + intr (pktInfo.intr, (struct REGPACK*)®); + okay = ((reg.r_flags & 1) == 0); +#endif + + if (okay) + pktInfo.error = NULL; + else pktInfo.error = PktGetErrorStr (reg.r_dx >> 8); + return (okay); +} + +/**************************************************************************/ + +/* + * Search for packet driver at interrupt 60h through 80h. If ASCIIZ + * string "PKT DRVR" found at offset 3 in the interrupt handler, return + * interrupt number, else return zero in pktInfo.intr + */ +PUBLIC BOOL PktSearchDriver (void) +{ + BYTE intr = 0x20; + BOOL found = FALSE; + + while (!found && intr < 0xFF) + { + static char str[12]; /* 3 + strlen("PKT DRVR") */ + static char pktStr[9] = "PKT DRVR"; /* ASCIIZ string at ofs 3 */ + DWORD rp; /* in interrupt routine */ + +#if (DOSX & PHARLAP) + _dx_rmiv_get (intr, &rp); + ReadRealMem (&str, (REALPTR)rp, sizeof(str)); + +#elif (DOSX & DJGPP) + __dpmi_raddr realAdr; + __dpmi_get_real_mode_interrupt_vector (intr, &realAdr); + rp = (realAdr.segment << 4) + realAdr.offset16; + dosmemget (rp, sizeof(str), &str); + +#elif (DOSX & DOS4GW) + rp = dpmi_get_real_vector (intr); + memcpy (&str, (void*)rp, sizeof(str)); + +#else + _fmemcpy (&str, getvect(intr), sizeof(str)); +#endif + + found = memcmp (&str[3],&pktStr,sizeof(pktStr)) == 0; + intr++; + } + pktInfo.intr = (found ? intr-1 : 0); + return (found); +} + + +/**************************************************************************/ + +static BOOL PktSetAccess (void) +{ + reg.r_ax = 0x0200 + pktInfo.class; + reg.r_bx = 0xFFFF; + reg.r_dx = 0; + reg.r_cx = 0; + +#if (DOSX & PHARLAP) + reg.ds = 0; + reg.esi = 0; + reg.es = RP_SEG (realBase); + reg.edi = (WORD) &PktReceiver; + +#elif (DOSX & DJGPP) + reg.x.ds = 0; + reg.x.si = 0; + reg.x.es = rm_mem.rm_segment; + reg.x.di = PktReceiver; + +#elif (DOSX & DOS4GW) + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = rm_base_seg; + reg.r_di = PktReceiver; + +#else + reg.r_ds = 0; + reg.r_si = 0; + reg.r_es = FP_SEG (&PktReceiver); + reg.r_di = FP_OFF (&PktReceiver); +#endif + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.handle = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktReleaseHandle (WORD handle) +{ + reg.r_ax = 0x0300; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTransmit (const void *eth, int len) +{ + if (len > ETH_MTU) + return (FALSE); + + reg.r_ax = 0x0400; /* Function 4, send pkt */ + reg.r_cx = len; /* total size of frame */ + +#if (DOSX & DJGPP) + dosmemput (eth, len, realBase+pktTxBuf); + reg.x.ds = rm_mem.rm_segment; /* DOS data segment and */ + reg.x.si = pktTxBuf; /* DOS offset to buffer */ + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTxBuf), eth, len); + reg.r_ds = rm_base_seg; + reg.r_si = pktTxBuf; + +#elif (DOSX & PHARLAP) + memcpy (&pktTxBuf, eth, len); + reg.r_ds = FP_SEG (&pktTxBuf); + reg.r_si = FP_OFF (&pktTxBuf); + +#else + reg.r_ds = FP_SEG (eth); + reg.r_si = FP_OFF (eth); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +#if (DOSX & (DJGPP|DOS4GW)) +LOCAL __inline BOOL CheckElement (RX_ELEMENT *rx) +#else +LOCAL __inline BOOL CheckElement (RX_ELEMENT _far *rx) +#endif +{ + WORD count_1, count_2; + + /* + * We got an upcall to the same RMCB with wrong handle. + * This can happen if we failed to release handle at program exit + */ + if (rx->handle != pktInfo.handle) + { + pktInfo.error = "Wrong handle"; + intStat.wrongHandle++; + PktReleaseHandle (rx->handle); + return (FALSE); + } + count_1 = rx->firstCount; + count_2 = rx->secondCount; + + if (count_1 != count_2) + { + pktInfo.error = "Bad sync"; + intStat.badSync++; + return (FALSE); + } + if (count_1 > ETH_MAX) + { + pktInfo.error = "Large esize"; + intStat.tooLarge++; + return (FALSE); + } +#if 0 + if (count_1 < ETH_MIN) + { + pktInfo.error = "Small esize"; + intStat.tooSmall++; + return (FALSE); + } +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktTerminHandle (WORD handle) +{ + reg.r_ax = 0x0500; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetInterface (WORD handle) +{ + reg.r_ax = 0x0700; + reg.r_bx = handle; + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetReceiverMode (PKT_RX_MODE mode) +{ + if (pktInfo.class == PD_SLIP || pktInfo.class == PD_PPP) + return (TRUE); + + reg.r_ax = 0x1400; + reg.r_bx = pktInfo.handle; + reg.r_cx = (WORD)mode; + + if (!PktInterrupt()) + return (FALSE); + + receiveMode = mode; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetReceiverMode (PKT_RX_MODE *mode) +{ + reg.r_ax = 0x1500; + reg.r_bx = pktInfo.handle; + + if (!PktInterrupt()) + return (FALSE); + + *mode = reg.r_ax; + return (TRUE); +} + +/**************************************************************************/ + +static PKT_STAT initialStat; /* statistics at startup */ +static BOOL resetStat = FALSE; /* statistics reset ? */ + +PUBLIC BOOL PktGetStatistics (WORD handle) +{ + reg.r_ax = 0x1800; + reg.r_bx = handle; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktStat, DOS_ADDR(reg.ds,reg.esi), sizeof(pktStat)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktStat), &pktStat); + +#elif (DOSX & DOS4GW) + memcpy (&pktStat, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktStat)); + +#else + _fmemcpy (&pktStat, MK_FP(reg.r_ds,reg.r_si), sizeof(pktStat)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSessStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + if (resetStat) + { + pktStat.inPackets -= initialStat.inPackets; + pktStat.outPackets -= initialStat.outPackets; + pktStat.inBytes -= initialStat.inBytes; + pktStat.outBytes -= initialStat.outBytes; + pktStat.inErrors -= initialStat.inErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.outErrors -= initialStat.outErrors; + pktStat.lost -= initialStat.lost; + } + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktResetStatistics (WORD handle) +{ + if (!PktGetStatistics(pktInfo.handle)) + return (FALSE); + + memcpy (&initialStat, &pktStat, sizeof(initialStat)); + resetStat = TRUE; + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetAddress (ETHER *addr) +{ + reg.r_ax = 0x0600; + reg.r_bx = pktInfo.handle; + reg.r_cx = sizeof (*addr); + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; + reg.x.di = pktTemp; +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); /* ES:DI = address for result */ +#endif + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (addr, realBase + (WORD)&pktTemp, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemget (realBase+pktTemp, sizeof(*addr), addr); + +#elif (DOSX & DOS4GW) + memcpy (addr, (void*)(realBase+pktTemp), sizeof(*addr)); + +#else + memcpy ((void*)addr, &pktTemp, sizeof(*addr)); +#endif + + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktSetAddress (const ETHER *addr) +{ + /* copy addr to real-mode scrath area */ + +#if (DOSX & PHARLAP) + WriteRealMem (realBase + (WORD)&pktTemp, (void*)addr, sizeof(*addr)); + +#elif (DOSX & DJGPP) + dosmemput (addr, sizeof(*addr), realBase+pktTemp); + +#elif (DOSX & DOS4GW) + memcpy ((void*)(realBase+pktTemp), addr, sizeof(*addr)); + +#else + memcpy (&pktTemp, (void*)addr, sizeof(*addr)); +#endif + + reg.r_ax = 0x1900; + reg.r_cx = sizeof (*addr); /* address length */ + +#if (DOSX & DJGPP) + reg.x.es = rm_mem.rm_segment; /* DOS offset to param */ + reg.x.di = pktTemp; /* DOS segment to param */ +#elif (DOSX & DOS4GW) + reg.r_es = rm_base_seg; + reg.r_di = pktTemp; +#else + reg.r_es = FP_SEG (&pktTemp); + reg.r_di = FP_OFF (&pktTemp); +#endif + + return PktInterrupt(); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverInfo (void) +{ + pktInfo.majVer = 0; + pktInfo.minVer = 0; + memset (&pktInfo.name, 0, sizeof(pktInfo.name)); + reg.r_ax = 0x01FF; + reg.r_bx = 0; + + if (!PktInterrupt()) + return (FALSE); + + pktInfo.number = reg.r_cx & 0xFF; + pktInfo.class = reg.r_cx >> 8; +#if 0 + pktInfo.minVer = reg.r_bx % 10; + pktInfo.majVer = reg.r_bx / 10; +#else + pktInfo.majVer = reg.r_bx; // !! +#endif + pktInfo.funcs = reg.r_ax & 0xFF; + pktInfo.type = reg.r_dx & 0xFF; + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.name, DOS_ADDR(reg.ds,reg.esi), sizeof(pktInfo.name)); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.ds,reg.x.si), sizeof(pktInfo.name), &pktInfo.name); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.name, (void*)DOS_ADDR(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); + +#else + _fmemcpy (&pktInfo.name, MK_FP(reg.r_ds,reg.r_si), sizeof(pktInfo.name)); +#endif + return (TRUE); +} + +/**************************************************************************/ + +PUBLIC BOOL PktGetDriverParam (void) +{ + reg.r_ax = 0x0A00; + + if (!PktInterrupt()) + return (FALSE); + +#if (DOSX & PHARLAP) + ReadRealMem (&pktInfo.majVer, DOS_ADDR(reg.es,reg.edi), PKT_PARAM_SIZE); + +#elif (DOSX & DJGPP) + dosmemget (DOS_ADDR(reg.x.es,reg.x.di), PKT_PARAM_SIZE, &pktInfo.majVer); + +#elif (DOSX & DOS4GW) + memcpy (&pktInfo.majVer, (void*)DOS_ADDR(reg.r_es,reg.r_di), PKT_PARAM_SIZE); + +#else + _fmemcpy (&pktInfo.majVer, MK_FP(reg.r_es,reg.r_di), PKT_PARAM_SIZE); +#endif + return (TRUE); +} + +/**************************************************************************/ + +#if (DOSX & PHARLAP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (outOfs != inOfs) + { + RX_ELEMENT _far *head = (RX_ELEMENT _far*)(protBase+outOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + outOfs += sizeof (RX_ELEMENT); + if (outOfs > LAST_RX_BUF) + outOfs = FIRST_RX_BUF; + *rxOutOfsFp = outOfs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + *rxOutOfsFp = busy ? (*rxInOfsFp + sizeof(RX_ELEMENT)) : *rxInOfsFp; + if (*rxOutOfsFp > LAST_RX_BUF) + *rxOutOfsFp = FIRST_RX_BUF; + *(DWORD _far*)(protBase + (WORD)&pktDrop) = 0; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = *rxInOfsFp; + WORD outOfs = *rxOutOfsFp; + + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (*(DWORD _far*)(protBase + (WORD)&pktDrop)); + } + +#elif (DOSX & DJGPP) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = _farpeekw (_dos_ds, realBase+rxOutOfs); + + if (ofs != _farpeekw (_dos_ds, realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = _farpeekw (_dos_ds, realBase+ofs); + head.secondCount = _farpeekw (_dos_ds, realBase+ofs+2); + head.handle = _farpeekw (_dos_ds, realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + dosmemget (realBase+ofs+6, len, buf); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + disable(); + ofs = _farpeekw (_dos_ds, realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + _farpokew (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + else _farpokew (_dos_ds, realBase+rxOutOfs, ofs); + _farpokel (_dos_ds, realBase+pktDrop, 0UL); + enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + disable(); + inOfs = _farpeekw (_dos_ds, realBase+rxInOfs); + outOfs = _farpeekw (_dos_ds, realBase+rxOutOfs); + enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return _farpeekl (_dos_ds, realBase+pktDrop); + } + +#elif (DOSX & DOS4GW) + PUBLIC int PktReceive (BYTE *buf, int max) + { + WORD ofs = *(WORD*) (realBase+rxOutOfs); + + if (ofs != *(WORD*) (realBase+rxInOfs)) + { + RX_ELEMENT head; + int size, len = max; + + head.firstCount = *(WORD*) (realBase+ofs); + head.secondCount = *(WORD*) (realBase+ofs+2); + head.handle = *(WORD*) (realBase+ofs+4); + + if (CheckElement(&head)) + { + size = min (head.firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + memcpy (buf, (const void*)(realBase+ofs+6), len); + } + else + size = -1; + + ofs += sizeof (RX_ELEMENT); + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + WORD ofs; + + _disable(); + ofs = *(WORD*) (realBase+rxInOfs); + if (busy) + ofs += sizeof (RX_ELEMENT); + + if (ofs > LAST_RX_BUF) + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + else *(WORD*) (realBase+rxOutOfs) = ofs; + *(DWORD*) (realBase+pktDrop) = 0UL; + _enable(); + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs, outOfs; + + _disable(); + inOfs = *(WORD*) (realBase+rxInOfs); + outOfs = *(WORD*) (realBase+rxOutOfs); + _enable(); + if (inOfs >= outOfs) + return (inOfs - outOfs) / sizeof(RX_ELEMENT); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return *(DWORD*) (realBase+pktDrop); + } + +#else /* real-mode small/large model */ + + PUBLIC int PktReceive (BYTE *buf, int max) + { + if (rxOutOfs != rxInOfs) + { + RX_ELEMENT far *head = (RX_ELEMENT far*) MK_FP (_DS,rxOutOfs); + int size, len = max; + + if (CheckElement(head)) + { + size = min (head->firstCount, sizeof(RX_ELEMENT)); + len = min (size, max); + _fmemcpy (buf, &head->destin, len); + } + else + size = -1; + + rxOutOfs += sizeof (RX_ELEMENT); + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + return (size); + } + return (0); + } + + PUBLIC void PktQueueBusy (BOOL busy) + { + rxOutOfs = busy ? (rxInOfs + sizeof(RX_ELEMENT)) : rxInOfs; + if (rxOutOfs > LAST_RX_BUF) + rxOutOfs = FIRST_RX_BUF; + pktDrop = 0L; + } + + PUBLIC WORD PktBuffersUsed (void) + { + WORD inOfs = rxInOfs; + WORD outOfs = rxOutOfs; + + if (inOfs >= outOfs) + return ((inOfs - outOfs) / sizeof(RX_ELEMENT)); + return (NUM_RX_BUF - (outOfs - inOfs) / sizeof(RX_ELEMENT)); + } + + PUBLIC DWORD PktRxDropped (void) + { + return (pktDrop); + } +#endif + +/**************************************************************************/ + +LOCAL __inline void PktFreeMem (void) +{ +#if (DOSX & PHARLAP) + if (realSeg) + { + _dx_real_free (realSeg); + realSeg = 0; + } +#elif (DOSX & DJGPP) + if (rm_mem.rm_segment) + { + unsigned ofs; /* clear the DOS-mem to prevent further upcalls */ + + for (ofs = 0; ofs < 16 * rm_mem.size / 4; ofs += 4) + _farpokel (_dos_ds, realBase + ofs, 0); + _go32_dpmi_free_dos_memory (&rm_mem); + rm_mem.rm_segment = 0; + } +#elif (DOSX & DOS4GW) + if (rm_base_sel) + { + dpmi_real_free (rm_base_sel); + rm_base_sel = 0; + } +#endif +} + +/**************************************************************************/ + +PUBLIC BOOL PktExitDriver (void) +{ + if (pktInfo.handle) + { + if (!PktSetReceiverMode(PDRX_BROADCAST)) + PUTS ("Error restoring receiver mode."); + + if (!PktReleaseHandle(pktInfo.handle)) + PUTS ("Error releasing PKT-DRVR handle."); + + PktFreeMem(); + pktInfo.handle = 0; + } + + if (pcap_pkt_debug >= 1) + printf ("Internal stats: too-small %lu, too-large %lu, bad-sync %lu, " + "wrong-handle %lu\n", + intStat.tooSmall, intStat.tooLarge, + intStat.badSync, intStat.wrongHandle); + return (TRUE); +} + +#if (DOSX & (DJGPP|DOS4GW)) +static void dump_pkt_stub (void) +{ + int i; + + fprintf (stderr, "PktReceiver %lu, pkt_stub[PktReceiver] =\n", + PktReceiver); + for (i = 0; i < 15; i++) + fprintf (stderr, "%02X, ", real_stub_array[i+PktReceiver]); + fputs ("\n", stderr); +} +#endif + +/* + * Front end initialization routine + */ +PUBLIC BOOL PktInitDriver (PKT_RX_MODE mode) +{ + PKT_RX_MODE rxMode; + BOOL writeInfo = (pcap_pkt_debug >= 3); + + pktInfo.quiet = (pcap_pkt_debug < 3); + +#if (DOSX & PHARLAP) && defined(__HIGHC__) + if (_mwenv != 2) + { + fprintf (stderr, "Only Pharlap DOS extender supported.\n"); + return (FALSE); + } +#endif + +#if (DOSX & PHARLAP) && defined(__WATCOMC__) + if (_Extender != 1) + { + fprintf (stderr, "Only DOS4GW style extenders supported.\n"); + return (FALSE); + } +#endif + + if (!PktSearchDriver()) + { + PUTS ("Packet driver not found."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetDriverInfo()) + { + PUTS ("Error getting pkt-drvr information."); + PktFreeMem(); + return (FALSE); + } + +#if (DOSX & PHARLAP) + if (RealCopy((ULONG)&rxOutOfs, (ULONG)&pktRxEnd, + &realBase, &protBase, (USHORT*)&realSeg)) + { + rxOutOfsFp = (WORD _far *) (protBase + (WORD) &rxOutOfs); + rxInOfsFp = (WORD _far *) (protBase + (WORD) &rxInOfs); + *rxOutOfsFp = FIRST_RX_BUF; + *rxInOfsFp = FIRST_RX_BUF; + } + else + { + PUTS ("Cannot allocate real-mode stub."); + return (FALSE); + } + +#elif (DOSX & (DJGPP|DOS4GW)) + if (sizeof(real_stub_array) > 0xFFFF) + { + fprintf (stderr, "`real_stub_array[]' too big.\n"); + return (FALSE); + } +#if (DOSX & DJGPP) + rm_mem.size = (sizeof(real_stub_array) + 15) / 16; + + if (_go32_dpmi_allocate_dos_memory(&rm_mem) || rm_mem.rm_offset != 0) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_mem.rm_segment << 4); + dosmemput (&real_stub_array, sizeof(real_stub_array), realBase); + _farpokel (_dos_ds, realBase+rxOutOfs, FIRST_RX_BUF); + _farpokel (_dos_ds, realBase+rxInOfs, FIRST_RX_BUF); + +#elif (DOSX & DOS4GW) + rm_base_seg = dpmi_real_malloc (sizeof(real_stub_array), &rm_base_sel); + if (!rm_base_seg) + { + PUTS ("real-mode init failed."); + return (FALSE); + } + realBase = (rm_base_seg << 4); + memcpy ((void*)realBase, &real_stub_array, sizeof(real_stub_array)); + *(WORD*) (realBase+rxOutOfs) = FIRST_RX_BUF; + *(WORD*) (realBase+rxInOfs) = FIRST_RX_BUF; + +#endif + { + int pushf = PktReceiver; + + while (real_stub_array[pushf++] != 0x9C && /* pushf */ + real_stub_array[pushf] != 0xFA) /* cli */ + { + if (++para_skip > 16) + { + fprintf (stderr, "Something wrong with `pkt_stub.inc'.\n"); + para_skip = 0; + dump_pkt_stub(); + return (FALSE); + } + } + if (*(WORD*)(real_stub_array + offsetof(PktRealStub,_dummy)) != 0xB800) + { + fprintf (stderr, "`real_stub_array[]' is misaligned.\n"); + return (FALSE); + } + } + + if (pcap_pkt_debug > 2) + dump_pkt_stub(); + +#else + rxOutOfs = FIRST_RX_BUF; + rxInOfs = FIRST_RX_BUF; +#endif + + if (!PktSetAccess()) + { + PUTS ("Error setting pkt-drvr access."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetAddress(&myAddress)) + { + PUTS ("Error fetching adapter address."); + PktFreeMem(); + return (FALSE); + } + + if (!PktSetReceiverMode(mode)) + { + PUTS ("Error setting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (!PktGetReceiverMode(&rxMode)) + { + PUTS ("Error getting receiver mode."); + PktFreeMem(); + return (FALSE); + } + + if (writeInfo) + printf ("Pkt-driver information:\n" + " Version : %d.%d\n" + " Name : %.15s\n" + " Class : %u (%s)\n" + " Type : %u\n" + " Number : %u\n" + " Funcs : %u\n" + " Intr : %Xh\n" + " Handle : %u\n" + " Extended : %s\n" + " Hi-perf : %s\n" + " RX mode : %s\n" + " Eth-addr : %02X:%02X:%02X:%02X:%02X:%02X\n", + + pktInfo.majVer, pktInfo.minVer, pktInfo.name, + pktInfo.class, PktGetClassName(pktInfo.class), + pktInfo.type, pktInfo.number, + pktInfo.funcs, pktInfo.intr, pktInfo.handle, + pktInfo.funcs == 2 || pktInfo.funcs == 6 ? "Yes" : "No", + pktInfo.funcs == 5 || pktInfo.funcs == 6 ? "Yes" : "No", + PktRXmodeStr(rxMode), + myAddress[0], myAddress[1], myAddress[2], + myAddress[3], myAddress[4], myAddress[5]); + +#if defined(DEBUG) && (DOSX & PHARLAP) + if (writeInfo) + { + DWORD rAdr = realBase + (WORD)&PktReceiver; + unsigned sel, ofs; + + printf ("\nReceiver at %04X:%04X\n", RP_SEG(rAdr), RP_OFF(rAdr)); + printf ("Realbase = %04X:%04X\n", RP_SEG(realBase),RP_OFF(realBase)); + + sel = _FP_SEG (protBase); + ofs = _FP_OFF (protBase); + printf ("Protbase = %04X:%08X\n", sel,ofs); + printf ("RealSeg = %04X\n", realSeg); + + sel = _FP_SEG (rxOutOfsFp); + ofs = _FP_OFF (rxOutOfsFp); + printf ("rxOutOfsFp = %04X:%08X\n", sel,ofs); + + sel = _FP_SEG (rxInOfsFp); + ofs = _FP_OFF (rxInOfsFp); + printf ("rxInOfsFp = %04X:%08X\n", sel,ofs); + + printf ("Ready: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + + PktQueueBusy (TRUE); + printf ("Busy: *rxOutOfsFp = %04X *rxInOfsFp = %04X\n", + *rxOutOfsFp, *rxInOfsFp); + } +#endif + + memset (&pktStat, 0, sizeof(pktStat)); /* clear statistics */ + PktQueueBusy (TRUE); + return (TRUE); +} + + +/* + * DPMI functions only for Watcom + DOS4GW extenders + */ +#if (DOSX & DOS4GW) +LOCAL DWORD dpmi_get_real_vector (int intr) +{ + union REGS r; + + r.x.eax = 0x200; + r.x.ebx = (DWORD) intr; + int386 (0x31, &r, &r); + return ((r.w.cx << 4) + r.w.dx); +} + +LOCAL WORD dpmi_real_malloc (int size, WORD *selector) +{ + union REGS r; + + r.x.eax = 0x0100; /* DPMI allocate DOS memory */ + r.x.ebx = (size + 15) / 16; /* Number of paragraphs requested */ + int386 (0x31, &r, &r); + if (r.w.cflag & 1) + return (0); + + *selector = r.w.dx; + return (r.w.ax); /* Return segment address */ +} + +LOCAL void dpmi_real_free (WORD selector) +{ + union REGS r; + + r.x.eax = 0x101; /* DPMI free DOS memory */ + r.x.ebx = selector; /* Selector to free */ + int386 (0x31, &r, &r); +} +#endif + + +#if defined(DOSX) && (DOSX & PHARLAP) +/* + * Description: + * This routine allocates conventional memory for the specified block + * of code (which must be within the first 64K of the protected mode + * program segment) and copies the code to it. + * + * The caller should free up the conventional memory block when it + * is done with the conventional memory. + * + * NOTE THIS ROUTINE REQUIRES 386|DOS-EXTENDER 3.0 OR LATER. + * + * Calling arguments: + * start_offs start of real mode code in program segment + * end_offs 1 byte past end of real mode code in program segment + * real_basep returned; real mode ptr to use as a base for the + * real mode code (eg, to get the real mode FAR + * addr of a function foo(), take + * real_basep + (ULONG) foo). + * This pointer is constructed such that + * offsets within the real mode segment are + * the same as the link-time offsets in the + * protected mode program segment + * prot_basep returned; prot mode ptr to use as a base for getting + * to the conventional memory, also constructed + * so that adding the prot mode offset of a + * function or variable to the base gets you a + * ptr to the function or variable in the + * conventional memory block. + * rmem_adrp returned; real mode para addr of allocated + * conventional memory block, to be used to free + * up the conventional memory when done. DO NOT + * USE THIS TO CONSTRUCT A REAL MODE PTR, USE + * REAL_BASEP INSTEAD SO THAT OFFSETS WORK OUT + * CORRECTLY. + * + * Returned values: + * 0 if error + * 1 if success + */ +int RealCopy (ULONG start_offs, + ULONG end_offs, + REALPTR *real_basep, + FARPTR *prot_basep, + USHORT *rmem_adrp) +{ + ULONG rm_base; /* base real mode para addr for accessing */ + /* allocated conventional memory */ + UCHAR *source; /* source pointer for copy */ + FARPTR destin; /* destination pointer for copy */ + ULONG len; /* number of bytes to copy */ + ULONG temp; + USHORT stemp; + + /* First check for valid inputs + */ + if (start_offs >= end_offs || end_offs > 0x10000) + return (FALSE); + + /* Round start_offs down to a paragraph (16-byte) boundary so we can set up + * the real mode pointer easily. Round up end_offs to make sure we allocate + * enough paragraphs + */ + start_offs &= ~15; + end_offs = (15 + (end_offs << 4)) >> 4; + + /* Allocate the conventional memory for our real mode code. Remember to + * round byte count UP to 16-byte paragraph size. We alloc it + * above the DOS data buffer so both the DOS data buffer and the appl + * conventional mem block can still be resized. + * + * First just try to alloc it; if we can't get it, shrink the appl mem + * block down to the minimum, try to alloc the memory again, then grow the + * appl mem block back to the maximum. (Don't try to shrink the DOS data + * buffer to free conventional memory; it wouldn't be good for this routine + * to have the possible side effect of making file I/O run slower.) + */ + len = ((end_offs - start_offs) + 15) >> 4; + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + { + if (_dx_cmem_usage(0, 0, &temp, &temp) != _DOSE_NONE) + return (FALSE); + + if (_dx_real_above(len, rmem_adrp, &stemp) != _DOSE_NONE) + *rmem_adrp = 0; + + if (_dx_cmem_usage(0, 1, &temp, &temp) != _DOSE_NONE) + { + if (*rmem_adrp != 0) + _dx_real_free (*rmem_adrp); + return (FALSE); + } + + if (*rmem_adrp == 0) + return (FALSE); + } + + /* Construct real mode & protected mode pointers to access the allocated + * memory. Note we know start_offs is aligned on a paragraph (16-byte) + * boundary, because we rounded it down. + * + * We make the offsets come out rights by backing off the real mode selector + * by start_offs. + */ + rm_base = ((ULONG) *rmem_adrp) - (start_offs >> 4); + RP_SET (*real_basep, 0, rm_base); + FP_SET (*prot_basep, rm_base << 4, SS_DOSMEM); + + /* Copy the real mode code/data to the allocated memory + */ + source = (UCHAR *) start_offs; + destin = *prot_basep; + FP_SET (destin, FP_OFF(*prot_basep) + start_offs, FP_SEL(*prot_basep)); + len = end_offs - start_offs; + WriteFarMem (destin, source, len); + + return (TRUE); +} +#endif /* DOSX && (DOSX & PHARLAP) */ diff --git a/src/libpcap-1.10.5/msdos/pktdrvr.h b/src/libpcap-1.10.5/msdos/pktdrvr.h new file mode 100644 index 0000000000..82a1026536 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/pktdrvr.h @@ -0,0 +1,153 @@ +#ifndef __PKTDRVR_H +#define __PKTDRVR_H + +#define PUBLIC +#define LOCAL static + +#define RX_BUF_SIZE ETH_MTU /* buffer size variables. NB !! */ +#define TX_BUF_SIZE ETH_MTU /* must be same as in pkt_rx*.* */ + +#ifdef __HIGHC__ +#pragma Off(Align_members) +#else +#pragma pack(1) +#endif + +typedef enum { /* Packet-driver classes */ + PD_ETHER = 1, + PD_PRONET10 = 2, + PD_IEEE8025 = 3, + PD_OMNINET = 4, + PD_APPLETALK = 5, + PD_SLIP = 6, + PD_STARTLAN = 7, + PD_ARCNET = 8, + PD_AX25 = 9, + PD_KISS = 10, + PD_IEEE8023_2 = 11, + PD_FDDI8022 = 12, + PD_X25 = 13, + PD_LANstar = 14, + PD_PPP = 18 + } PKT_CLASS; + +typedef enum { /* Packet-driver receive modes */ + PDRX_OFF = 1, /* turn off receiver */ + PDRX_DIRECT, /* receive only to this interface */ + PDRX_BROADCAST, /* DIRECT + broadcast packets */ + PDRX_MULTICAST1, /* BROADCAST + limited multicast */ + PDRX_MULTICAST2, /* BROADCAST + all multicast */ + PDRX_ALL_PACKETS, /* receive all packets on network */ + } PKT_RX_MODE; + +typedef struct { + char type[8]; + char len; + } PKT_FRAME; + + +typedef struct { + BYTE class; /* = 1 for DEC/Intel/Xerox Ethernet */ + BYTE number; /* = 0 for single LAN adapter */ + WORD type; /* = 13 for 3C523 */ + BYTE funcs; /* Basic/Extended/HiPerf functions */ + WORD intr; /* user interrupt vector number */ + WORD handle; /* Handle associated with session */ + BYTE name [15]; /* Name of adapter interface,ie.3C523*/ + BOOL quiet; /* (don't) print errors to stdout */ + const char *error; /* address of error string */ + BYTE majVer; /* Major driver implementation ver. */ + BYTE minVer; /* Minor driver implementation ver. */ + BYTE dummyLen; /* length of following data */ + WORD MAClength; /* HiPerformance data, N/A */ + WORD MTU; /* HiPerformance data, N/A */ + WORD multicast; /* HiPerformance data, N/A */ + WORD rcvrBuffers; /* valid for */ + WORD UMTbufs; /* High Performance drivers only */ + WORD postEOIintr; /* Usage ?? */ + } PKT_INFO; + +#define PKT_PARAM_SIZE 14 /* members majVer - postEOIintr */ + + +typedef struct { + DWORD inPackets; /* # of packets received */ + DWORD outPackets; /* # of packets transmitted */ + DWORD inBytes; /* # of bytes received */ + DWORD outBytes; /* # of bytes transmitted */ + DWORD inErrors; /* # of reception errors */ + DWORD outErrors; /* # of transmission errors */ + DWORD lost; /* # of packets lost (RX) */ + } PKT_STAT; + + +typedef struct { + ETHER destin; + ETHER source; + WORD proto; + BYTE data [TX_BUF_SIZE]; + } TX_ELEMENT; + +typedef struct { + WORD firstCount; /* # of bytes on 1st */ + WORD secondCount; /* and 2nd upcall */ + WORD handle; /* instance that upcalled */ + ETHER destin; /* E-net destination address */ + ETHER source; /* E-net source address */ + WORD proto; /* protocol number */ + BYTE data [RX_BUF_SIZE]; + } RX_ELEMENT; + + +#ifdef __HIGHC__ +#pragma pop(Align_members) +#else +#pragma pack() +#endif + + +/* + * Prototypes for publics + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern PKT_STAT pktStat; /* statistics for packets */ +extern PKT_INFO pktInfo; /* packet-driver information */ + +extern PKT_RX_MODE receiveMode; +extern ETHER myAddress, ethBroadcast; + +extern BOOL PktInitDriver (PKT_RX_MODE mode); +extern BOOL PktExitDriver (void); + +extern const char *PktGetErrorStr (int errNum); +extern const char *PktGetClassName (WORD class); +extern const char *PktRXmodeStr (PKT_RX_MODE mode); +extern BOOL PktSearchDriver (void); +extern int PktReceive (BYTE *buf, int max); +extern BOOL PktTransmit (const void *eth, int len); +extern DWORD PktRxDropped (void); +extern BOOL PktReleaseHandle (WORD handle); +extern BOOL PktTerminHandle (WORD handle); +extern BOOL PktResetInterface (WORD handle); +extern BOOL PktSetReceiverMode(PKT_RX_MODE mode); +extern BOOL PktGetReceiverMode(PKT_RX_MODE *mode); +extern BOOL PktGetStatistics (WORD handle); +extern BOOL PktSessStatistics (WORD handle); +extern BOOL PktResetStatistics(WORD handle); +extern BOOL PktGetAddress (ETHER *addr); +extern BOOL PktSetAddress (const ETHER *addr); +extern BOOL PktGetDriverInfo (void); +extern BOOL PktGetDriverParam (void); +extern void PktQueueBusy (BOOL busy); +extern WORD PktBuffersUsed (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __PKTDRVR_H */ + diff --git a/src/libpcap-1.10.5/msdos/readme.dos b/src/libpcap-1.10.5/msdos/readme.dos new file mode 100644 index 0000000000..d2bb211235 --- /dev/null +++ b/src/libpcap-1.10.5/msdos/readme.dos @@ -0,0 +1,166 @@ +libpcap for DOS +--------------- + +This file contains some notes on building and using libpcap for MS-DOS. +Look in `README' and `pcap.man' for usage and details. These targets are +supported: + + - Borland C 4.0+ small or large model. + - Metaware HighC 3.1+ with PharLap DOS-extender + - GNU C 2.7+ with djgpp 2.01+ DOS extender + - Watcom C 11.x with DOS4GW extender + +Note: the files in the libpcap.zip contains short truncated filenames. + So for djgpp to work with these, disable the use of long file names by + setting "LFN=n" in the environment. On the other hand, if you get libpcap + from GitHub or the official libpcap.tar.gz, some filenames are beyond 8+3. + In this case set "LFN=y". + +Files specific to DOS are pcap-dos.[ch] and the assembly and C files in +the MSDOS sub-directory. Remember to built the libpcap library from the top +install directory. And not from the MSDOS sub-directory. + +Note for djgpp users: + If you got the libpcap from the official site www.tcpdump, then that + distribution does NOT contain any sources for building 32-bit drivers. + Instead get the full version at + https://www.watt-32.net/pcap/libpcap.zip + + and set "USE_32BIT_DRIVERS = 1" in msdos\common.dj. + + + +Requirements +------------ + +DOS-libpcap currently only works reliably with a real-mode Ethernet packet- +driver. This driver must be installed prior to using any program (e.g. +tcpdump) compiled with libpcap. Work is underway to implement protected- +mode drivers for 32-bit targets (djgpp only). The 3Com 3c509 driver is +working almost perfectly. Due to lack of LAN-cards, I've not had the +opportunity to test other drivers. These 32-bit drivers are modified +Linux drivers. + + +Required packages +----------------- + +The following packages and tools must be present for all targets. + +1. Watt-32 tcp/ip library. This library is *not* used to send or + receive network data. It's mostly used to access the 'hosts' + file and other features. Get 'watt32s*.zip' at: + + https://www.watt-32.net + +2. Exception handler and disassembler library (libexc.a) is needed if + "USE_EXCEPT = 1" in common.dj. Available at: + + https://www.watt-32.net/misc/exc_dx07.zip + +3. Flex & Bison is used to generate parser for the filter handler + pcap_compile: + ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/flx254b.zip + ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/bsn241b.zip + +4. NASM assembler v 0.98 or later is required when building djgpp and + Watcom targets: + https://www.nasm.us/ + +5. sed (Stream Editor) is required for doing `make depend'. + It's available at: + ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/sed422b.zip + + A touch tool to update the time-stamp of a file. E.g.: + ftp://ftp.delorie.com/pub/djgpp/current/v2gnu/grep29b.zip + +6. For djgpp rm.exe and cp.exe are required. These should already be + part of your djgpp installation. Also required (experimental at the + time) for djgpp is DLX 2.91 or later. This tool is for the generation + of dynamically loadable modules. + + +Compiling libpcap +----------------- + +Follow these steps in building libpcap: + +1. Make sure you've installed Watt-32 properly (see it's `INSTALL' file). + During that installation a environment variable `WATT_ROOT' is set. + This variable is used for building libpcap also (`WATT_INC' is + deducted from `WATT_ROOT'). djgpp users should also define environment + variables `C_INCLUDE_PATH' and `LIBRARY_PATH' to point to the include + directory and library directory respectively. E.g. put this in your + AUTOEXEC.BAT: + set C_INCLUDE_PATH=c:/net/watt/inc + set LIBRARY_PATH=c:/net/watt/lib + +2. Revise the msdos/common.dj file for your djgpp/gcc installation; + - change the value of `GCCLIB' to match location of libgcc.a. + - set `USE_32BIT_DRIVERS = 1' to build 32-bit driver objects. + + +3. Build pcap by using appropriate makefile. For djgpp, use: + `make -f msdos/makefile.dj' (i.e. GNU `make') + + For a Watcom target say: + `wmake -f msdos\makefile.wc' + + For a Borland target say: + `maker -f msdos\Makefile pcap_bc.lib' (Borland's `maker.exe') + + And for a HighC/Pharlap target say: + `maker -f msdos\Makefile pcap_hc.lib' (Borland's `maker.exe') + + You might like to change some `CFLAGS' -- only `DEBUG' define currently + have any effect. It shows a rotating "fan" in upper right corner of + screen. Remove `DEBUG' if you don't like it. You could add + `-fomit-frame-pointer' to `CFLAGS' to speed up the generated code. + But note, this makes debugging and crash-traceback difficult. Only + add it if you're fully confident your application is 100% stable. + + Note: Code in `USE_NDIS2' does not work at the moment. + +4. The resulting library is put in current directory. There's some + test-program for `libpcap': `filtertest.exe', `findalldevstest.exe', + `nonblocktest.exe' and `opentest.exe'. + + But linking the library with `tcpdump' is the ultimate test. DOS/djgpp + should now hopefully be a supported target. Get the sources at: + https://www.tcpdump.org/ + or + https://github.com/the-tcpdump-group/tcpdump/ + + (click on the 'Download ZIP' on the right side of that page.) + + +Extensions to libpcap +--------------------- + +I've included some extra functions to DOS-libpcap: + + `pcap_config_hook (const char *keyword, const char *value)' : + + Allows an application to set values of internal libpcap variables. + `keyword' and an associated `value' should be present in the `debug_tab[]' + array in pcap-dos.c (currently only used to set debug-levels and parameters + for the 32-bit network drivers.) Thus an application using DOS-libpcap can + override the default value during it's configure process (see tcpdump's + msdos/config.c file for an extended example). + + `pcap_set_wait (pcap_t *, void (*)(void), int)' : + + Only effective when reading offline traffic from dump-files. + Function `pcap_offline_read()' will wait (and optionally yield) + before printing next packet. This will simulate the pace the packets + where actually recorded. + + + +Happy sniffing ! + + +Gisle Vanem + +October 1999, 2004, 2006, 2013 + diff --git a/src/libpcap-1.10.5/nametoaddr.c b/src/libpcap-1.10.5/nametoaddr.c new file mode 100644 index 0000000000..d5cb981cc9 --- /dev/null +++ b/src/libpcap-1.10.5/nametoaddr.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Name to id translation routines used by the scanner. + * These functions are not time critical. + */ + +#include + +#ifdef DECNETLIB +#include +#include +#endif + +#ifdef _WIN32 + #include + #include + + #ifdef INET6 + /* + * To quote the MSDN page for getaddrinfo() at + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + * + * "Support for getaddrinfo on Windows 2000 and older versions + * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and + * later. To execute an application that uses this function on earlier + * versions of Windows, then you need to include the Ws2tcpip.h and + * Wspiapi.h files. When the Wspiapi.h include file is added, the + * getaddrinfo function is defined to the WspiapiGetAddrInfo inline + * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo + * function is implemented in such a way that if the Ws2_32.dll or the + * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology + * Preview for Windows 2000) does not include getaddrinfo, then a + * version of getaddrinfo is implemented inline based on code in the + * Wspiapi.h header file. This inline code will be used on older Windows + * platforms that do not natively support the getaddrinfo function." + * + * We use getaddrinfo(), so we include Wspiapi.h here. + */ + #include + #endif /* INET6 */ +#else /* _WIN32 */ + #include + #include + #include + #include + + #include + + #ifdef HAVE_ETHER_HOSTTON + #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include . + */ + #include + #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include + */ + #include + #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include + */ + #include + #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON) + /* + * OK, just include + */ + #include + #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) + /* + * OK, include , after all the other stuff we + * need to include or define for its benefit. + */ + #define NEED_NETINET_IF_ETHER_H + #else + /* + * We'll have to declare it ourselves. + * If defines struct ether_addr, include + * it. Otherwise, define it ourselves. + */ + #ifdef HAVE_STRUCT_ETHER_ADDR + #define NEED_NETINET_IF_ETHER_H + #else /* HAVE_STRUCT_ETHER_ADDR */ + struct ether_addr { + unsigned char ether_addr_octet[6]; + }; + #endif /* HAVE_STRUCT_ETHER_ADDR */ + #endif /* what declares ether_hostton() */ + + #ifdef NEED_NETINET_IF_ETHER_H + #include /* Needed on some platforms */ + #include /* Needed on some platforms */ + #include + #endif /* NEED_NETINET_IF_ETHER_H */ + + #ifndef HAVE_DECL_ETHER_HOSTTON + /* + * No header declares it, so declare it ourselves. + */ + extern int ether_hostton(const char *, struct ether_addr *); + #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */ + #endif /* HAVE_ETHER_HOSTTON */ + + #include + #include +#endif /* _WIN32 */ + +#include +#include +#include +#include + +#include "pcap-int.h" + +#include "diag-control.h" + +#include "gencode.h" +#include +#include "nametoaddr.h" + +#include "thread-local.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifndef NTOHL +#define NTOHL(x) (x) = ntohl(x) +#define NTOHS(x) (x) = ntohs(x) +#endif + +/* + * Convert host name to internet address. + * Return 0 upon failure. + * XXX - not thread-safe; don't use it inside libpcap. + */ +bpf_u_int32 ** +pcap_nametoaddr(const char *name) +{ +#ifndef h_addr + static bpf_u_int32 *hlist[2]; +#endif + bpf_u_int32 **p; + struct hostent *hp; + + /* + * gethostbyname() is deprecated on Windows, perhaps because + * it's not thread-safe, or because it doesn't support IPv6, + * or both. + * + * We deprecate pcap_nametoaddr() on all platforms because + * it's not thread-safe; we supply it for backwards compatibility, + * so suppress the deprecation warning. We could, I guess, + * use getaddrinfo() and construct the array ourselves, but + * that's probably not worth the effort, as that wouldn't make + * this thread-safe - we can't change the API to require that + * our caller free the address array, so we still have to reuse + * a local array. + */ +DIAG_OFF_DEPRECATION + if ((hp = gethostbyname(name)) != NULL) { +DIAG_ON_DEPRECATION +#ifndef h_addr + hlist[0] = (bpf_u_int32 *)hp->h_addr; + NTOHL(hp->h_addr); + return hlist; +#else + for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p) + NTOHL(**p); + return (bpf_u_int32 **)hp->h_addr_list; +#endif + } + else + return 0; +} + +struct addrinfo * +pcap_nametoaddrinfo(const char *name) +{ + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; /*not really*/ + hints.ai_protocol = IPPROTO_TCP; /*not really*/ + error = getaddrinfo(name, NULL, &hints, &res); + if (error) + return NULL; + else + return res; +} + +/* + * Convert net name to internet address. + * Return 0 upon failure. + * XXX - not guaranteed to be thread-safe! See below for platforms + * on which it is thread-safe and on which it isn't. + */ +#if defined(_WIN32) || defined(__CYGWIN__) +bpf_u_int32 +pcap_nametonetaddr(const char *name _U_) +{ + /* + * There's no "getnetbyname()" on Windows. + * + * XXX - I guess we could use the BSD code to read + * C:\Windows\System32\drivers\etc/networks, assuming + * that's its home on all the versions of Windows + * we use, but that file probably just has the loopback + * network on 127/24 on 99 44/100% of Windows machines. + * + * (Heck, these days it probably just has that on 99 44/100% + * of *UN*X* machines.) + */ + return 0; +} +#else /* _WIN32 */ +bpf_u_int32 +pcap_nametonetaddr(const char *name) +{ + /* + * UN*X. + */ + struct netent *np; + #if defined(HAVE_LINUX_GETNETBYNAME_R) + /* + * We have Linux's reentrant getnetbyname_r(). + */ + struct netent result_buf; + char buf[1024]; /* arbitrary size */ + int h_errnoval; + int err; + + /* + * Apparently, the man page at + * + * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html + * + * lies when it says + * + * If the function call successfully obtains a network record, + * then *result is set pointing to result_buf; otherwise, *result + * is set to NULL. + * + * and, in fact, at least in some versions of GNU libc, it does + * *not* always get set if getnetbyname_r() succeeds. + */ + np = NULL; + err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, + &h_errnoval); + if (err != 0) { + /* + * XXX - dynamically allocate the buffer, and make it + * bigger if we get ERANGE back? + */ + return 0; + } + #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + /* + * We have Solaris's and IRIX's reentrant getnetbyname_r(). + */ + struct netent result_buf; + char buf[1024]; /* arbitrary size */ + + np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf); + #elif defined(HAVE_AIX_GETNETBYNAME_R) + /* + * We have AIX's reentrant getnetbyname_r(). + */ + struct netent result_buf; + struct netent_data net_data; + + if (getnetbyname_r(name, &result_buf, &net_data) == -1) + np = NULL; + else + np = &result_buf; + #else + /* + * We don't have any getnetbyname_r(); either we have a + * getnetbyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX), or we have the + * traditional getnetbyname() (everything else, including + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ + np = getnetbyname(name); + #endif + if (np != NULL) + return np->n_net; + else + return 0; +} +#endif /* _WIN32 */ + +/* + * Convert a port name to its port and protocol numbers. + * We assume only TCP or UDP. + * Return 0 upon failure. + */ +int +pcap_nametoport(const char *name, int *port, int *proto) +{ + struct addrinfo hints, *res, *ai; + int error; + struct sockaddr_in *in4; +#ifdef INET6 + struct sockaddr_in6 *in6; +#endif + int tcp_port = -1; + int udp_port = -1; + + /* + * We check for both TCP and UDP in case there are + * ambiguous entries. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + error = getaddrinfo(NULL, name, &hints, &res); + if (error != 0) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { + /* + * This is a real error, not just "there's + * no such service name". + * XXX - this doesn't return an error string. + */ + return 0; + } + } else { + /* + * OK, we found it. Did it find anything? + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Get a port number; we're done. + */ + if (ai->ai_addr->sa_family == AF_INET) { + in4 = (struct sockaddr_in *)ai->ai_addr; + tcp_port = ntohs(in4->sin_port); + break; + } +#ifdef INET6 + if (ai->ai_addr->sa_family == AF_INET6) { + in6 = (struct sockaddr_in6 *)ai->ai_addr; + tcp_port = ntohs(in6->sin6_port); + break; + } +#endif + } + } + freeaddrinfo(res); + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + error = getaddrinfo(NULL, name, &hints, &res); + if (error != 0) { + if (error != EAI_NONAME && + error != EAI_SERVICE) { + /* + * This is a real error, not just "there's + * no such service name". + * XXX - this doesn't return an error string. + */ + return 0; + } + } else { + /* + * OK, we found it. Did it find anything? + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Get a port number; we're done. + */ + if (ai->ai_addr->sa_family == AF_INET) { + in4 = (struct sockaddr_in *)ai->ai_addr; + udp_port = ntohs(in4->sin_port); + break; + } +#ifdef INET6 + if (ai->ai_addr->sa_family == AF_INET6) { + in6 = (struct sockaddr_in6 *)ai->ai_addr; + udp_port = ntohs(in6->sin6_port); + break; + } +#endif + } + } + freeaddrinfo(res); + } + + /* + * We need to check /etc/services for ambiguous entries. + * If we find an ambiguous entry, and it has the + * same port number, change the proto to PROTO_UNDEF + * so both TCP and UDP will be checked. + */ + if (tcp_port >= 0) { + *port = tcp_port; + *proto = IPPROTO_TCP; + if (udp_port >= 0) { + if (udp_port == tcp_port) + *proto = PROTO_UNDEF; +#ifdef notdef + else + /* Can't handle ambiguous names that refer + to different port numbers. */ + warning("ambiguous port %s in /etc/services", + name); +#endif + } + return 1; + } + if (udp_port >= 0) { + *port = udp_port; + *proto = IPPROTO_UDP; + return 1; + } +#if defined(ultrix) || defined(__osf__) + /* Special hack in case NFS isn't in /etc/services */ + if (strcmp(name, "nfs") == 0) { + *port = 2049; + *proto = PROTO_UNDEF; + return 1; + } +#endif + return 0; +} + +/* + * Convert a string in the form PPP-PPP, where correspond to ports, to + * a starting and ending port in a port range. + * Return 0 on failure. + */ +int +pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) +{ + char *off, *cpy; + int save_proto; + + if ((cpy = strdup(name)) == NULL) + return 0; + + if ((off = strchr(cpy, '-')) == NULL) { + free(cpy); + return 0; + } + + *off = '\0'; + + if (pcap_nametoport(cpy, port1, proto) == 0) { + free(cpy); + return 0; + } + save_proto = *proto; + + if (pcap_nametoport(off + 1, port2, proto) == 0) { + free(cpy); + return 0; + } + free(cpy); + + if (*proto != save_proto) + *proto = PROTO_UNDEF; + + return 1; +} + +/* + * XXX - not guaranteed to be thread-safe! See below for platforms + * on which it is thread-safe and on which it isn't. + */ +int +pcap_nametoproto(const char *str) +{ + struct protoent *p; + #if defined(HAVE_LINUX_GETNETBYNAME_R) + /* + * We have Linux's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + char buf[1024]; /* arbitrary size */ + int err; + + err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p); + if (err != 0) { + /* + * XXX - dynamically allocate the buffer, and make it + * bigger if we get ERANGE back? + */ + return 0; + } + #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) + /* + * We have Solaris's and IRIX's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + char buf[1024]; /* arbitrary size */ + + p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf); + #elif defined(HAVE_AIX_GETNETBYNAME_R) + /* + * We have AIX's reentrant getprotobyname_r(). + */ + struct protoent result_buf; + struct protoent_data proto_data; + + if (getprotobyname_r(str, &result_buf, &proto_data) == -1) + p = NULL; + else + p = &result_buf; + #else + /* + * We don't have any getprotobyname_r(); either we have a + * getprotobyname() that uses thread-specific data, in which + * case we're thread-safe (sufficiently recent FreeBSD, + * sufficiently recent Darwin-based OS, sufficiently recent + * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have + * the traditional getprotobyname() (everything else, including + * current NetBSD and OpenBSD), in which case we're not + * thread-safe. + */ + p = getprotobyname(str); + #endif + if (p != 0) + return p->p_proto; + else + return PROTO_UNDEF; +} + +#include "ethertype.h" + +struct eproto { + const char *s; + u_short p; +}; + +/* + * Static data base of ether protocol types. + * tcpdump used to import this, and it's declared as an export on + * Debian, at least, so make it a public symbol, even though we + * don't officially export it by declaring it in a header file. + * (Programs *should* do this themselves, as tcpdump now does.) + * + * We declare it here, right before defining it, to squelch any + * warnings we might get from compilers about the lack of a + * declaration. + */ +PCAP_API struct eproto eproto_db[]; +PCAP_API_DEF struct eproto eproto_db[] = { + { "aarp", ETHERTYPE_AARP }, + { "arp", ETHERTYPE_ARP }, + { "atalk", ETHERTYPE_ATALK }, + { "decnet", ETHERTYPE_DN }, + { "ip", ETHERTYPE_IP }, +#ifdef INET6 + { "ip6", ETHERTYPE_IPV6 }, +#endif + { "lat", ETHERTYPE_LAT }, + { "loopback", ETHERTYPE_LOOPBACK }, + { "mopdl", ETHERTYPE_MOPDL }, + { "moprc", ETHERTYPE_MOPRC }, + { "rarp", ETHERTYPE_REVARP }, + { "sca", ETHERTYPE_SCA }, + { (char *)0, 0 } +}; + +int +pcap_nametoeproto(const char *s) +{ + struct eproto *p = eproto_db; + + while (p->s != 0) { + if (strcmp(p->s, s) == 0) + return p->p; + p += 1; + } + return PROTO_UNDEF; +} + +#include "llc.h" + +/* Static data base of LLC values. */ +static struct eproto llc_db[] = { + { "iso", LLCSAP_ISONS }, + { "stp", LLCSAP_8021D }, + { "ipx", LLCSAP_IPX }, + { "netbeui", LLCSAP_NETBEUI }, + { (char *)0, 0 } +}; + +int +pcap_nametollc(const char *s) +{ + struct eproto *p = llc_db; + + while (p->s != 0) { + if (strcmp(p->s, s) == 0) + return p->p; + p += 1; + } + return PROTO_UNDEF; +} + +/* Hex digit to 8-bit unsigned integer. */ +static inline u_char +xdtoi(u_char c) +{ + if (c >= '0' && c <= '9') + return (u_char)(c - '0'); + else if (c >= 'a' && c <= 'f') + return (u_char)(c - 'a' + 10); + else + return (u_char)(c - 'A' + 10); +} + +int +__pcap_atoin(const char *s, bpf_u_int32 *addr) +{ + u_int n; + int len; + + *addr = 0; + len = 0; + for (;;) { + n = 0; + while (*s && *s != '.') { + if (n > 25) { + /* The result will be > 255 */ + return -1; + } + n = n * 10 + *s++ - '0'; + } + if (n > 255) + return -1; + *addr <<= 8; + *addr |= n & 0xff; + len += 8; + if (*s == '\0') + return len; + ++s; + } + /* NOTREACHED */ +} + +int +__pcap_atodn(const char *s, bpf_u_int32 *addr) +{ +#define AREASHIFT 10 +#define AREAMASK 0176000 +#define NODEMASK 01777 + + u_int node, area; + + if (sscanf(s, "%d.%d", &area, &node) != 2) + return(0); + + *addr = (area << AREASHIFT) & AREAMASK; + *addr |= (node & NODEMASK); + + return(32); +} + +/* + * Convert 's', which can have the one of the forms: + * + * "xx:xx:xx:xx:xx:xx" + * "xx.xx.xx.xx.xx.xx" + * "xx-xx-xx-xx-xx-xx" + * "xxxx.xxxx.xxxx" + * "xxxxxxxxxxxx" + * + * (or various mixes of ':', '.', and '-') into a new + * ethernet address. Assumes 's' is well formed. + */ +u_char * +pcap_ether_aton(const char *s) +{ + register u_char *ep, *e; + register u_char d; + + e = ep = (u_char *)malloc(6); + if (e == NULL) + return (NULL); + + while (*s) { + if (*s == ':' || *s == '.' || *s == '-') + s += 1; + d = xdtoi(*s++); + if (PCAP_ISXDIGIT(*s)) { + d <<= 4; + d |= xdtoi(*s++); + } + *ep++ = d; + } + + return (e); +} + +#ifndef HAVE_ETHER_HOSTTON +/* + * Roll our own. + * + * This should be thread-safe, as we define the static variables + * we use to be thread-local, and as pcap_next_etherent() does so + * as well. + */ +u_char * +pcap_ether_hostton(const char *name) +{ + register struct pcap_etherent *ep; + register u_char *ap; + static thread_local FILE *fp = NULL; + static thread_local int init = 0; + + if (!init) { + fp = fopen(PCAP_ETHERS_FILE, "r"); + ++init; + if (fp == NULL) + return (NULL); + } else if (fp == NULL) + return (NULL); + else + rewind(fp); + + while ((ep = pcap_next_etherent(fp)) != NULL) { + if (strcmp(ep->name, name) == 0) { + ap = (u_char *)malloc(6); + if (ap != NULL) { + memcpy(ap, ep->addr, 6); + return (ap); + } + break; + } + } + return (NULL); +} +#else +/* + * Use the OS-supplied routine. + * This *should* be thread-safe; the API doesn't have a static buffer. + */ +u_char * +pcap_ether_hostton(const char *name) +{ + register u_char *ap; + u_char a[6]; + char namebuf[1024]; + + /* + * In AIX 7.1 and 7.2: int ether_hostton(char *, struct ether_addr *); + */ + pcapint_strlcpy(namebuf, name, sizeof(namebuf)); + ap = NULL; + if (ether_hostton(namebuf, (struct ether_addr *)a) == 0) { + ap = (u_char *)malloc(6); + if (ap != NULL) + memcpy((char *)ap, (char *)a, 6); + } + return (ap); +} +#endif + +/* + * XXX - not guaranteed to be thread-safe! + */ +int +#ifdef DECNETLIB +__pcap_nametodnaddr(const char *name, u_short *res) +{ + struct nodeent *getnodebyname(); + struct nodeent *nep; + + nep = getnodebyname(name); + if (nep == ((struct nodeent *)0)) + return(0); + + memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); + return(1); +#else +__pcap_nametodnaddr(const char *name _U_, u_short *res _U_) +{ + return(0); +#endif +} diff --git a/src/libpcap-1.10.5/nametoaddr.h b/src/libpcap-1.10.5/nametoaddr.h new file mode 100644 index 0000000000..fd6b7e1016 --- /dev/null +++ b/src/libpcap-1.10.5/nametoaddr.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Routines used for name-or-address-string-to-address resolution + * that are *not* exported to code using libpcap. + */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +int __pcap_nametodnaddr(const char *, u_short *); + +#ifdef __cplusplus +} +#endif diff --git a/src/libpcap-1.10.5/nlpid.h b/src/libpcap-1.10.5/nlpid.h new file mode 100644 index 0000000000..b730d3d42e --- /dev/null +++ b/src/libpcap-1.10.5/nlpid.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996 + * Juniper Networks, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution. The name of Juniper Networks may not + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* Types missing from some systems */ + +/* + * Network layer protocol identifiers + */ +#ifndef ISO8473_CLNP +#define ISO8473_CLNP 0x81 +#endif +#ifndef ISO9542_ESIS +#define ISO9542_ESIS 0x82 +#endif +#ifndef ISO9542X25_ESIS +#define ISO9542X25_ESIS 0x8a +#endif +#ifndef ISO10589_ISIS +#define ISO10589_ISIS 0x83 +#endif +/* + * this does not really belong in the nlpid.h file + * however we need it for generating nice + * IS-IS related BPF filters + */ +#define ISIS_L1_LAN_IIH 15 +#define ISIS_L2_LAN_IIH 16 +#define ISIS_PTP_IIH 17 +#define ISIS_L1_LSP 18 +#define ISIS_L2_LSP 20 +#define ISIS_L1_CSNP 24 +#define ISIS_L2_CSNP 25 +#define ISIS_L1_PSNP 26 +#define ISIS_L2_PSNP 27 + +#ifndef ISO8878A_CONS +#define ISO8878A_CONS 0x84 +#endif +#ifndef ISO10747_IDRP +#define ISO10747_IDRP 0x85 +#endif diff --git a/src/libpcap-1.10.5/nomkdep b/src/libpcap-1.10.5/nomkdep new file mode 100755 index 0000000000..bed736687e --- /dev/null +++ b/src/libpcap-1.10.5/nomkdep @@ -0,0 +1,6 @@ +#!/bin/sh - +# +# Does nothing; used if we don't have a command-line flag to the compiler +# to get it to generate dependencies. +# +exit 0 diff --git a/src/libpcap-1.10.5/optimize.c b/src/libpcap-1.10.5/optimize.c new file mode 100644 index 0000000000..d70949347b --- /dev/null +++ b/src/libpcap-1.10.5/optimize.c @@ -0,0 +1,3113 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Optimization module for BPF code intermediate representation. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include /* for SIZE_MAX */ +#include + +#include "pcap-int.h" + +#include "gencode.h" +#include "optimize.h" +#include "diag-control.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifdef BDEBUG +/* + * The internal "debug printout" flag for the filter expression optimizer. + * The code to print that stuff is present only if BDEBUG is defined, so + * the flag, and the routine to set it, are defined only if BDEBUG is + * defined. + */ +static int pcap_optimizer_debug; + +/* + * Routine to set that flag. + * + * This is intended for libpcap developers, not for general use. + * If you want to set these in a program, you'll have to declare this + * routine yourself, with the appropriate DLL import attribute on Windows; + * it's not declared in any header file, and won't be declared in any + * header file provided by libpcap. + */ +PCAP_API void pcap_set_optimizer_debug(int value); + +PCAP_API_DEF void +pcap_set_optimizer_debug(int value) +{ + pcap_optimizer_debug = value; +} + +/* + * The internal "print dot graph" flag for the filter expression optimizer. + * The code to print that stuff is present only if BDEBUG is defined, so + * the flag, and the routine to set it, are defined only if BDEBUG is + * defined. + */ +static int pcap_print_dot_graph; + +/* + * Routine to set that flag. + * + * This is intended for libpcap developers, not for general use. + * If you want to set these in a program, you'll have to declare this + * routine yourself, with the appropriate DLL import attribute on Windows; + * it's not declared in any header file, and won't be declared in any + * header file provided by libpcap. + */ +PCAP_API void pcap_set_print_dot_graph(int value); + +PCAP_API_DEF void +pcap_set_print_dot_graph(int value) +{ + pcap_print_dot_graph = value; +} + +#endif + +/* + * lowest_set_bit(). + * + * Takes a 32-bit integer as an argument. + * + * If handed a non-zero value, returns the index of the lowest set bit, + * counting upwards from zero. + * + * If handed zero, the results are platform- and compiler-dependent. + * Keep it out of the light, don't give it any water, don't feed it + * after midnight, and don't pass zero to it. + * + * This is the same as the count of trailing zeroes in the word. + */ +#if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4) + /* + * GCC 3.4 and later; we have __builtin_ctz(). + */ + #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask)) +#elif defined(_MSC_VER) + /* + * Visual Studio; we support only 2005 and later, so use + * _BitScanForward(). + */ +#include + +#ifndef __clang__ +#pragma intrinsic(_BitScanForward) +#endif + +static __forceinline u_int +lowest_set_bit(int mask) +{ + unsigned long bit; + + /* + * Don't sign-extend mask if long is longer than int. + * (It's currently not, in MSVC, even on 64-bit platforms, but....) + */ + if (_BitScanForward(&bit, (unsigned int)mask) == 0) + abort(); /* mask is zero */ + return (u_int)bit; +} +#elif defined(MSDOS) && defined(__DJGPP__) + /* + * MS-DOS with DJGPP, which declares ffs() in , which + * we've already included. + */ + #define lowest_set_bit(mask) ((u_int)(ffs((mask)) - 1)) +#elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS) + /* + * MS-DOS with Watcom C, which has and declares ffs() there, + * or some other platform (UN*X conforming to a sufficient recent version + * of the Single UNIX Specification). + */ + #include + #define lowest_set_bit(mask) (u_int)((ffs((mask)) - 1)) +#else +/* + * None of the above. + * Use a perfect-hash-function-based function. + */ +static u_int +lowest_set_bit(int mask) +{ + unsigned int v = (unsigned int)mask; + + static const u_int MultiplyDeBruijnBitPosition[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + + /* + * We strip off all but the lowermost set bit (v & ~v), + * and perform a minimal perfect hash on it to look up the + * number of low-order zero bits in a table. + * + * See: + * + * http://7ooo.mooo.com/text/ComputingTrailingZerosHOWTO.pdf + * + * http://supertech.csail.mit.edu/papers/debruijn.pdf + */ + return (MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27]); +} +#endif + +/* + * Represents a deleted instruction. + */ +#define NOP -1 + +/* + * Register numbers for use-def values. + * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory + * location. A_ATOM is the accumulator and X_ATOM is the index + * register. + */ +#define A_ATOM BPF_MEMWORDS +#define X_ATOM (BPF_MEMWORDS+1) + +/* + * This define is used to represent *both* the accumulator and + * x register in use-def computations. + * Currently, the use-def code assumes only one definition per instruction. + */ +#define AX_ATOM N_ATOMS + +/* + * These data structures are used in a Cocke and Schwartz style + * value numbering scheme. Since the flowgraph is acyclic, + * exit values can be propagated from a node's predecessors + * provided it is uniquely defined. + */ +struct valnode { + int code; + bpf_u_int32 v0, v1; + int val; /* the value number */ + struct valnode *next; +}; + +/* Integer constants mapped with the load immediate opcode. */ +#define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U) + +struct vmapinfo { + int is_const; + bpf_u_int32 const_val; +}; + +typedef struct { + /* + * Place to longjmp to on an error. + */ + jmp_buf top_ctx; + + /* + * The buffer into which to put error message. + */ + char *errbuf; + + /* + * A flag to indicate that further optimization is needed. + * Iterative passes are continued until a given pass yields no + * code simplification or branch movement. + */ + int done; + + /* + * XXX - detect loops that do nothing but repeated AND/OR pullups + * and edge moves. + * If 100 passes in a row do nothing but that, treat that as a + * sign that we're in a loop that just shuffles in a cycle in + * which each pass just shuffles the code and we eventually + * get back to the original configuration. + * + * XXX - we need a non-heuristic way of detecting, or preventing, + * such a cycle. + */ + int non_branch_movement_performed; + + u_int n_blocks; /* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */ + struct block **blocks; + u_int n_edges; /* twice n_blocks, so guaranteed to be > 0 */ + struct edge **edges; + + /* + * A bit vector set representation of the dominators. + * We round up the set size to the next power of two. + */ + u_int nodewords; /* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */ + u_int edgewords; /* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */ + struct block **levels; + bpf_u_int32 *space; + +#define BITS_PER_WORD (8*sizeof(bpf_u_int32)) +/* + * True if a is in uset {p} + */ +#define SET_MEMBER(p, a) \ +((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))) + +/* + * Add 'a' to uset p. + */ +#define SET_INSERT(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * Delete 'a' from uset p. + */ +#define SET_DELETE(p, a) \ +(p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)) + +/* + * a := a intersect b + * n must be guaranteed to be > 0 + */ +#define SET_INTERSECT(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register u_int _n = n;\ + do *_x++ &= *_y++; while (--_n != 0);\ +} + +/* + * a := a - b + * n must be guaranteed to be > 0 + */ +#define SET_SUBTRACT(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register u_int _n = n;\ + do *_x++ &=~ *_y++; while (--_n != 0);\ +} + +/* + * a := a union b + * n must be guaranteed to be > 0 + */ +#define SET_UNION(a, b, n)\ +{\ + register bpf_u_int32 *_x = a, *_y = b;\ + register u_int _n = n;\ + do *_x++ |= *_y++; while (--_n != 0);\ +} + + uset all_dom_sets; + uset all_closure_sets; + uset all_edge_sets; + +#define MODULUS 213 + struct valnode *hashtbl[MODULUS]; + bpf_u_int32 curval; + bpf_u_int32 maxval; + + struct vmapinfo *vmap; + struct valnode *vnode_base; + struct valnode *next_vnode; +} opt_state_t; + +typedef struct { + /* + * Place to longjmp to on an error. + */ + jmp_buf top_ctx; + + /* + * The buffer into which to put error message. + */ + char *errbuf; + + /* + * Some pointers used to convert the basic block form of the code, + * into the array form that BPF requires. 'fstart' will point to + * the malloc'd array while 'ftail' is used during the recursive + * traversal. + */ + struct bpf_insn *fstart; + struct bpf_insn *ftail; +} conv_state_t; + +static void opt_init(opt_state_t *, struct icode *); +static void opt_cleanup(opt_state_t *); +static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + +static void intern_blocks(opt_state_t *, struct icode *); + +static void find_inedges(opt_state_t *, struct block *); +#ifdef BDEBUG +static void opt_dump(opt_state_t *, struct icode *); +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +static void +find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b) +{ + int level; + + if (isMarked(ic, b)) + return; + + Mark(ic, b); + b->link = 0; + + if (JT(b)) { + find_levels_r(opt_state, ic, JT(b)); + find_levels_r(opt_state, ic, JF(b)); + level = MAX(JT(b)->level, JF(b)->level) + 1; + } else + level = 0; + b->level = level; + b->link = opt_state->levels[level]; + opt_state->levels[level] = b; +} + +/* + * Level graph. The levels go from 0 at the leaves to + * N_LEVELS at the root. The opt_state->levels[] array points to the + * first node of the level list, whose elements are linked + * with the 'link' field of the struct block. + */ +static void +find_levels(opt_state_t *opt_state, struct icode *ic) +{ + memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels)); + unMarkAll(ic); + find_levels_r(opt_state, ic, ic->root); +} + +/* + * Find dominator relationships. + * Assumes graph has been leveled. + */ +static void +find_dom(opt_state_t *opt_state, struct block *root) +{ + u_int i; + int level; + struct block *b; + bpf_u_int32 *x; + + /* + * Initialize sets to contain all nodes. + */ + x = opt_state->all_dom_sets; + /* + * In opt_init(), we've made sure the product doesn't overflow. + */ + i = opt_state->n_blocks * opt_state->nodewords; + while (i != 0) { + --i; + *x++ = 0xFFFFFFFFU; + } + /* Root starts off empty. */ + for (i = opt_state->nodewords; i != 0;) { + --i; + root->dom[i] = 0; + } + + /* root->level is the highest level no found. */ + for (level = root->level; level >= 0; --level) { + for (b = opt_state->levels[level]; b; b = b->link) { + SET_INSERT(b->dom, b->id); + if (JT(b) == 0) + continue; + SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords); + SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords); + } + } +} + +static void +propedom(opt_state_t *opt_state, struct edge *ep) +{ + SET_INSERT(ep->edom, ep->id); + if (ep->succ) { + SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords); + SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords); + } +} + +/* + * Compute edge dominators. + * Assumes graph has been leveled and predecessors established. + */ +static void +find_edom(opt_state_t *opt_state, struct block *root) +{ + u_int i; + uset x; + int level; + struct block *b; + + x = opt_state->all_edge_sets; + /* + * In opt_init(), we've made sure the product doesn't overflow. + */ + for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) { + --i; + x[i] = 0xFFFFFFFFU; + } + + /* root->level is the highest level no found. */ + memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); + memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0)); + for (level = root->level; level >= 0; --level) { + for (b = opt_state->levels[level]; b != 0; b = b->link) { + propedom(opt_state, &b->et); + propedom(opt_state, &b->ef); + } + } +} + +/* + * Find the backwards transitive closure of the flow graph. These sets + * are backwards in the sense that we find the set of nodes that reach + * a given node, not the set of nodes that can be reached by a node. + * + * Assumes graph has been leveled. + */ +static void +find_closure(opt_state_t *opt_state, struct block *root) +{ + int level; + struct block *b; + + /* + * Initialize sets to contain no nodes. + */ + memset((char *)opt_state->all_closure_sets, 0, + opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets)); + + /* root->level is the highest level no found. */ + for (level = root->level; level >= 0; --level) { + for (b = opt_state->levels[level]; b; b = b->link) { + SET_INSERT(b->closure, b->id); + if (JT(b) == 0) + continue; + SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords); + SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords); + } + } +} + +/* + * Return the register number that is used by s. + * + * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X + * are used, the scratch memory location's number if a scratch memory + * location is used (e.g., 0 for M[0]), or -1 if none of those are used. + * + * The implementation should probably change to an array access. + */ +static int +atomuse(struct stmt *s) +{ + register int c = s->code; + + if (c == NOP) + return -1; + + switch (BPF_CLASS(c)) { + + case BPF_RET: + return (BPF_RVAL(c) == BPF_A) ? A_ATOM : + (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; + + case BPF_LD: + case BPF_LDX: + /* + * As there are fewer than 2^31 memory locations, + * s->k should be convertible to int without problems. + */ + return (BPF_MODE(c) == BPF_IND) ? X_ATOM : + (BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1; + + case BPF_ST: + return A_ATOM; + + case BPF_STX: + return X_ATOM; + + case BPF_JMP: + case BPF_ALU: + if (BPF_SRC(c) == BPF_X) + return AX_ATOM; + return A_ATOM; + + case BPF_MISC: + return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; + } + abort(); + /* NOTREACHED */ +} + +/* + * Return the register number that is defined by 's'. We assume that + * a single stmt cannot define more than one register. If no register + * is defined, return -1. + * + * The implementation should probably change to an array access. + */ +static int +atomdef(struct stmt *s) +{ + if (s->code == NOP) + return -1; + + switch (BPF_CLASS(s->code)) { + + case BPF_LD: + case BPF_ALU: + return A_ATOM; + + case BPF_LDX: + return X_ATOM; + + case BPF_ST: + case BPF_STX: + return s->k; + + case BPF_MISC: + return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; + } + return -1; +} + +/* + * Compute the sets of registers used, defined, and killed by 'b'. + * + * "Used" means that a statement in 'b' uses the register before any + * statement in 'b' defines it, i.e. it uses the value left in + * that register by a predecessor block of this block. + * "Defined" means that a statement in 'b' defines it. + * "Killed" means that a statement in 'b' defines it before any + * statement in 'b' uses it, i.e. it kills the value left in that + * register by a predecessor block of this block. + */ +static void +compute_local_ud(struct block *b) +{ + struct slist *s; + atomset def = 0, use = 0, killed = 0; + int atom; + + for (s = b->stmts; s; s = s->next) { + if (s->s.code == NOP) + continue; + atom = atomuse(&s->s); + if (atom >= 0) { + if (atom == AX_ATOM) { + if (!ATOMELEM(def, X_ATOM)) + use |= ATOMMASK(X_ATOM); + if (!ATOMELEM(def, A_ATOM)) + use |= ATOMMASK(A_ATOM); + } + else if (atom < N_ATOMS) { + if (!ATOMELEM(def, atom)) + use |= ATOMMASK(atom); + } + else + abort(); + } + atom = atomdef(&s->s); + if (atom >= 0) { + if (!ATOMELEM(use, atom)) + killed |= ATOMMASK(atom); + def |= ATOMMASK(atom); + } + } + if (BPF_CLASS(b->s.code) == BPF_JMP) { + /* + * XXX - what about RET? + */ + atom = atomuse(&b->s); + if (atom >= 0) { + if (atom == AX_ATOM) { + if (!ATOMELEM(def, X_ATOM)) + use |= ATOMMASK(X_ATOM); + if (!ATOMELEM(def, A_ATOM)) + use |= ATOMMASK(A_ATOM); + } + else if (atom < N_ATOMS) { + if (!ATOMELEM(def, atom)) + use |= ATOMMASK(atom); + } + else + abort(); + } + } + + b->def = def; + b->kill = killed; + b->in_use = use; +} + +/* + * Assume graph is already leveled. + */ +static void +find_ud(opt_state_t *opt_state, struct block *root) +{ + int i, maxlevel; + struct block *p; + + /* + * root->level is the highest level no found; + * count down from there. + */ + maxlevel = root->level; + for (i = maxlevel; i >= 0; --i) + for (p = opt_state->levels[i]; p; p = p->link) { + compute_local_ud(p); + p->out_use = 0; + } + + for (i = 1; i <= maxlevel; ++i) { + for (p = opt_state->levels[i]; p; p = p->link) { + p->out_use |= JT(p)->in_use | JF(p)->in_use; + p->in_use |= p->out_use &~ p->kill; + } + } +} +static void +init_val(opt_state_t *opt_state) +{ + opt_state->curval = 0; + opt_state->next_vnode = opt_state->vnode_base; + memset((char *)opt_state->vmap, 0, opt_state->maxval * sizeof(*opt_state->vmap)); + memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl); +} + +/* + * Because we really don't have an IR, this stuff is a little messy. + * + * This routine looks in the table of existing value number for a value + * with generated from an operation with the specified opcode and + * the specified values. If it finds it, it returns its value number, + * otherwise it makes a new entry in the table and returns the + * value number of that entry. + */ +static bpf_u_int32 +F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1) +{ + u_int hash; + bpf_u_int32 val; + struct valnode *p; + + hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8); + hash %= MODULUS; + + for (p = opt_state->hashtbl[hash]; p; p = p->next) + if (p->code == code && p->v0 == v0 && p->v1 == v1) + return p->val; + + /* + * Not found. Allocate a new value, and assign it a new + * value number. + * + * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we + * increment it before using it as the new value number, which + * means we never assign VAL_UNKNOWN. + * + * XXX - unless we overflow, but we probably won't have 2^32-1 + * values; we treat 32 bits as effectively infinite. + */ + val = ++opt_state->curval; + if (BPF_MODE(code) == BPF_IMM && + (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) { + opt_state->vmap[val].const_val = v0; + opt_state->vmap[val].is_const = 1; + } + p = opt_state->next_vnode++; + p->val = val; + p->code = code; + p->v0 = v0; + p->v1 = v1; + p->next = opt_state->hashtbl[hash]; + opt_state->hashtbl[hash] = p; + + return val; +} + +static inline void +vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter) +{ + if (alter && newval != VAL_UNKNOWN && *valp == newval) + s->code = NOP; + else + *valp = newval; +} + +/* + * Do constant-folding on binary operators. + * (Unary operators are handled elsewhere.) + */ +static void +fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1) +{ + bpf_u_int32 a, b; + + a = opt_state->vmap[v0].const_val; + b = opt_state->vmap[v1].const_val; + + switch (BPF_OP(s->code)) { + case BPF_ADD: + a += b; + break; + + case BPF_SUB: + a -= b; + break; + + case BPF_MUL: + a *= b; + break; + + case BPF_DIV: + if (b == 0) + opt_error(opt_state, "division by zero"); + a /= b; + break; + + case BPF_MOD: + if (b == 0) + opt_error(opt_state, "modulus by zero"); + a %= b; + break; + + case BPF_AND: + a &= b; + break; + + case BPF_OR: + a |= b; + break; + + case BPF_XOR: + a ^= b; + break; + + case BPF_LSH: + /* + * A left shift of more than the width of the type + * is undefined in C; we'll just treat it as shifting + * all the bits out. + * + * XXX - the BPF interpreter doesn't check for this, + * so its behavior is dependent on the behavior of + * the processor on which it's running. There are + * processors on which it shifts all the bits out + * and processors on which it does no shift. + */ + if (b < 32) + a <<= b; + else + a = 0; + break; + + case BPF_RSH: + /* + * A right shift of more than the width of the type + * is undefined in C; we'll just treat it as shifting + * all the bits out. + * + * XXX - the BPF interpreter doesn't check for this, + * so its behavior is dependent on the behavior of + * the processor on which it's running. There are + * processors on which it shifts all the bits out + * and processors on which it does no shift. + */ + if (b < 32) + a >>= b; + else + a = 0; + break; + + default: + abort(); + } + s->k = a; + s->code = BPF_LD|BPF_IMM; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; +} + +static inline struct slist * +this_op(struct slist *s) +{ + while (s != 0 && s->s.code == NOP) + s = s->next; + return s; +} + +static void +opt_not(struct block *b) +{ + struct block *tmp = JT(b); + + JT(b) = JF(b); + JF(b) = tmp; +} + +static void +opt_peep(opt_state_t *opt_state, struct block *b) +{ + struct slist *s; + struct slist *next, *last; + bpf_u_int32 val; + + s = b->stmts; + if (s == 0) + return; + + last = s; + for (/*empty*/; /*empty*/; s = next) { + /* + * Skip over nops. + */ + s = this_op(s); + if (s == 0) + break; /* nothing left in the block */ + + /* + * Find the next real instruction after that one + * (skipping nops). + */ + next = this_op(s->next); + if (next == 0) + break; /* no next instruction */ + last = next; + + /* + * st M[k] --> st M[k] + * ldx M[k] tax + */ + if (s->s.code == BPF_ST && + next->s.code == (BPF_LDX|BPF_MEM) && + s->s.k == next->s.k) { + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + next->s.code = BPF_MISC|BPF_TAX; + } + /* + * ld #k --> ldx #k + * tax txa + */ + if (s->s.code == (BPF_LD|BPF_IMM) && + next->s.code == (BPF_MISC|BPF_TAX)) { + s->s.code = BPF_LDX|BPF_IMM; + next->s.code = BPF_MISC|BPF_TXA; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + /* + * This is an ugly special case, but it happens + * when you say tcp[k] or udp[k] where k is a constant. + */ + if (s->s.code == (BPF_LD|BPF_IMM)) { + struct slist *add, *tax, *ild; + + /* + * Check that X isn't used on exit from this + * block (which the optimizer might cause). + * We know the code generator won't generate + * any local dependencies. + */ + if (ATOMELEM(b->out_use, X_ATOM)) + continue; + + /* + * Check that the instruction following the ldi + * is an addx, or it's an ldxms with an addx + * following it (with 0 or more nops between the + * ldxms and addx). + */ + if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B)) + add = next; + else + add = this_op(next->next); + if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X)) + continue; + + /* + * Check that a tax follows that (with 0 or more + * nops between them). + */ + tax = this_op(add->next); + if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX)) + continue; + + /* + * Check that an ild follows that (with 0 or more + * nops between them). + */ + ild = this_op(tax->next); + if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || + BPF_MODE(ild->s.code) != BPF_IND) + continue; + /* + * We want to turn this sequence: + * + * (004) ldi #0x2 {s} + * (005) ldxms [14] {next} -- optional + * (006) addx {add} + * (007) tax {tax} + * (008) ild [x+0] {ild} + * + * into this sequence: + * + * (004) nop + * (005) ldxms [14] + * (006) nop + * (007) nop + * (008) ild [x+2] + * + * XXX We need to check that X is not + * subsequently used, because we want to change + * what'll be in it after this sequence. + * + * We know we can eliminate the accumulator + * modifications earlier in the sequence since + * it is defined by the last stmt of this sequence + * (i.e., the last statement of the sequence loads + * a value into the accumulator, so we can eliminate + * earlier operations on the accumulator). + */ + ild->s.k += s->s.k; + s->s.code = NOP; + add->s.code = NOP; + tax->s.code = NOP; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + } + /* + * If the comparison at the end of a block is an equality + * comparison against a constant, and nobody uses the value + * we leave in the A register at the end of a block, and + * the operation preceding the comparison is an arithmetic + * operation, we can sometime optimize it away. + */ + if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) && + !ATOMELEM(b->out_use, A_ATOM)) { + /* + * We can optimize away certain subtractions of the + * X register. + */ + if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) { + val = b->val[X_ATOM]; + if (opt_state->vmap[val].is_const) { + /* + * If we have a subtract to do a comparison, + * and the X register is a known constant, + * we can merge this value into the + * comparison: + * + * sub x -> nop + * jeq #y jeq #(x+y) + */ + b->s.k += opt_state->vmap[val].const_val; + last->s.code = NOP; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } else if (b->s.k == 0) { + /* + * If the X register isn't a constant, + * and the comparison in the test is + * against 0, we can compare with the + * X register, instead: + * + * sub x -> nop + * jeq #0 jeq x + */ + last->s.code = NOP; + b->s.code = BPF_JMP|BPF_JEQ|BPF_X; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + } + /* + * Likewise, a constant subtract can be simplified: + * + * sub #x -> nop + * jeq #y -> jeq #(x+y) + */ + else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) { + last->s.code = NOP; + b->s.k += last->s.k; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + /* + * And, similarly, a constant AND can be simplified + * if we're testing against 0, i.e.: + * + * and #k nop + * jeq #0 -> jset #k + */ + else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) && + b->s.k == 0) { + b->s.k = last->s.k; + b->s.code = BPF_JMP|BPF_K|BPF_JSET; + last->s.code = NOP; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + opt_not(b); + } + } + /* + * jset #0 -> never + * jset #ffffffff -> always + */ + if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) { + if (b->s.k == 0) + JT(b) = JF(b); + if (b->s.k == 0xffffffffU) + JF(b) = JT(b); + } + /* + * If we're comparing against the index register, and the index + * register is a known constant, we can just compare against that + * constant. + */ + val = b->val[X_ATOM]; + if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) { + bpf_u_int32 v = opt_state->vmap[val].const_val; + b->s.code &= ~BPF_X; + b->s.k = v; + } + /* + * If the accumulator is a known constant, we can compute the + * comparison result. + */ + val = b->val[A_ATOM]; + if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) { + bpf_u_int32 v = opt_state->vmap[val].const_val; + switch (BPF_OP(b->s.code)) { + + case BPF_JEQ: + v = v == b->s.k; + break; + + case BPF_JGT: + v = v > b->s.k; + break; + + case BPF_JGE: + v = v >= b->s.k; + break; + + case BPF_JSET: + v &= b->s.k; + break; + + default: + abort(); + } + if (JF(b) != JT(b)) { + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + if (v) + JF(b) = JT(b); + else + JT(b) = JF(b); + } +} + +/* + * Compute the symbolic value of expression of 's', and update + * anything it defines in the value table 'val'. If 'alter' is true, + * do various optimizations. This code would be cleaner if symbolic + * evaluation and code transformations weren't folded together. + */ +static void +opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter) +{ + int op; + bpf_u_int32 v; + + switch (s->code) { + + case BPF_LD|BPF_ABS|BPF_W: + case BPF_LD|BPF_ABS|BPF_H: + case BPF_LD|BPF_ABS|BPF_B: + v = F(opt_state, s->code, s->k, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IND|BPF_W: + case BPF_LD|BPF_IND|BPF_H: + case BPF_LD|BPF_IND|BPF_B: + v = val[X_ATOM]; + if (alter && opt_state->vmap[v].is_const) { + s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code); + s->k += opt_state->vmap[v].const_val; + v = F(opt_state, s->code, s->k, 0L); + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + else + v = F(opt_state, s->code, s->k, v); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_LEN: + v = F(opt_state, s->code, 0L, 0L); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LD|BPF_IMM: + v = K(s->k); + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_LDX|BPF_IMM: + v = K(s->k); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_LDX|BPF_MSH|BPF_B: + v = F(opt_state, s->code, s->k, 0L); + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ALU|BPF_NEG: + if (alter && opt_state->vmap[val[A_ATOM]].is_const) { + s->code = BPF_LD|BPF_IMM; + /* + * Do this negation as unsigned arithmetic; that's + * what modern BPF engines do, and it guarantees + * that all possible values can be negated. (Yeah, + * negating 0x80000000, the minimum signed 32-bit + * two's-complement value, results in 0x80000000, + * so it's still negative, but we *should* be doing + * all unsigned arithmetic here, to match what + * modern BPF engines do.) + * + * Express it as 0U - (unsigned value) so that we + * don't get compiler warnings about negating an + * unsigned value and don't get UBSan warnings + * about the result of negating 0x80000000 being + * undefined. + */ + s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val; + val[A_ATOM] = K(s->k); + } + else + val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], 0L); + break; + + case BPF_ALU|BPF_ADD|BPF_K: + case BPF_ALU|BPF_SUB|BPF_K: + case BPF_ALU|BPF_MUL|BPF_K: + case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: + case BPF_ALU|BPF_AND|BPF_K: + case BPF_ALU|BPF_OR|BPF_K: + case BPF_ALU|BPF_XOR|BPF_K: + case BPF_ALU|BPF_LSH|BPF_K: + case BPF_ALU|BPF_RSH|BPF_K: + op = BPF_OP(s->code); + if (alter) { + if (s->k == 0) { + /* + * Optimize operations where the constant + * is zero. + * + * Don't optimize away "sub #0" + * as it may be needed later to + * fixup the generated math code. + * + * Fail if we're dividing by zero or taking + * a modulus by zero. + */ + if (op == BPF_ADD || + op == BPF_LSH || op == BPF_RSH || + op == BPF_OR || op == BPF_XOR) { + s->code = NOP; + break; + } + if (op == BPF_MUL || op == BPF_AND) { + s->code = BPF_LD|BPF_IMM; + val[A_ATOM] = K(s->k); + break; + } + if (op == BPF_DIV) + opt_error(opt_state, + "division by zero"); + if (op == BPF_MOD) + opt_error(opt_state, + "modulus by zero"); + } + if (opt_state->vmap[val[A_ATOM]].is_const) { + fold_op(opt_state, s, val[A_ATOM], K(s->k)); + val[A_ATOM] = K(s->k); + break; + } + } + val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k)); + break; + + case BPF_ALU|BPF_ADD|BPF_X: + case BPF_ALU|BPF_SUB|BPF_X: + case BPF_ALU|BPF_MUL|BPF_X: + case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: + case BPF_ALU|BPF_AND|BPF_X: + case BPF_ALU|BPF_OR|BPF_X: + case BPF_ALU|BPF_XOR|BPF_X: + case BPF_ALU|BPF_LSH|BPF_X: + case BPF_ALU|BPF_RSH|BPF_X: + op = BPF_OP(s->code); + if (alter && opt_state->vmap[val[X_ATOM]].is_const) { + if (opt_state->vmap[val[A_ATOM]].is_const) { + fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]); + val[A_ATOM] = K(s->k); + } + else { + s->code = BPF_ALU|BPF_K|op; + s->k = opt_state->vmap[val[X_ATOM]].const_val; + if ((op == BPF_LSH || op == BPF_RSH) && + s->k > 31) + opt_error(opt_state, + "shift by more than 31 bits"); + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + val[A_ATOM] = + F(opt_state, s->code, val[A_ATOM], K(s->k)); + } + break; + } + /* + * Check if we're doing something to an accumulator + * that is 0, and simplify. This may not seem like + * much of a simplification but it could open up further + * optimizations. + * XXX We could also check for mul by 1, etc. + */ + if (alter && opt_state->vmap[val[A_ATOM]].is_const + && opt_state->vmap[val[A_ATOM]].const_val == 0) { + if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) { + s->code = BPF_MISC|BPF_TXA; + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + } + else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD || + op == BPF_AND || op == BPF_LSH || op == BPF_RSH) { + s->code = BPF_LD|BPF_IMM; + s->k = 0; + vstore(s, &val[A_ATOM], K(s->k), alter); + break; + } + else if (op == BPF_NEG) { + s->code = NOP; + break; + } + } + val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]); + break; + + case BPF_MISC|BPF_TXA: + vstore(s, &val[A_ATOM], val[X_ATOM], alter); + break; + + case BPF_LD|BPF_MEM: + v = val[s->k]; + if (alter && opt_state->vmap[v].is_const) { + s->code = BPF_LD|BPF_IMM; + s->k = opt_state->vmap[v].const_val; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + vstore(s, &val[A_ATOM], v, alter); + break; + + case BPF_MISC|BPF_TAX: + vstore(s, &val[X_ATOM], val[A_ATOM], alter); + break; + + case BPF_LDX|BPF_MEM: + v = val[s->k]; + if (alter && opt_state->vmap[v].is_const) { + s->code = BPF_LDX|BPF_IMM; + s->k = opt_state->vmap[v].const_val; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + vstore(s, &val[X_ATOM], v, alter); + break; + + case BPF_ST: + vstore(s, &val[s->k], val[A_ATOM], alter); + break; + + case BPF_STX: + vstore(s, &val[s->k], val[X_ATOM], alter); + break; + } +} + +static void +deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[]) +{ + register int atom; + + atom = atomuse(s); + if (atom >= 0) { + if (atom == AX_ATOM) { + last[X_ATOM] = 0; + last[A_ATOM] = 0; + } + else + last[atom] = 0; + } + atom = atomdef(s); + if (atom >= 0) { + if (last[atom]) { + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + last[atom]->code = NOP; + } + last[atom] = s; + } +} + +static void +opt_deadstores(opt_state_t *opt_state, register struct block *b) +{ + register struct slist *s; + register int atom; + struct stmt *last[N_ATOMS]; + + memset((char *)last, 0, sizeof last); + + for (s = b->stmts; s != 0; s = s->next) + deadstmt(opt_state, &s->s, last); + deadstmt(opt_state, &b->s, last); + + for (atom = 0; atom < N_ATOMS; ++atom) + if (last[atom] && !ATOMELEM(b->out_use, atom)) { + last[atom]->code = NOP; + /* + * The store was removed as it's dead, + * so the value stored into now has + * an unknown value. + */ + vstore(0, &b->val[atom], VAL_UNKNOWN, 0); + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } +} + +static void +opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts) +{ + struct slist *s; + struct edge *p; + int i; + bpf_u_int32 aval, xval; + +#if 0 + for (s = b->stmts; s && s->next; s = s->next) + if (BPF_CLASS(s->s.code) == BPF_JMP) { + do_stmts = 0; + break; + } +#endif + + /* + * Initialize the atom values. + */ + p = b->in_edges; + if (p == 0) { + /* + * We have no predecessors, so everything is undefined + * upon entry to this block. + */ + memset((char *)b->val, 0, sizeof(b->val)); + } else { + /* + * Inherit values from our predecessors. + * + * First, get the values from the predecessor along the + * first edge leading to this node. + */ + memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val)); + /* + * Now look at all the other nodes leading to this node. + * If, for the predecessor along that edge, a register + * has a different value from the one we have (i.e., + * control paths are merging, and the merging paths + * assign different values to that register), give the + * register the undefined value of 0. + */ + while ((p = p->next) != NULL) { + for (i = 0; i < N_ATOMS; ++i) + if (b->val[i] != p->pred->val[i]) + b->val[i] = 0; + } + } + aval = b->val[A_ATOM]; + xval = b->val[X_ATOM]; + for (s = b->stmts; s; s = s->next) + opt_stmt(opt_state, &s->s, b->val, do_stmts); + + /* + * This is a special case: if we don't use anything from this + * block, and we load the accumulator or index register with a + * value that is already there, or if this block is a return, + * eliminate all the statements. + * + * XXX - what if it does a store? Presumably that falls under + * the heading of "if we don't use anything from this block", + * i.e., if we use any memory location set to a different + * value by this block, then we use something from this block. + * + * XXX - why does it matter whether we use anything from this + * block? If the accumulator or index register doesn't change + * its value, isn't that OK even if we use that value? + * + * XXX - if we load the accumulator with a different value, + * and the block ends with a conditional branch, we obviously + * can't eliminate it, as the branch depends on that value. + * For the index register, the conditional branch only depends + * on the index register value if the test is against the index + * register value rather than a constant; if nothing uses the + * value we put into the index register, and we're not testing + * against the index register's value, and there aren't any + * other problems that would keep us from eliminating this + * block, can we eliminate it? + */ + if (do_stmts && + ((b->out_use == 0 && + aval != VAL_UNKNOWN && b->val[A_ATOM] == aval && + xval != VAL_UNKNOWN && b->val[X_ATOM] == xval) || + BPF_CLASS(b->s.code) == BPF_RET)) { + if (b->stmts != 0) { + b->stmts = 0; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + } + } else { + opt_peep(opt_state, b); + opt_deadstores(opt_state, b); + } + /* + * Set up values for branch optimizer. + */ + if (BPF_SRC(b->s.code) == BPF_K) + b->oval = K(b->s.k); + else + b->oval = b->val[X_ATOM]; + b->et.code = b->s.code; + b->ef.code = -b->s.code; +} + +/* + * Return true if any register that is used on exit from 'succ', has + * an exit value that is different from the corresponding exit value + * from 'b'. + */ +static int +use_conflict(struct block *b, struct block *succ) +{ + int atom; + atomset use = succ->out_use; + + if (use == 0) + return 0; + + for (atom = 0; atom < N_ATOMS; ++atom) + if (ATOMELEM(use, atom)) + if (b->val[atom] != succ->val[atom]) + return 1; + return 0; +} + +/* + * Given a block that is the successor of an edge, and an edge that + * dominates that edge, return either a pointer to a child of that + * block (a block to which that block jumps) if that block is a + * candidate to replace the successor of the latter edge or NULL + * if neither of the children of the first block are candidates. + */ +static struct block * +fold_edge(struct block *child, struct edge *ep) +{ + int sense; + bpf_u_int32 aval0, aval1, oval0, oval1; + int code = ep->code; + + if (code < 0) { + /* + * This edge is a "branch if false" edge. + */ + code = -code; + sense = 0; + } else { + /* + * This edge is a "branch if true" edge. + */ + sense = 1; + } + + /* + * If the opcode for the branch at the end of the block we + * were handed isn't the same as the opcode for the branch + * to which the edge we were handed corresponds, the tests + * for those branches aren't testing the same conditions, + * so the blocks to which the first block branches aren't + * candidates to replace the successor of the edge. + */ + if (child->s.code != code) + return 0; + + aval0 = child->val[A_ATOM]; + oval0 = child->oval; + aval1 = ep->pred->val[A_ATOM]; + oval1 = ep->pred->oval; + + /* + * If the A register value on exit from the successor block + * isn't the same as the A register value on exit from the + * predecessor of the edge, the blocks to which the first + * block branches aren't candidates to replace the successor + * of the edge. + */ + if (aval0 != aval1) + return 0; + + if (oval0 == oval1) + /* + * The operands of the branch instructions are + * identical, so the branches are testing the + * same condition, and the result is true if a true + * branch was taken to get here, otherwise false. + */ + return sense ? JT(child) : JF(child); + + if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K)) + /* + * At this point, we only know the comparison if we + * came down the true branch, and it was an equality + * comparison with a constant. + * + * I.e., if we came down the true branch, and the branch + * was an equality comparison with a constant, we know the + * accumulator contains that constant. If we came down + * the false branch, or the comparison wasn't with a + * constant, we don't know what was in the accumulator. + * + * We rely on the fact that distinct constants have distinct + * value numbers. + */ + return JF(child); + + return 0; +} + +/* + * If we can make this edge go directly to a child of the edge's current + * successor, do so. + */ +static void +opt_j(opt_state_t *opt_state, struct edge *ep) +{ + register u_int i, k; + register struct block *target; + + /* + * Does this edge go to a block where, if the test + * at the end of it succeeds, it goes to a block + * that's a leaf node of the DAG, i.e. a return + * statement? + * If so, there's nothing to optimize. + */ + if (JT(ep->succ) == 0) + return; + + /* + * Does this edge go to a block that goes, in turn, to + * the same block regardless of whether the test at the + * end succeeds or fails? + */ + if (JT(ep->succ) == JF(ep->succ)) { + /* + * Common branch targets can be eliminated, provided + * there is no data dependency. + * + * Check whether any register used on exit from the + * block to which the successor of this edge goes + * has a value at that point that's different from + * the value it has on exit from the predecessor of + * this edge. If not, the predecessor of this edge + * can just go to the block to which the successor + * of this edge goes, bypassing the successor of this + * edge, as the successor of this edge isn't doing + * any calculations whose results are different + * from what the blocks before it did and isn't + * doing any tests the results of which matter. + */ + if (!use_conflict(ep->pred, JT(ep->succ))) { + /* + * No, there isn't. + * Make this edge go to the block to + * which the successor of that edge + * goes. + * + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 1; + opt_state->done = 0; + ep->succ = JT(ep->succ); + } + } + /* + * For each edge dominator that matches the successor of this + * edge, promote the edge successor to the its grandchild. + * + * XXX We violate the set abstraction here in favor a reasonably + * efficient loop. + */ + top: + for (i = 0; i < opt_state->edgewords; ++i) { + /* i'th word in the bitset of dominators */ + register bpf_u_int32 x = ep->edom[i]; + + while (x != 0) { + /* Find the next dominator in that word and mark it as found */ + k = lowest_set_bit(x); + x &=~ ((bpf_u_int32)1 << k); + k += i * BITS_PER_WORD; + + target = fold_edge(ep->succ, opt_state->edges[k]); + /* + * We have a candidate to replace the successor + * of ep. + * + * Check that there is no data dependency between + * nodes that will be violated if we move the edge; + * i.e., if any register used on exit from the + * candidate has a value at that point different + * from the value it has when we exit the + * predecessor of that edge, there's a data + * dependency that will be violated. + */ + if (target != 0 && !use_conflict(ep->pred, target)) { + /* + * It's safe to replace the successor of + * ep; do so, and note that we've made + * at least one change. + * + * XXX - this is one of the operations that + * happens when the optimizer gets into + * one of those infinite loops. + */ + opt_state->done = 0; + ep->succ = target; + if (JT(target) != 0) + /* + * Start over unless we hit a leaf. + */ + goto top; + return; + } + } + } +} + +/* + * XXX - is this, and and_pullup(), what's described in section 6.1.2 + * "Predicate Assertion Propagation" in the BPF+ paper? + * + * Note that this looks at block dominators, not edge dominators. + * Don't think so. + * + * "A or B" compiles into + * + * A + * t / \ f + * / B + * / t / \ f + * \ / + * \ / + * X + * + * + */ +static void +or_pullup(opt_state_t *opt_state, struct block *b, struct block *root) +{ + bpf_u_int32 val; + int at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + * XXX why? + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + /* + * For the first edge in the list of edges coming into this block, + * see whether the predecessor of that edge comes here via a true + * branch or a false branch. + */ + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); /* jt */ + else + diffp = &JF(b->in_edges->pred); /* jf */ + + /* + * diffp is a pointer to a pointer to the block. + * + * Go down the false chain looking as far as you can, + * making sure that each jump-compare is doing the + * same as the original block. + * + * If you reach the bottom before you reach a + * different jump-compare, just exit. There's nothing + * to do here. XXX - no, this version is checking for + * the value leaving the block; that's from the BPF+ + * pullup routine. + */ + at_top = 1; + for (;;) { + /* + * Done if that's not going anywhere XXX + */ + if (*diffp == 0) + return; + + /* + * Done if that predecessor blah blah blah isn't + * going the same place we're going XXX + * + * Does the true edge of this block point to the same + * location as the true edge of b? + */ + if (JT(*diffp) != JT(b)) + return; + + /* + * Done if this node isn't a dominator of that + * node blah blah blah XXX + * + * Does b dominate diffp? + */ + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + /* + * Break out of the loop if that node's value of A + * isn't the value of A above XXX + */ + if ((*diffp)->val[A_ATOM] != val) + break; + + /* + * Get the JF for that node XXX + * Go down the false path. + */ + diffp = &JF(*diffp); + at_top = 0; + } + + /* + * Now that we've found a different jump-compare in a chain + * below b, search further down until we find another + * jump-compare that looks at the original value. This + * jump-compare should get pulled up. XXX again we're + * comparing values not jump-compares. + */ + samep = &JF(*diffp); + for (;;) { + /* + * Done if that's not going anywhere XXX + */ + if (*samep == 0) + return; + + /* + * Done if that predecessor blah blah blah isn't + * going the same place we're going XXX + */ + if (JT(*samep) != JT(b)) + return; + + /* + * Done if this node isn't a dominator of that + * node blah blah blah XXX + * + * Does b dominate samep? + */ + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + /* + * Break out of the loop if that node's value of A + * is the value of A above XXX + */ + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between dp0 and dp1. Currently, the code generator + will not produce such dependencies. */ + samep = &JF(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JF(pull); + JF(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + /* + * XXX - this is one of the operations that happens when the + * optimizer gets into one of those infinite loops. + */ + opt_state->done = 0; + + /* + * Recompute dominator sets as control flow graph has changed. + */ + find_dom(opt_state, root); +} + +static void +and_pullup(opt_state_t *opt_state, struct block *b, struct block *root) +{ + bpf_u_int32 val; + int at_top; + struct block *pull; + struct block **diffp, **samep; + struct edge *ep; + + ep = b->in_edges; + if (ep == 0) + return; + + /* + * Make sure each predecessor loads the same value. + */ + val = ep->pred->val[A_ATOM]; + for (ep = ep->next; ep != 0; ep = ep->next) + if (val != ep->pred->val[A_ATOM]) + return; + + if (JT(b->in_edges->pred) == b) + diffp = &JT(b->in_edges->pred); + else + diffp = &JF(b->in_edges->pred); + + at_top = 1; + for (;;) { + if (*diffp == 0) + return; + + if (JF(*diffp) != JF(b)) + return; + + if (!SET_MEMBER((*diffp)->dom, b->id)) + return; + + if ((*diffp)->val[A_ATOM] != val) + break; + + diffp = &JT(*diffp); + at_top = 0; + } + samep = &JT(*diffp); + for (;;) { + if (*samep == 0) + return; + + if (JF(*samep) != JF(b)) + return; + + if (!SET_MEMBER((*samep)->dom, b->id)) + return; + + if ((*samep)->val[A_ATOM] == val) + break; + + /* XXX Need to check that there are no data dependencies + between diffp and samep. Currently, the code generator + will not produce such dependencies. */ + samep = &JT(*samep); + } +#ifdef notdef + /* XXX This doesn't cover everything. */ + for (i = 0; i < N_ATOMS; ++i) + if ((*samep)->val[i] != pred->val[i]) + return; +#endif + /* Pull up the node. */ + pull = *samep; + *samep = JT(pull); + JT(pull) = *diffp; + + /* + * At the top of the chain, each predecessor needs to point at the + * pulled up node. Inside the chain, there is only one predecessor + * to worry about. + */ + if (at_top) { + for (ep = b->in_edges; ep != 0; ep = ep->next) { + if (JT(ep->pred) == b) + JT(ep->pred) = pull; + else + JF(ep->pred) = pull; + } + } + else + *diffp = pull; + + /* + * XXX - this is one of the operations that happens when the + * optimizer gets into one of those infinite loops. + */ + opt_state->done = 0; + + /* + * Recompute dominator sets as control flow graph has changed. + */ + find_dom(opt_state, root); +} + +static void +opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts) +{ + int i, maxlevel; + struct block *p; + + init_val(opt_state); + maxlevel = ic->root->level; + + find_inedges(opt_state, ic->root); + for (i = maxlevel; i >= 0; --i) + for (p = opt_state->levels[i]; p; p = p->link) + opt_blk(opt_state, p, do_stmts); + + if (do_stmts) + /* + * No point trying to move branches; it can't possibly + * make a difference at this point. + * + * XXX - this might be after we detect a loop where + * we were just looping infinitely moving branches + * in such a fashion that we went through two or more + * versions of the machine code, eventually returning + * to the first version. (We're really not doing a + * full loop detection, we're just testing for two + * passes in a row where we do nothing but + * move branches.) + */ + return; + + /* + * Is this what the BPF+ paper describes in sections 6.1.1, + * 6.1.2, and 6.1.3? + */ + for (i = 1; i <= maxlevel; ++i) { + for (p = opt_state->levels[i]; p; p = p->link) { + opt_j(opt_state, &p->et); + opt_j(opt_state, &p->ef); + } + } + + find_inedges(opt_state, ic->root); + for (i = 1; i <= maxlevel; ++i) { + for (p = opt_state->levels[i]; p; p = p->link) { + or_pullup(opt_state, p, ic->root); + and_pullup(opt_state, p, ic->root); + } + } +} + +static inline void +link_inedge(struct edge *parent, struct block *child) +{ + parent->next = child->in_edges; + child->in_edges = parent; +} + +static void +find_inedges(opt_state_t *opt_state, struct block *root) +{ + u_int i; + int level; + struct block *b; + + for (i = 0; i < opt_state->n_blocks; ++i) + opt_state->blocks[i]->in_edges = 0; + + /* + * Traverse the graph, adding each edge to the predecessor + * list of its successors. Skip the leaves (i.e. level 0). + */ + for (level = root->level; level > 0; --level) { + for (b = opt_state->levels[level]; b != 0; b = b->link) { + link_inedge(&b->et, JT(b)); + link_inedge(&b->ef, JF(b)); + } + } +} + +static void +opt_root(struct block **b) +{ + struct slist *tmp, *s; + + s = (*b)->stmts; + (*b)->stmts = 0; + while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b)) + *b = JT(*b); + + tmp = (*b)->stmts; + if (tmp != 0) + sappend(s, tmp); + (*b)->stmts = s; + + /* + * If the root node is a return, then there is no + * point executing any statements (since the bpf machine + * has no side effects). + */ + if (BPF_CLASS((*b)->s.code) == BPF_RET) + (*b)->stmts = 0; +} + +static void +opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts) +{ + +#ifdef BDEBUG + if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { + printf("opt_loop(root, %d) begin\n", do_stmts); + opt_dump(opt_state, ic); + } +#endif + + /* + * XXX - optimizer loop detection. + */ + int loop_count = 0; + for (;;) { + opt_state->done = 1; + /* + * XXX - optimizer loop detection. + */ + opt_state->non_branch_movement_performed = 0; + find_levels(opt_state, ic); + find_dom(opt_state, ic->root); + find_closure(opt_state, ic->root); + find_ud(opt_state, ic->root); + find_edom(opt_state, ic->root); + opt_blks(opt_state, ic, do_stmts); +#ifdef BDEBUG + if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { + printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done); + opt_dump(opt_state, ic); + } +#endif + + /* + * Was anything done in this optimizer pass? + */ + if (opt_state->done) { + /* + * No, so we've reached a fixed point. + * We're done. + */ + break; + } + + /* + * XXX - was anything done other than branch movement + * in this pass? + */ + if (opt_state->non_branch_movement_performed) { + /* + * Yes. Clear any loop-detection counter; + * we're making some form of progress (assuming + * we can't get into a cycle doing *other* + * optimizations...). + */ + loop_count = 0; + } else { + /* + * No - increment the counter, and quit if + * it's up to 100. + */ + loop_count++; + if (loop_count >= 100) { + /* + * We've done nothing but branch movement + * for 100 passes; we're probably + * in a cycle and will never reach a + * fixed point. + * + * XXX - yes, we really need a non- + * heuristic way of detecting a cycle. + */ + opt_state->done = 1; + break; + } + } + } +} + +/* + * Optimize the filter code in its dag representation. + * Return 0 on success, -1 on error. + */ +int +bpf_optimize(struct icode *ic, char *errbuf) +{ + opt_state_t opt_state; + + memset(&opt_state, 0, sizeof(opt_state)); + opt_state.errbuf = errbuf; + opt_state.non_branch_movement_performed = 0; + if (setjmp(opt_state.top_ctx)) { + opt_cleanup(&opt_state); + return -1; + } + opt_init(&opt_state, ic); + opt_loop(&opt_state, ic, 0); + opt_loop(&opt_state, ic, 1); + intern_blocks(&opt_state, ic); +#ifdef BDEBUG + if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { + printf("after intern_blocks()\n"); + opt_dump(&opt_state, ic); + } +#endif + opt_root(&ic->root); +#ifdef BDEBUG + if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) { + printf("after opt_root()\n"); + opt_dump(&opt_state, ic); + } +#endif + opt_cleanup(&opt_state); + return 0; +} + +static void +make_marks(struct icode *ic, struct block *p) +{ + if (!isMarked(ic, p)) { + Mark(ic, p); + if (BPF_CLASS(p->s.code) != BPF_RET) { + make_marks(ic, JT(p)); + make_marks(ic, JF(p)); + } + } +} + +/* + * Mark code array such that isMarked(ic->cur_mark, i) is true + * only for nodes that are alive. + */ +static void +mark_code(struct icode *ic) +{ + ic->cur_mark += 1; + make_marks(ic, ic->root); +} + +/* + * True iff the two stmt lists load the same value from the packet into + * the accumulator. + */ +static int +eq_slist(struct slist *x, struct slist *y) +{ + for (;;) { + while (x && x->s.code == NOP) + x = x->next; + while (y && y->s.code == NOP) + y = y->next; + if (x == 0) + return y == 0; + if (y == 0) + return x == 0; + if (x->s.code != y->s.code || x->s.k != y->s.k) + return 0; + x = x->next; + y = y->next; + } +} + +static inline int +eq_blk(struct block *b0, struct block *b1) +{ + if (b0->s.code == b1->s.code && + b0->s.k == b1->s.k && + b0->et.succ == b1->et.succ && + b0->ef.succ == b1->ef.succ) + return eq_slist(b0->stmts, b1->stmts); + return 0; +} + +static void +intern_blocks(opt_state_t *opt_state, struct icode *ic) +{ + struct block *p; + u_int i, j; + int done1; /* don't shadow global */ + top: + done1 = 1; + for (i = 0; i < opt_state->n_blocks; ++i) + opt_state->blocks[i]->link = 0; + + mark_code(ic); + + for (i = opt_state->n_blocks - 1; i != 0; ) { + --i; + if (!isMarked(ic, opt_state->blocks[i])) + continue; + for (j = i + 1; j < opt_state->n_blocks; ++j) { + if (!isMarked(ic, opt_state->blocks[j])) + continue; + if (eq_blk(opt_state->blocks[i], opt_state->blocks[j])) { + opt_state->blocks[i]->link = opt_state->blocks[j]->link ? + opt_state->blocks[j]->link : opt_state->blocks[j]; + break; + } + } + } + for (i = 0; i < opt_state->n_blocks; ++i) { + p = opt_state->blocks[i]; + if (JT(p) == 0) + continue; + if (JT(p)->link) { + done1 = 0; + JT(p) = JT(p)->link; + } + if (JF(p)->link) { + done1 = 0; + JF(p) = JF(p)->link; + } + } + if (!done1) + goto top; +} + +static void +opt_cleanup(opt_state_t *opt_state) +{ + free((void *)opt_state->vnode_base); + free((void *)opt_state->vmap); + free((void *)opt_state->edges); + free((void *)opt_state->space); + free((void *)opt_state->levels); + free((void *)opt_state->blocks); +} + +/* + * For optimizer errors. + */ +static void PCAP_NORETURN +opt_error(opt_state_t *opt_state, const char *fmt, ...) +{ + va_list ap; + + if (opt_state->errbuf != NULL) { + va_start(ap, fmt); + (void)vsnprintf(opt_state->errbuf, + PCAP_ERRBUF_SIZE, fmt, ap); + va_end(ap); + } + longjmp(opt_state->top_ctx, 1); + /* NOTREACHED */ +#ifdef _AIX + PCAP_UNREACHABLE +#endif /* _AIX */ +} + +/* + * Return the number of stmts in 's'. + */ +static u_int +slength(struct slist *s) +{ + u_int n = 0; + + for (; s; s = s->next) + if (s->s.code != NOP) + ++n; + return n; +} + +/* + * Return the number of nodes reachable by 'p'. + * All nodes should be initially unmarked. + */ +static int +count_blocks(struct icode *ic, struct block *p) +{ + if (p == 0 || isMarked(ic, p)) + return 0; + Mark(ic, p); + return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1; +} + +/* + * Do a depth first search on the flow graph, numbering the + * the basic blocks, and entering them into the 'blocks' array.` + */ +static void +number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p) +{ + u_int n; + + if (p == 0 || isMarked(ic, p)) + return; + + Mark(ic, p); + n = opt_state->n_blocks++; + if (opt_state->n_blocks == 0) { + /* + * Overflow. + */ + opt_error(opt_state, "filter is too complex to optimize"); + } + p->id = n; + opt_state->blocks[n] = p; + + number_blks_r(opt_state, ic, JT(p)); + number_blks_r(opt_state, ic, JF(p)); +} + +/* + * Return the number of stmts in the flowgraph reachable by 'p'. + * The nodes should be unmarked before calling. + * + * Note that "stmts" means "instructions", and that this includes + * + * side-effect statements in 'p' (slength(p->stmts)); + * + * statements in the true branch from 'p' (count_stmts(JT(p))); + * + * statements in the false branch from 'p' (count_stmts(JF(p))); + * + * the conditional jump itself (1); + * + * an extra long jump if the true branch requires it (p->longjt); + * + * an extra long jump if the false branch requires it (p->longjf). + */ +static u_int +count_stmts(struct icode *ic, struct block *p) +{ + u_int n; + + if (p == 0 || isMarked(ic, p)) + return 0; + Mark(ic, p); + n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p)); + return slength(p->stmts) + n + 1 + p->longjt + p->longjf; +} + +/* + * Allocate memory. All allocation is done before optimization + * is begun. A linear bound on the size of all data structures is computed + * from the total number of blocks and/or statements. + */ +static void +opt_init(opt_state_t *opt_state, struct icode *ic) +{ + bpf_u_int32 *p; + int i, n, max_stmts; + u_int product; + size_t block_memsize, edge_memsize; + + /* + * First, count the blocks, so we can malloc an array to map + * block number to block. Then, put the blocks into the array. + */ + unMarkAll(ic); + n = count_blocks(ic, ic->root); + opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks)); + if (opt_state->blocks == NULL) + opt_error(opt_state, "malloc"); + unMarkAll(ic); + opt_state->n_blocks = 0; + number_blks_r(opt_state, ic, ic->root); + + /* + * This "should not happen". + */ + if (opt_state->n_blocks == 0) + opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue"); + + opt_state->n_edges = 2 * opt_state->n_blocks; + if ((opt_state->n_edges / 2) != opt_state->n_blocks) { + /* + * Overflow. + */ + opt_error(opt_state, "filter is too complex to optimize"); + } + opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges)); + if (opt_state->edges == NULL) { + opt_error(opt_state, "malloc"); + } + + /* + * The number of levels is bounded by the number of nodes. + */ + opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels)); + if (opt_state->levels == NULL) { + opt_error(opt_state, "malloc"); + } + + opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1; + opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1; + + /* + * Make sure opt_state->n_blocks * opt_state->nodewords fits + * in a u_int; we use it as a u_int number-of-iterations + * value. + */ + product = opt_state->n_blocks * opt_state->nodewords; + if ((product / opt_state->n_blocks) != opt_state->nodewords) { + /* + * XXX - just punt and don't try to optimize? + * In practice, this is unlikely to happen with + * a normal filter. + */ + opt_error(opt_state, "filter is too complex to optimize"); + } + + /* + * Make sure the total memory required for that doesn't + * overflow. + */ + block_memsize = (size_t)2 * product * sizeof(*opt_state->space); + if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) { + opt_error(opt_state, "filter is too complex to optimize"); + } + + /* + * Make sure opt_state->n_edges * opt_state->edgewords fits + * in a u_int; we use it as a u_int number-of-iterations + * value. + */ + product = opt_state->n_edges * opt_state->edgewords; + if ((product / opt_state->n_edges) != opt_state->edgewords) { + opt_error(opt_state, "filter is too complex to optimize"); + } + + /* + * Make sure the total memory required for that doesn't + * overflow. + */ + edge_memsize = (size_t)product * sizeof(*opt_state->space); + if (edge_memsize / product != sizeof(*opt_state->space)) { + opt_error(opt_state, "filter is too complex to optimize"); + } + + /* + * Make sure the total memory required for both of them doesn't + * overflow. + */ + if (block_memsize > SIZE_MAX - edge_memsize) { + opt_error(opt_state, "filter is too complex to optimize"); + } + + /* XXX */ + opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize); + if (opt_state->space == NULL) { + opt_error(opt_state, "malloc"); + } + p = opt_state->space; + opt_state->all_dom_sets = p; + for (i = 0; i < n; ++i) { + opt_state->blocks[i]->dom = p; + p += opt_state->nodewords; + } + opt_state->all_closure_sets = p; + for (i = 0; i < n; ++i) { + opt_state->blocks[i]->closure = p; + p += opt_state->nodewords; + } + opt_state->all_edge_sets = p; + for (i = 0; i < n; ++i) { + register struct block *b = opt_state->blocks[i]; + + b->et.edom = p; + p += opt_state->edgewords; + b->ef.edom = p; + p += opt_state->edgewords; + b->et.id = i; + opt_state->edges[i] = &b->et; + b->ef.id = opt_state->n_blocks + i; + opt_state->edges[opt_state->n_blocks + i] = &b->ef; + b->et.pred = b; + b->ef.pred = b; + } + max_stmts = 0; + for (i = 0; i < n; ++i) + max_stmts += slength(opt_state->blocks[i]->stmts) + 1; + /* + * We allocate at most 3 value numbers per statement, + * so this is an upper bound on the number of valnodes + * we'll need. + */ + opt_state->maxval = 3 * max_stmts; + opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap)); + if (opt_state->vmap == NULL) { + opt_error(opt_state, "malloc"); + } + opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base)); + if (opt_state->vnode_base == NULL) { + opt_error(opt_state, "malloc"); + } +} + +/* + * This is only used when supporting optimizer debugging. It is + * global state, so do *not* do more than one compile in parallel + * and expect it to provide meaningful information. + */ +#ifdef BDEBUG +int bids[NBIDS]; +#endif + +static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...) + PCAP_PRINTFLIKE(2, 3); + +/* + * Returns true if successful. Returns false if a branch has + * an offset that is too large. If so, we have marked that + * branch so that on a subsequent iteration, it will be treated + * properly. + */ +static int +convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p) +{ + struct bpf_insn *dst; + struct slist *src; + u_int slen; + u_int off; + struct slist **offset = NULL; + + if (p == 0 || isMarked(ic, p)) + return (1); + Mark(ic, p); + + if (convert_code_r(conv_state, ic, JF(p)) == 0) + return (0); + if (convert_code_r(conv_state, ic, JT(p)) == 0) + return (0); + + slen = slength(p->stmts); + dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf); + /* inflate length by any extra jumps */ + + p->offset = (int)(dst - conv_state->fstart); + + /* generate offset[] for convenience */ + if (slen) { + offset = (struct slist **)calloc(slen, sizeof(struct slist *)); + if (!offset) { + conv_error(conv_state, "not enough core"); + /*NOTREACHED*/ + } + } + src = p->stmts; + for (off = 0; off < slen && src; off++) { +#if 0 + printf("off=%d src=%x\n", off, src); +#endif + offset[off] = src; + src = src->next; + } + + off = 0; + for (src = p->stmts; src; src = src->next) { + if (src->s.code == NOP) + continue; + dst->code = (u_short)src->s.code; + dst->k = src->s.k; + + /* fill block-local relative jump */ + if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) { +#if 0 + if (src->s.jt || src->s.jf) { + free(offset); + conv_error(conv_state, "illegal jmp destination"); + /*NOTREACHED*/ + } +#endif + goto filled; + } + if (off == slen - 2) /*???*/ + goto filled; + + { + u_int i; + int jt, jf; + const char ljerr[] = "%s for block-local relative jump: off=%d"; + +#if 0 + printf("code=%x off=%d %x %x\n", src->s.code, + off, src->s.jt, src->s.jf); +#endif + + if (!src->s.jt || !src->s.jf) { + free(offset); + conv_error(conv_state, ljerr, "no jmp destination", off); + /*NOTREACHED*/ + } + + jt = jf = 0; + for (i = 0; i < slen; i++) { + if (offset[i] == src->s.jt) { + if (jt) { + free(offset); + conv_error(conv_state, ljerr, "multiple matches", off); + /*NOTREACHED*/ + } + + if (i - off - 1 >= 256) { + free(offset); + conv_error(conv_state, ljerr, "out-of-range jump", off); + /*NOTREACHED*/ + } + dst->jt = (u_char)(i - off - 1); + jt++; + } + if (offset[i] == src->s.jf) { + if (jf) { + free(offset); + conv_error(conv_state, ljerr, "multiple matches", off); + /*NOTREACHED*/ + } + if (i - off - 1 >= 256) { + free(offset); + conv_error(conv_state, ljerr, "out-of-range jump", off); + /*NOTREACHED*/ + } + dst->jf = (u_char)(i - off - 1); + jf++; + } + } + if (!jt || !jf) { + free(offset); + conv_error(conv_state, ljerr, "no destination found", off); + /*NOTREACHED*/ + } + } +filled: + ++dst; + ++off; + } + if (offset) + free(offset); + +#ifdef BDEBUG + if (dst - conv_state->fstart < NBIDS) + bids[dst - conv_state->fstart] = p->id + 1; +#endif + dst->code = (u_short)p->s.code; + dst->k = p->s.k; + if (JT(p)) { + /* number of extra jumps inserted */ + u_char extrajmps = 0; + off = JT(p)->offset - (p->offset + slen) - 1; + if (off >= 256) { + /* offset too large for branch, must add a jump */ + if (p->longjt == 0) { + /* mark this instruction and retry */ + p->longjt++; + return(0); + } + dst->jt = extrajmps; + extrajmps++; + dst[extrajmps].code = BPF_JMP|BPF_JA; + dst[extrajmps].k = off - extrajmps; + } + else + dst->jt = (u_char)off; + off = JF(p)->offset - (p->offset + slen) - 1; + if (off >= 256) { + /* offset too large for branch, must add a jump */ + if (p->longjf == 0) { + /* mark this instruction and retry */ + p->longjf++; + return(0); + } + /* branch if F to following jump */ + /* if two jumps are inserted, F goes to second one */ + dst->jf = extrajmps; + extrajmps++; + dst[extrajmps].code = BPF_JMP|BPF_JA; + dst[extrajmps].k = off - extrajmps; + } + else + dst->jf = (u_char)off; + } + return (1); +} + + +/* + * Convert flowgraph intermediate representation to the + * BPF array representation. Set *lenp to the number of instructions. + * + * This routine does *NOT* leak the memory pointed to by fp. It *must + * not* do free(fp) before returning fp; doing so would make no sense, + * as the BPF array pointed to by the return value of icode_to_fcode() + * must be valid - it's being returned for use in a bpf_program structure. + * + * If it appears that icode_to_fcode() is leaking, the problem is that + * the program using pcap_compile() is failing to free the memory in + * the BPF program when it's done - the leak is in the program, not in + * the routine that happens to be allocating the memory. (By analogy, if + * a program calls fopen() without ever calling fclose() on the FILE *, + * it will leak the FILE structure; the leak is not in fopen(), it's in + * the program.) Change the program to use pcap_freecode() when it's + * done with the filter program. See the pcap man page. + */ +struct bpf_insn * +icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp, + char *errbuf) +{ + u_int n; + struct bpf_insn *fp; + conv_state_t conv_state; + + conv_state.fstart = NULL; + conv_state.errbuf = errbuf; + if (setjmp(conv_state.top_ctx) != 0) { + free(conv_state.fstart); + return NULL; + } + + /* + * Loop doing convert_code_r() until no branches remain + * with too-large offsets. + */ + for (;;) { + unMarkAll(ic); + n = *lenp = count_stmts(ic, root); + + fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); + if (fp == NULL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc"); + return NULL; + } + memset((char *)fp, 0, sizeof(*fp) * n); + conv_state.fstart = fp; + conv_state.ftail = fp + n; + + unMarkAll(ic); + if (convert_code_r(&conv_state, ic, root)) + break; + free(fp); + } + + return fp; +} + +/* + * For iconv_to_fconv() errors. + */ +static void PCAP_NORETURN +conv_error(conv_state_t *conv_state, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)vsnprintf(conv_state->errbuf, + PCAP_ERRBUF_SIZE, fmt, ap); + va_end(ap); + longjmp(conv_state->top_ctx, 1); + /* NOTREACHED */ +#ifdef _AIX + PCAP_UNREACHABLE +#endif /* _AIX */ +} + +/* + * Make a copy of a BPF program and put it in the "fcode" member of + * a "pcap_t". + * + * If we fail to allocate memory for the copy, fill in the "errbuf" + * member of the "pcap_t" with an error message, and return -1; + * otherwise, return 0. + */ +int +pcapint_install_bpf_program(pcap_t *p, struct bpf_program *fp) +{ + size_t prog_size; + + /* + * Validate the program. + */ + if (!pcapint_validate_filter(fp->bf_insns, fp->bf_len)) { + snprintf(p->errbuf, sizeof(p->errbuf), + "BPF program is not valid"); + return (-1); + } + + /* + * Free up any already installed program. + */ + pcap_freecode(&p->fcode); + + prog_size = sizeof(*fp->bf_insns) * fp->bf_len; + p->fcode.bf_len = fp->bf_len; + p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); + if (p->fcode.bf_insns == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (-1); + } + memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size); + return (0); +} + +#ifdef BDEBUG +static void +dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog, + FILE *out) +{ + int icount, noffset; + int i; + + if (block == NULL || isMarked(ic, block)) + return; + Mark(ic, block); + + icount = slength(block->stmts) + 1 + block->longjt + block->longjf; + noffset = min(block->offset + icount, (int)prog->bf_len); + + fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id); + for (i = block->offset; i < noffset; i++) { + fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i)); + } + fprintf(out, "\" tooltip=\""); + for (i = 0; i < BPF_MEMWORDS; i++) + if (block->val[i] != VAL_UNKNOWN) + fprintf(out, "val[%d]=%d ", i, block->val[i]); + fprintf(out, "val[A]=%d ", block->val[A_ATOM]); + fprintf(out, "val[X]=%d", block->val[X_ATOM]); + fprintf(out, "\""); + if (JT(block) == NULL) + fprintf(out, ", peripheries=2"); + fprintf(out, "];\n"); + + dot_dump_node(ic, JT(block), prog, out); + dot_dump_node(ic, JF(block), prog, out); +} + +static void +dot_dump_edge(struct icode *ic, struct block *block, FILE *out) +{ + if (block == NULL || isMarked(ic, block)) + return; + Mark(ic, block); + + if (JT(block)) { + fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n", + block->id, JT(block)->id); + fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n", + block->id, JF(block)->id); + } + dot_dump_edge(ic, JT(block), out); + dot_dump_edge(ic, JF(block), out); +} + +/* Output the block CFG using graphviz/DOT language + * In the CFG, block's code, value index for each registers at EXIT, + * and the jump relationship is show. + * + * example DOT for BPF `ip src host 1.1.1.1' is: + digraph BPF { + block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh [12]\n(001) jeq #0x800 jt 2 jf 5" tooltip="val[A]=0 val[X]=0"]; + block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld [26]\n(003) jeq #0x1010101 jt 4 jf 5" tooltip="val[A]=0 val[X]=0"]; + block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2]; + block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2]; + "block0":se -> "block1":n [label="T"]; + "block0":sw -> "block3":n [label="F"]; + "block1":se -> "block2":n [label="T"]; + "block1":sw -> "block3":n [label="F"]; + } + * + * After install graphviz on https://www.graphviz.org/, save it as bpf.dot + * and run `dot -Tpng -O bpf.dot' to draw the graph. + */ +static int +dot_dump(struct icode *ic, char *errbuf) +{ + struct bpf_program f; + FILE *out = stdout; + + memset(bids, 0, sizeof bids); + f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); + if (f.bf_insns == NULL) + return -1; + + fprintf(out, "digraph BPF {\n"); + unMarkAll(ic); + dot_dump_node(ic, ic->root, &f, out); + unMarkAll(ic); + dot_dump_edge(ic, ic->root, out); + fprintf(out, "}\n"); + + free((char *)f.bf_insns); + return 0; +} + +static int +plain_dump(struct icode *ic, char *errbuf) +{ + struct bpf_program f; + + memset(bids, 0, sizeof bids); + f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf); + if (f.bf_insns == NULL) + return -1; + bpf_dump(&f, 1); + putchar('\n'); + free((char *)f.bf_insns); + return 0; +} + +static void +opt_dump(opt_state_t *opt_state, struct icode *ic) +{ + int status; + char errbuf[PCAP_ERRBUF_SIZE]; + + /* + * If the CFG, in DOT format, is requested, output it rather than + * the code that would be generated from that graph. + */ + if (pcap_print_dot_graph) + status = dot_dump(ic, errbuf); + else + status = plain_dump(ic, errbuf); + if (status == -1) + opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf); +} +#endif diff --git a/src/libpcap-1.10.5/optimize.h b/src/libpcap-1.10.5/optimize.h new file mode 100644 index 0000000000..56b31f40c8 --- /dev/null +++ b/src/libpcap-1.10.5/optimize.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Some stuff for use when debugging the optimizer. + */ +#ifdef BDEBUG +#define NBIDS 1000 +extern int bids[NBIDS]; +#endif diff --git a/src/libpcap-1.10.5/org.tcpdump.chmod_bpf.plist b/src/libpcap-1.10.5/org.tcpdump.chmod_bpf.plist new file mode 100644 index 0000000000..f6fdfec77f --- /dev/null +++ b/src/libpcap-1.10.5/org.tcpdump.chmod_bpf.plist @@ -0,0 +1,16 @@ + + + + + Label + org.tcpdump.chmod_bpf + RunAtLoad + + Program + /usr/local/bin/chmod_bpf + ProgramArguments + + /usr/local/bin/chmod_bpf + + + diff --git a/src/libpcap-1.10.5/pcap-airpcap.c b/src/libpcap-1.10.5/pcap-airpcap.c new file mode 100644 index 0000000000..6d5d250877 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-airpcap.c @@ -0,0 +1,1055 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "pcap-int.h" + +#include + +#include "pcap-airpcap.h" + +/* Default size of the buffer we allocate in userland. */ +#define AIRPCAP_DEFAULT_USER_BUFFER_SIZE 256000 + +/* Default size of the buffer for the AirPcap adapter. */ +#define AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE 1000000 + +// +// We load the AirPcap DLL dynamically, so that the code will +// work whether you have it installed or not, and there don't +// have to be two different versions of the library, one linked +// to the AirPcap library and one not linked to it. +// +static pcap_code_handle_t airpcap_lib; + +typedef PCHAR (*AirpcapGetLastErrorHandler)(PAirpcapHandle); +typedef BOOL (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *, PCHAR); +typedef VOID (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription); +typedef PAirpcapHandle (*AirpcapOpenHandler)(PCHAR, PCHAR); +typedef VOID (*AirpcapCloseHandler)(PAirpcapHandle); +typedef BOOL (*AirpcapSetDeviceMacFlagsHandler)(PAirpcapHandle, UINT); +typedef BOOL (*AirpcapSetLinkTypeHandler)(PAirpcapHandle, AirpcapLinkType); +typedef BOOL (*AirpcapGetLinkTypeHandler)(PAirpcapHandle, PAirpcapLinkType); +typedef BOOL (*AirpcapSetKernelBufferHandler)(PAirpcapHandle, UINT); +typedef BOOL (*AirpcapSetFilterHandler)(PAirpcapHandle, PVOID, UINT); +typedef BOOL (*AirpcapSetMinToCopyHandler)(PAirpcapHandle, UINT); +typedef BOOL (*AirpcapGetReadEventHandler)(PAirpcapHandle, HANDLE *); +typedef BOOL (*AirpcapReadHandler)(PAirpcapHandle, PBYTE, UINT, PUINT); +typedef BOOL (*AirpcapWriteHandler)(PAirpcapHandle, PCHAR, ULONG); +typedef BOOL (*AirpcapGetStatsHandler)(PAirpcapHandle, PAirpcapStats); + +static AirpcapGetLastErrorHandler p_AirpcapGetLastError; +static AirpcapGetDeviceListHandler p_AirpcapGetDeviceList; +static AirpcapFreeDeviceListHandler p_AirpcapFreeDeviceList; +static AirpcapOpenHandler p_AirpcapOpen; +static AirpcapCloseHandler p_AirpcapClose; +static AirpcapSetDeviceMacFlagsHandler p_AirpcapSetDeviceMacFlags; +static AirpcapSetLinkTypeHandler p_AirpcapSetLinkType; +static AirpcapGetLinkTypeHandler p_AirpcapGetLinkType; +static AirpcapSetKernelBufferHandler p_AirpcapSetKernelBuffer; +static AirpcapSetFilterHandler p_AirpcapSetFilter; +static AirpcapSetMinToCopyHandler p_AirpcapSetMinToCopy; +static AirpcapGetReadEventHandler p_AirpcapGetReadEvent; +static AirpcapReadHandler p_AirpcapRead; +static AirpcapWriteHandler p_AirpcapWrite; +static AirpcapGetStatsHandler p_AirpcapGetStats; + +typedef enum LONG +{ + AIRPCAP_API_UNLOADED = 0, + AIRPCAP_API_LOADED, + AIRPCAP_API_CANNOT_LOAD, + AIRPCAP_API_LOADING +} AIRPCAP_API_LOAD_STATUS; + +static AIRPCAP_API_LOAD_STATUS airpcap_load_status; + +/* + * NOTE: this function should be called by the pcap functions that can + * theoretically deal with the AirPcap library for the first time, + * namely listing the adapters and creating a pcap_t for an adapter. + * All the other ones (activate, close, read, write, set parameters) + * work on a pcap_t for an AirPcap device, meaning we've already + * created the pcap_t and thus have loaded the functions, so we do + * not need to call this function. + */ +static AIRPCAP_API_LOAD_STATUS +load_airpcap_functions(void) +{ + AIRPCAP_API_LOAD_STATUS current_status; + + /* + * We don't use a mutex because there's no place that + * we can guarantee we'll be called before any threads + * other than the main thread exists. (For example, + * this might be a static library, so we can't arrange + * to be called by DllMain(), and there's no guarantee + * that the application called pcap_init() - which is + * supposed to be called only from one thread - so + * we can't arrange to be called from it.) + * + * If nobody's tried to load it yet, mark it as + * loading; in any case, return the status before + * we modified it. + */ + current_status = InterlockedCompareExchange((LONG *)&airpcap_load_status, + AIRPCAP_API_LOADING, AIRPCAP_API_UNLOADED); + + /* + * If the status was AIRPCAP_API_UNLOADED, we've set it + * to AIRPCAP_API_LOADING, because we're going to be + * the ones to load the library but current_status is + * AIRPCAP_API_UNLOADED. + * + * if it was AIRPCAP_API_LOADING, meaning somebody else + * was trying to load it, spin until they finish and + * set the status to a value reflecting whether they + * succeeded. + */ + while (current_status == AIRPCAP_API_LOADING) { + current_status = InterlockedCompareExchange((LONG*)&airpcap_load_status, + AIRPCAP_API_LOADING, AIRPCAP_API_LOADING); + Sleep(10); + } + + /* + * At this point, current_status is either: + * + * AIRPCAP_API_LOADED, in which case another thread + * loaded the library, so we're done; + * + * AIRPCAP_API_CANNOT_LOAD, in which another thread + * tried and failed to load the library, so we're + * done - we won't try it ourselves; + * + * AIRPCAP_API_LOADING, in which case *we're* the + * ones loading it, and should now try to do so. + */ + if (current_status == AIRPCAP_API_LOADED) + return AIRPCAP_API_LOADED; + + if (current_status == AIRPCAP_API_CANNOT_LOAD) + return AIRPCAP_API_CANNOT_LOAD; + + /* + * Start out assuming we can't load it. + */ + current_status = AIRPCAP_API_CANNOT_LOAD; + + airpcap_lib = pcapint_load_code("airpcap.dll"); + if (airpcap_lib != NULL) { + /* + * OK, we've loaded the library; now try to find the + * functions we need in it. + */ + p_AirpcapGetLastError = (AirpcapGetLastErrorHandler) pcapint_find_function(airpcap_lib, "AirpcapGetLastError"); + p_AirpcapGetDeviceList = (AirpcapGetDeviceListHandler) pcapint_find_function(airpcap_lib, "AirpcapGetDeviceList"); + p_AirpcapFreeDeviceList = (AirpcapFreeDeviceListHandler) pcapint_find_function(airpcap_lib, "AirpcapFreeDeviceList"); + p_AirpcapOpen = (AirpcapOpenHandler) pcapint_find_function(airpcap_lib, "AirpcapOpen"); + p_AirpcapClose = (AirpcapCloseHandler) pcapint_find_function(airpcap_lib, "AirpcapClose"); + p_AirpcapSetDeviceMacFlags = (AirpcapSetDeviceMacFlagsHandler) pcapint_find_function(airpcap_lib, "AirpcapSetDeviceMacFlags"); + p_AirpcapSetLinkType = (AirpcapSetLinkTypeHandler) pcapint_find_function(airpcap_lib, "AirpcapSetLinkType"); + p_AirpcapGetLinkType = (AirpcapGetLinkTypeHandler) pcapint_find_function(airpcap_lib, "AirpcapGetLinkType"); + p_AirpcapSetKernelBuffer = (AirpcapSetKernelBufferHandler) pcapint_find_function(airpcap_lib, "AirpcapSetKernelBuffer"); + p_AirpcapSetFilter = (AirpcapSetFilterHandler) pcapint_find_function(airpcap_lib, "AirpcapSetFilter"); + p_AirpcapSetMinToCopy = (AirpcapSetMinToCopyHandler) pcapint_find_function(airpcap_lib, "AirpcapSetMinToCopy"); + p_AirpcapGetReadEvent = (AirpcapGetReadEventHandler) pcapint_find_function(airpcap_lib, "AirpcapGetReadEvent"); + p_AirpcapRead = (AirpcapReadHandler) pcapint_find_function(airpcap_lib, "AirpcapRead"); + p_AirpcapWrite = (AirpcapWriteHandler) pcapint_find_function(airpcap_lib, "AirpcapWrite"); + p_AirpcapGetStats = (AirpcapGetStatsHandler) pcapint_find_function(airpcap_lib, "AirpcapGetStats"); + + // + // Make sure that we found everything + // + if (p_AirpcapGetLastError != NULL && + p_AirpcapGetDeviceList != NULL && + p_AirpcapFreeDeviceList != NULL && + p_AirpcapOpen != NULL && + p_AirpcapClose != NULL && + p_AirpcapSetDeviceMacFlags != NULL && + p_AirpcapSetLinkType != NULL && + p_AirpcapGetLinkType != NULL && + p_AirpcapSetKernelBuffer != NULL && + p_AirpcapSetFilter != NULL && + p_AirpcapSetMinToCopy != NULL && + p_AirpcapGetReadEvent != NULL && + p_AirpcapRead != NULL && + p_AirpcapWrite != NULL && + p_AirpcapGetStats != NULL) { + /* + * We have all we need. + */ + current_status = AIRPCAP_API_LOADED; + } + } + + if (current_status != AIRPCAP_API_LOADED) { + /* + * We failed; if we found the DLL, close the + * handle for it. + */ + if (airpcap_lib != NULL) { + FreeLibrary(airpcap_lib); + airpcap_lib = NULL; + } + } + + /* + * Now set the status appropriately - and atomically. + */ + InterlockedExchange((LONG *)&airpcap_load_status, current_status); + + return current_status; +} + +/* + * Private data for capturing on AirPcap devices. + */ +struct pcap_airpcap { + PAirpcapHandle adapter; + int filtering_in_kernel; + int nonblock; + int read_timeout; + HANDLE read_event; + struct pcap_stat stat; +}; + +static int +airpcap_setfilter(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_airpcap *pa = p->priv; + + if (!p_AirpcapSetFilter(pa->adapter, fp->bf_insns, + fp->bf_len * sizeof(struct bpf_insn))) { + /* + * Kernel filter not installed. + * + * XXX - we don't know whether this failed because: + * + * the kernel rejected the filter program as invalid, + * in which case we should fall back on userland + * filtering; + * + * the kernel rejected the filter program as too big, + * in which case we should again fall back on + * userland filtering; + * + * there was some other problem, in which case we + * should probably report an error; + * + * So we just fall back on userland filtering in + * all cases. + */ + + /* + * pcapint_install_bpf_program() validates the program. + * + * XXX - what if we already have a filter in the kernel? + */ + if (pcapint_install_bpf_program(p, fp) < 0) + return (-1); + pa->filtering_in_kernel = 0; /* filtering in userland */ + return (0); + } + + /* + * It worked. + */ + pa->filtering_in_kernel = 1; /* filtering in the kernel */ + + /* + * Discard any previously-received packets, as they might have + * passed whatever filter was formerly in effect, but might + * not pass this filter (BIOCSETF discards packets buffered + * in the kernel, so you can lose packets in any case). + */ + p->cc = 0; + return (0); +} + +static int +airpcap_set_datalink(pcap_t *p, int dlt) +{ + struct pcap_airpcap *pa = p->priv; + AirpcapLinkType type; + + switch (dlt) { + + case DLT_IEEE802_11_RADIO: + type = AIRPCAP_LT_802_11_PLUS_RADIO; + break; + + case DLT_PPI: + type = AIRPCAP_LT_802_11_PLUS_PPI; + break; + + case DLT_IEEE802_11: + type = AIRPCAP_LT_802_11; + break; + + default: + /* This can't happen; just return. */ + return (0); + } + if (!p_AirpcapSetLinkType(pa->adapter, type)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetLinkType() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + p->linktype = dlt; + return (0); +} + +static int +airpcap_getnonblock(pcap_t *p) +{ + struct pcap_airpcap *pa = p->priv; + + return (pa->nonblock); +} + +static int +airpcap_setnonblock(pcap_t *p, int nonblock) +{ + struct pcap_airpcap *pa = p->priv; + int newtimeout; + + if (nonblock) { + /* + * Set the packet buffer timeout to -1 for non-blocking + * mode. + */ + newtimeout = -1; + } else { + /* + * Restore the timeout set when the device was opened. + * (Note that this may be -1, in which case we're not + * really leaving non-blocking mode. However, although + * the timeout argument to pcap_set_timeout() and + * pcap_open_live() is an int, you're not supposed to + * supply a negative value, so that "shouldn't happen".) + */ + newtimeout = p->opt.timeout; + } + pa->read_timeout = newtimeout; + pa->nonblock = (newtimeout == -1); + return (0); +} + +static int +airpcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_airpcap *pa = p->priv; + AirpcapStats tas; + + /* + * Try to get statistics. + */ + if (!p_AirpcapGetStats(pa->adapter, &tas)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetStats() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + + ps->ps_drop = tas.Drops; + ps->ps_recv = tas.Recvs; + ps->ps_ifdrop = tas.IfDrops; + + return (0); +} + +/* + * Win32-only routine for getting statistics. + * + * This way is definitely safer than passing the pcap_stat * from the userland. + * In fact, there could happen than the user allocates a variable which is not + * big enough for the new structure, and the library will write in a zone + * which is not allocated to this variable. + * + * In this way, we're pretty sure we are writing on memory allocated to this + * variable. + * + * XXX - but this is the wrong way to handle statistics. Instead, we should + * have an API that returns data in a form like the Options section of a + * pcapng Interface Statistics Block: + * + * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6 + * + * which would let us add new statistics straightforwardly and indicate which + * statistics we are and are *not* providing, rather than having to provide + * possibly-bogus values for statistics we can't provide. + */ +static struct pcap_stat * +airpcap_stats_ex(pcap_t *p, int *pcap_stat_size) +{ + struct pcap_airpcap *pa = p->priv; + AirpcapStats tas; + + *pcap_stat_size = sizeof (p->stat); + + /* + * Try to get statistics. + */ + if (!p_AirpcapGetStats(pa->adapter, &tas)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetStats() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (NULL); + } + + p->stat.ps_recv = tas.Recvs; + p->stat.ps_drop = tas.Drops; + p->stat.ps_ifdrop = tas.IfDrops; + /* + * Just in case this is ever compiled for a target other than + * Windows, which is extremely unlikely at best. + */ +#ifdef _WIN32 + p->stat.ps_capt = tas.Capt; +#endif + return (&p->stat); +} + +/* Set the dimension of the kernel-level capture buffer */ +static int +airpcap_setbuff(pcap_t *p, int dim) +{ + struct pcap_airpcap *pa = p->priv; + + if (!p_AirpcapSetKernelBuffer(pa->adapter, dim)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetKernelBuffer() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + return (0); +} + +/* Set the driver working mode */ +static int +airpcap_setmode(pcap_t *p, int mode) +{ + if (mode != MODE_CAPT) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Only MODE_CAPT is supported on an AirPcap adapter"); + return (-1); + } + return (0); +} + +/*set the minimum amount of data that will release a read call*/ +static int +airpcap_setmintocopy(pcap_t *p, int size) +{ + struct pcap_airpcap *pa = p->priv; + + if (!p_AirpcapSetMinToCopy(pa->adapter, size)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetMinToCopy() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + return (0); +} + +static HANDLE +airpcap_getevent(pcap_t *p) +{ + struct pcap_airpcap *pa = p->priv; + + return (pa->read_event); +} + +static int +airpcap_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Getting OID values is not supported on an AirPcap adapter"); + return (PCAP_ERROR); +} + +static int +airpcap_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Setting OID values is not supported on an AirPcap adapter"); + return (PCAP_ERROR); +} + +static u_int +airpcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Cannot queue packets for transmission on an AirPcap adapter"); + return (0); +} + +static int +airpcap_setuserbuffer(pcap_t *p, int size) +{ + unsigned char *new_buff; + + if (size <= 0) { + /* Bogus parameter */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error: invalid size %d",size); + return (-1); + } + + /* Allocate the buffer */ + new_buff = (unsigned char *)malloc(sizeof(char)*size); + + if (!new_buff) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error: not enough memory"); + return (-1); + } + + free(p->buffer); + + p->buffer = new_buff; + p->bufsize = size; + + return (0); +} + +static int +airpcap_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_, + int maxpacks _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirPcap adapters don't support live dump"); + return (-1); +} + +static int +airpcap_live_dump_ended(pcap_t *p, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirPcap adapters don't support live dump"); + return (-1); +} + +static PAirpcapHandle +airpcap_get_airpcap_handle(pcap_t *p) +{ + struct pcap_airpcap *pa = p->priv; + + return (pa->adapter); +} + +static int +airpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_airpcap *pa = p->priv; + int cc; + int n; + register u_char *bp, *ep; + UINT bytes_read; + u_char *datap; + + cc = p->cc; + if (cc == 0) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + + // + // If we're not in non-blocking mode, wait for data to + // arrive. + // + if (pa->read_timeout != -1) { + WaitForSingleObject(pa->read_event, + (pa->read_timeout ==0 )? INFINITE: pa->read_timeout); + } + + // + // Read the data. + // p_AirpcapRead doesn't block. + // + if (!p_AirpcapRead(pa->adapter, (PBYTE)p->buffer, + p->bufsize, &bytes_read)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapRead() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + cc = bytes_read; + bp = (u_char *)p->buffer; + } else + bp = p->bp; + + /* + * Loop through each packet. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ +#define bhp ((AirpcapBpfHeader *)bp) + n = 0; + ep = bp + cc; + for (;;) { + register u_int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } else { + p->bp = bp; + p->cc = (int) (ep - bp); + return (n); + } + } + if (bp >= ep) + break; + + caplen = bhp->Caplen; + hdrlen = bhp->Hdrlen; + datap = bp + hdrlen; + /* + * Short-circuit evaluation: if using BPF filter + * in the AirPcap adapter, no need to do it now - + * we already know the packet passed the filter. + */ + if (pa->filtering_in_kernel || + p->fcode.bf_insns == NULL || + pcapint_filter(p->fcode.bf_insns, datap, bhp->Originallen, caplen)) { + struct pcap_pkthdr pkthdr; + + pkthdr.ts.tv_sec = bhp->TsSec; + pkthdr.ts.tv_usec = bhp->TsUsec; + pkthdr.caplen = caplen; + pkthdr.len = bhp->Originallen; + (*callback)(user, &pkthdr, datap); + bp += AIRPCAP_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->bp = bp; + p->cc = (int)(ep - bp); + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += AIRPCAP_WORDALIGN(caplen + hdrlen); + } + } +#undef bhp + p->cc = 0; + return (n); +} + +static int +airpcap_inject(pcap_t *p, const void *buf, int size) +{ + struct pcap_airpcap *pa = p->priv; + + /* + * XXX - the second argument to AirpcapWrite() *should* have + * been declared as a const pointer - a write function that + * stomps on what it writes is *extremely* rude - but such + * is life. We assume it is, in fact, not going to write on + * our buffer. + */ + if (!p_AirpcapWrite(pa->adapter, (void *)buf, size)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapWrite() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (-1); + } + + /* + * We assume it all got sent if "AirpcapWrite()" succeeded. + * "pcap_inject()" is expected to return the number of bytes + * sent. + */ + return (size); +} + +static void +airpcap_cleanup(pcap_t *p) +{ + struct pcap_airpcap *pa = p->priv; + + if (pa->adapter != NULL) { + p_AirpcapClose(pa->adapter); + pa->adapter = NULL; + } + pcapint_cleanup_live_common(p); +} + +static void +airpcap_breakloop(pcap_t *p) +{ + HANDLE read_event; + + pcapint_breakloop_common(p); + struct pcap_airpcap *pa = p->priv; + + /* XXX - what if either of these fail? */ + /* + * XXX - will SetEvent() force a wakeup and, if so, will + * the AirPcap read code handle that sanely? + */ + if (!p_AirpcapGetReadEvent(pa->adapter, &read_event)) + return; + SetEvent(read_event); +} + +static int +airpcap_activate(pcap_t *p) +{ + struct pcap_airpcap *pa = p->priv; + char *device = p->opt.device; + char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE]; + BOOL status; + AirpcapLinkType link_type; + + pa->adapter = p_AirpcapOpen(device, airpcap_errbuf); + if (pa->adapter == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", airpcap_errbuf); + return (PCAP_ERROR); + } + + /* + * Set monitor mode appropriately. + * Always turn off the "ACK frames sent to the card" mode. + */ + if (p->opt.rfmon) { + status = p_AirpcapSetDeviceMacFlags(pa->adapter, + AIRPCAP_MF_MONITOR_MODE_ON); + } else + status = p_AirpcapSetDeviceMacFlags(pa->adapter, + AIRPCAP_MF_ACK_FRAMES_ON); + if (!status) { + p_AirpcapClose(pa->adapter); + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetDeviceMacFlags() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + return (PCAP_ERROR); + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + /* + * If the buffer size wasn't explicitly set, default to + * AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE. + */ + if (p->opt.buffer_size == 0) + p->opt.buffer_size = AIRPCAP_DEFAULT_KERNEL_BUFFER_SIZE; + + if (!p_AirpcapSetKernelBuffer(pa->adapter, p->opt.buffer_size)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetKernelBuffer() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + goto bad; + } + + if(!p_AirpcapGetReadEvent(pa->adapter, &pa->read_event)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetReadEvent() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + goto bad; + } + + /* Set the buffer size */ + p->bufsize = AIRPCAP_DEFAULT_USER_BUFFER_SIZE; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + + if (p->opt.immediate) { + /* Tell the driver to copy the buffer as soon as data arrives. */ + if (!p_AirpcapSetMinToCopy(pa->adapter, 0)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetMinToCopy() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + goto bad; + } + } else { + /* + * Tell the driver to copy the buffer only if it contains + * at least 16K. + */ + if (!p_AirpcapSetMinToCopy(pa->adapter, 16000)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapSetMinToCopy() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + goto bad; + } + } + + /* + * Find out what the default link-layer header type is, + * and set p->datalink to that. + * + * We don't force it to another value because there + * might be some programs using WinPcap/Npcap that, + * when capturing on AirPcap devices, assume the + * default value set with the AirPcap configuration + * program is what you get. + * + * The out-of-the-box default appears to be radiotap. + */ + if (!p_AirpcapGetLinkType(pa->adapter, &link_type)) { + /* That failed. */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetLinkType() failed: %s", + p_AirpcapGetLastError(pa->adapter)); + goto bad; + } + switch (link_type) { + + case AIRPCAP_LT_802_11_PLUS_RADIO: + p->linktype = DLT_IEEE802_11_RADIO; + break; + + case AIRPCAP_LT_802_11_PLUS_PPI: + p->linktype = DLT_PPI; + break; + + case AIRPCAP_LT_802_11: + p->linktype = DLT_IEEE802_11; + break; + + case AIRPCAP_LT_UNKNOWN: + default: + /* OK, what? */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetLinkType() returned unknown link type %u", + link_type); + goto bad; + } + + /* + * Now provide a list of all the supported types; we + * assume they all work. We put radiotap at the top, + * followed by PPI, followed by "no radio metadata". + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 3); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + p->dlt_list[0] = DLT_IEEE802_11_RADIO; + p->dlt_list[1] = DLT_PPI; + p->dlt_list[2] = DLT_IEEE802_11; + p->dlt_count = 3; + + p->read_op = airpcap_read; + p->inject_op = airpcap_inject; + p->setfilter_op = airpcap_setfilter; + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = airpcap_set_datalink; + p->getnonblock_op = airpcap_getnonblock; + p->setnonblock_op = airpcap_setnonblock; + p->breakloop_op = airpcap_breakloop; + p->stats_op = airpcap_stats; + p->stats_ex_op = airpcap_stats_ex; + p->setbuff_op = airpcap_setbuff; + p->setmode_op = airpcap_setmode; + p->setmintocopy_op = airpcap_setmintocopy; + p->getevent_op = airpcap_getevent; + p->oid_get_request_op = airpcap_oid_get_request; + p->oid_set_request_op = airpcap_oid_set_request; + p->sendqueue_transmit_op = airpcap_sendqueue_transmit; + p->setuserbuffer_op = airpcap_setuserbuffer; + p->live_dump_op = airpcap_live_dump; + p->live_dump_ended_op = airpcap_live_dump_ended; + p->get_airpcap_handle_op = airpcap_get_airpcap_handle; + p->cleanup_op = airpcap_cleanup; + + return (0); + bad: + airpcap_cleanup(p); + return (PCAP_ERROR); +} + +/* + * Monitor mode is supported. + */ +static int +airpcap_can_set_rfmon(pcap_t *p) +{ + return (1); +} + +int +device_is_airpcap(const char *device, char *ebuf) +{ + static const char airpcap_prefix[] = "\\\\.\\airpcap"; + + /* + * We don't determine this by calling AirpcapGetDeviceList() + * and looking at the list, as that appears to be a costly + * operation. + * + * Instead, we just check whether it begins with "\\.\airpcap". + */ + if (strncmp(device, airpcap_prefix, sizeof airpcap_prefix - 1) == 0) { + /* + * Yes, it's an AirPcap device. + */ + return (1); + } + + /* + * No, it's not an AirPcap device. + */ + return (0); +} + +pcap_t * +airpcap_create(const char *device, char *ebuf, int *is_ours) +{ + int ret; + pcap_t *p; + + /* + * This can be called before we've tried loading the library, + * so do so if we haven't already tried to do so. + */ + if (load_airpcap_functions() != AIRPCAP_API_LOADED) { + /* + * We assume this means that we don't have the AirPcap + * software installed, which probably means we don't + * have an AirPcap device. + * + * Don't treat that as an error. + */ + *is_ours = 0; + return (NULL); + } + + /* + * Is this an AirPcap device? + */ + ret = device_is_airpcap(device, ebuf); + if (ret == 0) { + /* No. */ + *is_ours = 0; + return (NULL); + } + + /* + * Yes. + */ + *is_ours = 1; + p = PCAP_CREATE_COMMON(ebuf, struct pcap_airpcap); + if (p == NULL) + return (NULL); + + p->activate_op = airpcap_activate; + p->can_set_rfmon_op = airpcap_can_set_rfmon; + return (p); +} + +/* + * Add all AirPcap devices. + */ +int +airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf) +{ + AirpcapDeviceDescription *airpcap_devices, *airpcap_device; + char airpcap_errbuf[AIRPCAP_ERRBUF_SIZE]; + + /* + * This can be called before we've tried loading the library, + * so do so if we haven't already tried to do so. + */ + if (load_airpcap_functions() != AIRPCAP_API_LOADED) { + /* + * XXX - unless the error is "no such DLL", report this + * as an error rather than as "no AirPcap devices"? + */ + return (0); + } + + if (!p_AirpcapGetDeviceList(&airpcap_devices, airpcap_errbuf)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "AirpcapGetDeviceList() failed: %s", airpcap_errbuf); + return (-1); + } + + for (airpcap_device = airpcap_devices; airpcap_device != NULL; + airpcap_device = airpcap_device->next) { + if (pcapint_add_dev(devlistp, airpcap_device->Name, 0, + airpcap_device->Description, errbuf) == NULL) { + /* + * Failure. + */ + p_AirpcapFreeDeviceList(airpcap_devices); + return (-1); + } + } + p_AirpcapFreeDeviceList(airpcap_devices); + return (0); +} diff --git a/src/libpcap-1.10.5/pcap-airpcap.h b/src/libpcap-1.10.5/pcap-airpcap.h new file mode 100644 index 0000000000..aa1164ed4c --- /dev/null +++ b/src/libpcap-1.10.5/pcap-airpcap.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +pcap_t *airpcap_create(const char *, char *, int *); +int airpcap_findalldevs(pcap_if_list_t *devlistp, char *errbuf); +int device_is_airpcap(const char *device, char *ebuf); diff --git a/src/libpcap-1.10.5/pcap-bpf.c b/src/libpcap-1.10.5/pcap-bpf.c new file mode 100644 index 0000000000..b9e84e65f6 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bpf.c @@ -0,0 +1,3693 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include /* optionally get BSD define */ +#include +#include +/* + * defines ioctls, but doesn't include . + * + * We include as it might be necessary to declare ioctl(); + * at least on *BSD and macOS, it also defines various SIOC ioctls - + * we could include , but if we're already including + * , which includes on those platforms, + * there's not much point in doing so. + * + * If we have , we include it as well, to handle systems + * such as Solaris which don't arrange to include if you + * include + */ +#include +#ifdef HAVE_SYS_IOCCOM_H +#include +#endif +#include + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) +/* + * Add support for capturing on FreeBSD usbusN interfaces. + */ +static const char usbus_prefix[] = "usbus"; +#define USBUS_PREFIX_LEN (sizeof(usbus_prefix) - 1) +#include +#endif + +#include + +#ifdef _AIX + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we need "struct bpf_config" from it. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#include + +/* + * Prevent bpf.h from redefining the DLT_ values to their + * IFT_ values, as we're going to return the standard libpcap + * values, not IBM's non-standard IFT_ values. + */ +#undef _AIX +#include +#define _AIX + +/* + * If both BIOCROTZBUF and BPF_BUFMODE_ZBUF are defined, we have + * zero-copy BPF. + */ +#if defined(BIOCROTZBUF) && defined(BPF_BUFMODE_ZBUF) + #define HAVE_ZEROCOPY_BPF + #include + #include +#endif + +#include /* for IFT_ values */ +#include +#include +#include +#include + +#ifdef __64BIT__ +#define domakedev makedev64 +#define getmajor major64 +#define bpf_hdr bpf_hdr32 +#else /* __64BIT__ */ +#define domakedev makedev +#define getmajor major +#endif /* __64BIT__ */ + +#define BPF_NAME "bpf" +#define BPF_MINORS 4 +#define DRIVER_PATH "/usr/lib/drivers" +#define BPF_NODE "/dev/bpf" +static int bpfloadedflag = 0; +static int odmlockid = 0; + +static int bpf_load(char *errbuf); + +#else /* _AIX */ + +#include + +#endif /* _AIX */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SIOCGIFMEDIA +# include +#endif + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Later versions of NetBSD stick padding in front of FDDI frames + * to align the IP header on a 4-byte boundary. + */ +#if defined(__NetBSD__) && __NetBSD_Version__ > 106000000 +#define PCAP_FDDIPAD 3 +#endif + +/* + * Private data for capturing on BPF devices. + */ +struct pcap_bpf { +#ifdef HAVE_ZEROCOPY_BPF + /* + * Zero-copy read buffer -- for zero-copy BPF. 'buffer' above will + * alternative between these two actual mmap'd buffers as required. + * As there is a header on the front size of the mmap'd buffer, only + * some of the buffer is exposed to libpcap as a whole via bufsize; + * zbufsize is the true size. zbuffer tracks the current zbuf + * associated with buffer so that it can be used to decide which the + * next buffer to read will be. + */ + u_char *zbuf1, *zbuf2, *zbuffer; + u_int zbufsize; + u_int zerocopy; + u_int interrupted; + struct timespec firstsel; + /* + * If there's currently a buffer being actively processed, then it is + * referenced here; 'buffer' is also pointed at it, but offset by the + * size of the header. + */ + struct bpf_zbuf_header *bzh; + int nonblock; /* true if in nonblocking mode */ +#endif /* HAVE_ZEROCOPY_BPF */ + + char *device; /* device name */ + int filtering_in_kernel; /* using kernel filter */ + int must_do_on_close; /* stuff we must do when we close */ +}; + +/* + * Stuff to do when we close. + */ +#define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ +#define MUST_DESTROY_USBUS 0x00000002 /* destroy usbusN interface */ + +#ifdef BIOCGDLTLIST +# if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__) +#define HAVE_BSD_IEEE80211 + +/* + * The ifm_ulist member of a struct ifmediareq is an int * on most systems, + * but it's a uint64_t on newer versions of OpenBSD. + * + * We check this by checking whether IFM_GMASK is defined and > 2^32-1. + */ +# if defined(IFM_GMASK) && IFM_GMASK > 0xFFFFFFFF +# define IFM_ULIST_TYPE uint64_t +# else +# define IFM_ULIST_TYPE int +# endif +# endif + +# if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) +static int find_802_11(struct bpf_dltlist *); + +# ifdef HAVE_BSD_IEEE80211 +static int monitor_mode(pcap_t *, int); +# endif + +# if defined(__APPLE__) +static void remove_non_802_11(pcap_t *); +static void remove_802_11(pcap_t *); +# endif + +# endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */ + +#endif /* BIOCGDLTLIST */ + +#if defined(sun) && defined(LIFNAMSIZ) && defined(lifr_zoneid) +#include +#endif + +/* + * We include the OS's , not our "pcap/bpf.h", so we probably + * don't get DLT_DOCSIS defined. + */ +#ifndef DLT_DOCSIS +#define DLT_DOCSIS 143 +#endif + +/* + * In some versions of macOS, we might not even get any of the + * 802.11-plus-radio-header DLT_'s defined, even though some + * of them are used by various Airport drivers in those versions. + */ +#ifndef DLT_PRISM_HEADER +#define DLT_PRISM_HEADER 119 +#endif +#ifndef DLT_AIRONET_HEADER +#define DLT_AIRONET_HEADER 120 +#endif +#ifndef DLT_IEEE802_11_RADIO +#define DLT_IEEE802_11_RADIO 127 +#endif +#ifndef DLT_IEEE802_11_RADIO_AVS +#define DLT_IEEE802_11_RADIO_AVS 163 +#endif + +static int pcap_can_set_rfmon_bpf(pcap_t *p); +static int pcap_activate_bpf(pcap_t *p); +static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp); +static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t); +static int pcap_set_datalink_bpf(pcap_t *p, int dlt); + +/* + * For zerocopy bpf, the setnonblock/getnonblock routines need to modify + * pb->nonblock so we don't call select(2) if the pcap handle is in non- + * blocking mode. + */ +static int +pcap_getnonblock_bpf(pcap_t *p) +{ +#ifdef HAVE_ZEROCOPY_BPF + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) + return (pb->nonblock); +#endif + return (pcapint_getnonblock_fd(p)); +} + +static int +pcap_setnonblock_bpf(pcap_t *p, int nonblock) +{ +#ifdef HAVE_ZEROCOPY_BPF + struct pcap_bpf *pb = p->priv; + + if (pb->zerocopy) { + pb->nonblock = nonblock; + return (0); + } +#endif + return (pcapint_setnonblock_fd(p, nonblock)); +} + +#ifdef HAVE_ZEROCOPY_BPF +/* + * Zero-copy BPF buffer routines to check for and acknowledge BPF data in + * shared memory buffers. + * + * pcap_next_zbuf_shm(): Check for a newly available shared memory buffer, + * and set up p->buffer and cc to reflect one if available. Notice that if + * there was no prior buffer, we select zbuf1 as this will be the first + * buffer filled for a fresh BPF session. + */ +static int +pcap_next_zbuf_shm(pcap_t *p, int *cc) +{ + struct pcap_bpf *pb = p->priv; + struct bpf_zbuf_header *bzh; + + if (pb->zbuffer == pb->zbuf2 || pb->zbuffer == NULL) { + bzh = (struct bpf_zbuf_header *)pb->zbuf1; + if (bzh->bzh_user_gen != + atomic_load_acq_int(&bzh->bzh_kernel_gen)) { + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf1; + p->buffer = pb->zbuffer + sizeof(*bzh); + *cc = bzh->bzh_kernel_len; + return (1); + } + } else if (pb->zbuffer == pb->zbuf1) { + bzh = (struct bpf_zbuf_header *)pb->zbuf2; + if (bzh->bzh_user_gen != + atomic_load_acq_int(&bzh->bzh_kernel_gen)) { + pb->bzh = bzh; + pb->zbuffer = (u_char *)pb->zbuf2; + p->buffer = pb->zbuffer + sizeof(*bzh); + *cc = bzh->bzh_kernel_len; + return (1); + } + } + *cc = 0; + return (0); +} + +/* + * pcap_next_zbuf() -- Similar to pcap_next_zbuf_shm(), except wait using + * select() for data or a timeout, and possibly force rotation of the buffer + * in the event we time out or are in immediate mode. Invoke the shared + * memory check before doing system calls in order to avoid doing avoidable + * work. + */ +static int +pcap_next_zbuf(pcap_t *p, int *cc) +{ + struct pcap_bpf *pb = p->priv; + struct bpf_zbuf bz; + struct timeval tv; + struct timespec cur; + fd_set r_set; + int data, r; + int expire, tmout; + +#define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000)) + /* + * Start out by seeing whether anything is waiting by checking the + * next shared memory buffer for data. + */ + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + /* + * If a previous sleep was interrupted due to signal delivery, make + * sure that the timeout gets adjusted accordingly. This requires + * that we analyze when the timeout should be been expired, and + * subtract the current time from that. If after this operation, + * our timeout is less than or equal to zero, handle it like a + * regular timeout. + */ + tmout = p->opt.timeout; + if (tmout) + (void) clock_gettime(CLOCK_MONOTONIC, &cur); + if (pb->interrupted && p->opt.timeout) { + expire = TSTOMILLI(&pb->firstsel) + p->opt.timeout; + tmout = expire - TSTOMILLI(&cur); +#undef TSTOMILLI + if (tmout <= 0) { + pb->interrupted = 0; + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, "BIOCROTZBUF"); + return (PCAP_ERROR); + } + return (pcap_next_zbuf_shm(p, cc)); + } + } + /* + * No data in the buffer, so must use select() to wait for data or + * the next timeout. Note that we only call select if the handle + * is in blocking mode. + */ + if (!pb->nonblock) { + FD_ZERO(&r_set); + FD_SET(p->fd, &r_set); + if (tmout != 0) { + tv.tv_sec = tmout / 1000; + tv.tv_usec = (tmout * 1000) % 1000000; + } + r = select(p->fd + 1, &r_set, NULL, NULL, + p->opt.timeout != 0 ? &tv : NULL); + if (r < 0 && errno == EINTR) { + if (!pb->interrupted && p->opt.timeout) { + pb->interrupted = 1; + pb->firstsel = cur; + } + return (0); + } else if (r < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "select"); + return (PCAP_ERROR); + } + } + pb->interrupted = 0; + /* + * Check again for data, which may exist now that we've either been + * woken up as a result of data or timed out. Try the "there's data" + * case first since it doesn't require a system call. + */ + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + /* + * Try forcing a buffer rotation to dislodge timed out or immediate + * data. + */ + if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCROTZBUF"); + return (PCAP_ERROR); + } + return (pcap_next_zbuf_shm(p, cc)); +} + +/* + * Notify kernel that we are done with the buffer. We don't reset zbuffer so + * that we know which buffer to use next time around. + */ +static int +pcap_ack_zbuf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; + + atomic_store_rel_int(&pb->bzh->bzh_user_gen, + pb->bzh->bzh_kernel_gen); + pb->bzh = NULL; + p->buffer = NULL; + return (0); +} +#endif /* HAVE_ZEROCOPY_BPF */ + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_bpf); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_bpf; + p->can_set_rfmon_op = pcap_can_set_rfmon_bpf; +#ifdef BIOCSTSTAMP + /* + * We claim that we support microsecond and nanosecond time + * stamps. + */ + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, + "malloc"); + free(p); + return (NULL); + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + p->tstamp_precision_count = 2; +#endif /* BIOCSTSTAMP */ + return (p); +} + +/* + * On success, returns a file descriptor for a BPF device. + * On failure, returns a PCAP_ERROR_ value, and sets p->errbuf. + */ +static int +bpf_open(char *errbuf) +{ + int fd = -1; + static const char cloning_device[] = "/dev/bpf"; + u_int n = 0; + char device[sizeof "/dev/bpf0000000000"]; + static int no_cloning_bpf = 0; + +#ifdef _AIX + /* + * Load the bpf driver, if it isn't already loaded, + * and create the BPF device entries, if they don't + * already exist. + */ + if (bpf_load(errbuf) == PCAP_ERROR) + return (PCAP_ERROR); +#endif + + /* + * First, unless we've already tried opening /dev/bpf and + * gotten ENOENT, try opening /dev/bpf. + * If it fails with ENOENT, remember that, so we don't try + * again, and try /dev/bpfN. + */ + if (!no_cloning_bpf && + (fd = open(cloning_device, O_RDWR)) == -1 && + ((errno != EACCES && errno != ENOENT) || + (fd = open(cloning_device, O_RDONLY)) == -1)) { + if (errno != ENOENT) { + if (errno == EACCES) { + fd = PCAP_ERROR_PERM_DENIED; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed - root privileges may be required", + cloning_device); + } else { + fd = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "(cannot open device) %s", cloning_device); + } + return (fd); + } + no_cloning_bpf = 1; + } + + if (no_cloning_bpf) { + /* + * We don't have /dev/bpf. + * Go through all the /dev/bpfN minors and find one + * that isn't in use. + */ + do { + (void)snprintf(device, sizeof(device), "/dev/bpf%u", n++); + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + */ + fd = open(device, O_RDWR); + if (fd == -1 && errno == EACCES) + fd = open(device, O_RDONLY); + } while (fd < 0 && errno == EBUSY); + } + + /* + * XXX better message for all minors used + */ + if (fd < 0) { + switch (errno) { + + case ENOENT: + if (n == 1) { + /* + * /dev/bpf0 doesn't exist, which + * means we probably have no BPF + * devices. + */ + fd = PCAP_ERROR_CAPTURE_NOTSUP; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(there are no BPF devices)"); + } else { + /* + * We got EBUSY on at least one + * BPF device, so we have BPF + * devices, but all the ones + * that exist are busy. + */ + fd = PCAP_ERROR; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "(all BPF devices are busy)"); + } + break; + + case EACCES: + /* + * Got EACCES on the last device we tried, + * and EBUSY on all devices before that, + * if any. + */ + fd = PCAP_ERROR_PERM_DENIED; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed - root privileges may be required", + device); + break; + + default: + /* + * Some other problem. + */ + fd = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "(cannot open BPF device) %s", device); + break; + } + } + + return (fd); +} + +/* + * Bind a network adapter to a BPF device, given a descriptor for the + * BPF device and the name of the network adapter. + * + * Use BIOCSETLIF if available (meaning "on Solaris"), as it supports + * longer device names and binding to devices in other zones. + * + * If the name is longer than will fit, return PCAP_ERROR_NO_SUCH_DEVICE + * before trying to bind the interface, as there cannot be such a device. + * + * If the attempt succeeds, return BPF_BIND_SUCCEEDED. + * + * If the attempt fails: + * + * if it fails with ENOBUFS, return BPF_BIND_BUFFER_TOO_BIG, and + * fill in an error message, as the buffer being requested is too + * large - our caller may try a smaller buffer if no buffer size + * was explicitly specified. + * + * otherwise, return the appropriate PCAP_ERROR_ code and + * fill in an error message. + */ +#define BPF_BIND_SUCCEEDED 0 +#define BPF_BIND_BUFFER_TOO_BIG 1 + +static int +bpf_bind(int fd, const char *name, char *errbuf) +{ + int status; +#ifdef LIFNAMSIZ + struct lifreq ifr; + const char *ifname = name; + + #if defined(ZONENAME_MAX) && defined(lifr_zoneid) + char *zonesep; + + /* + * We have support for zones. + * Retrieve the zoneid of the zone we are currently executing in. + */ + if ((ifr.lifr_zoneid = getzoneid()) == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "getzoneid()"); + return (PCAP_ERROR); + } + + /* + * Check if the given source datalink name has a '/' separated + * zonename prefix string. The zonename prefixed source datalink can + * be used by pcap consumers in the Solaris global zone to capture + * traffic on datalinks in non-global zones. Non-global zones + * do not have access to datalinks outside of their own namespace. + */ + if ((zonesep = strchr(name, '/')) != NULL) { + char *zname; + ptrdiff_t znamelen; + + if (ifr.lifr_zoneid != GLOBAL_ZONEID) { + /* + * We treat this as a generic error rather + * than as "permission denied" because + * this isn't a case of "you don't have + * enough permission to capture on this + * device, so you'll have to do something + * to get that permission" (such as + * configuring the system to allow non-root + * users to capture traffic), it's a case + * of "nobody has permission to do this, + * so there's nothing to do to fix it + * other than running the capture program + * in the global zone or the zone containing + * the adapter". + * + * (And, yes, this is a real issue; for example, + * Wireshark might make platform-specific suggestions + * on how to fix a PCAP_ERROR_PERM_DENIED problem, + * none of which will help here.) + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "zonename/linkname only valid in global zone."); + return (PCAP_ERROR); + } + znamelen = zonesep - name; + zname = malloc(znamelen + 1); + if (zname == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (PCAP_ERROR); + } + memcpy(zname, name, znamelen + 1); + zname[znamelen] = '\0'; + ifr.lifr_zoneid = getzoneidbyname(zname); + if (ifr.lifr_zoneid == -1) { + switch (errno) { + + case EINVAL: + case ENAMETOOLONG: + /* + * If the name's length exceeds + * ZONENAMEMAX, clearly there cannot + * be such a zone; it's not clear that + * "that name's too long for a zone" + * is more informative than "there's + * no such zone". + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "There is no zone named \"%s\"", + zname); + + /* + * No such zone means the name + * refers to a non-existent interface. + */ + status = PCAP_ERROR_NO_SUCH_DEVICE; + break; + + default: + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "getzoneidbyname(%s)", zname); + status = PCAP_ERROR; + break; + } + free(zname); + return (status); + } + free(zname); + + /* + * To bind to this interface, we set the ifr.lifr_zoneid + * to the zone ID of its zone (done above), and we set + * ifr.lifr_name to the name of the interface within that + * zone (done below, using ifname). + */ + ifname = zonesep + 1; + } + #endif + + if (strlen(ifname) >= sizeof(ifr.lifr_name)) { + /* The name is too long, so it can't possibly exist. */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + (void)pcapint_strlcpy(ifr.lifr_name, ifname, sizeof(ifr.lifr_name)); + status = ioctl(fd, BIOCSETLIF, (caddr_t)&ifr); +#else + struct ifreq ifr; + + if (strlen(name) >= sizeof(ifr.ifr_name)) { + /* The name is too long, so it can't possibly exist. */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + (void)pcapint_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + status = ioctl(fd, BIOCSETIF, (caddr_t)&ifr); +#endif + + if (status < 0) { + switch (errno) { + +#if defined(HAVE_SOLARIS) + /* + * For some reason, Solaris 11 appears to return ESRCH + * for unknown devices. + */ + case ESRCH: +#else + /* + * The *BSDs (including CupertinoBSD a/k/a Darwin) + * return ENXIO for unknown devices. + */ + case ENXIO: +#endif + /* + * There's no such device. + * + * There's nothing more to say, so clear out the + * error message. + */ + errbuf[0] = '\0'; + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case ENETDOWN: + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return (PCAP_ERROR_IFACE_NOT_UP); + + case ENOBUFS: + /* + * The buffer size is too big. + * Return a special indication so that, if we're + * trying to crank the buffer size down, we know + * we have to continue; add an error message that + * tells the user what needs to be fixed. + */ + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "The requested buffer size for %s is too large", + name); + return (BPF_BIND_BUFFER_TOO_BIG); + + default: + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "Binding interface %s to BPF device failed", + name); + return (PCAP_ERROR); + } + } + return (BPF_BIND_SUCCEEDED); +} + +/* + * Open and bind to a device; used if we're not actually going to use + * the device, but are just testing whether it can be opened, or opening + * it to get information about it. + * + * Returns an error code on failure (always negative), and an FD for + * the now-bound BPF device on success (always non-negative). + */ +static int +bpf_open_and_bind(const char *name, char *errbuf) +{ + int fd; + int status; + + /* + * First, open a BPF device. + */ + fd = bpf_open(errbuf); + if (fd < 0) + return (fd); /* fd is the appropriate error code */ + + /* + * Now bind to the device. + */ + status = bpf_bind(fd, name, errbuf); + if (status != BPF_BIND_SUCCEEDED) { + close(fd); + if (status == BPF_BIND_BUFFER_TOO_BIG) { + /* + * We didn't specify a buffer size, so + * this *really* shouldn't fail because + * there's no buffer space. Fail. + */ + return (PCAP_ERROR); + } + return (status); + } + + /* + * Success. + */ + return (fd); +} + +#ifdef __APPLE__ +static int +device_exists(int fd, const char *name, char *errbuf) +{ + int status; + struct ifreq ifr; + + if (strlen(name) >= sizeof(ifr.ifr_name)) { + /* The name is too long, so it can't possibly exist. */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + (void)pcapint_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + status = ioctl(fd, SIOCGIFFLAGS, (caddr_t)&ifr); + + if (status < 0) { + if (errno == ENXIO || errno == EINVAL) { + /* + * macOS and *BSD return one of those two + * errors if the device doesn't exist. + * Don't fill in an error, as this is + * an "expected" condition. + */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + + /* + * Some other error - provide a message for it, as + * it's "unexpected". + */ + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "Can't get interface flags on %s", name); + return (PCAP_ERROR); + } + + /* + * The device exists. + */ + return (0); +} +#endif + +#ifdef BIOCGDLTLIST +static int +get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) +{ + memset(bdlp, 0, sizeof(*bdlp)); + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) { + u_int i; + int is_ethernet; + + bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); + if (bdlp->bfl_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (PCAP_ERROR); + } + + if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLTLIST"); + free(bdlp->bfl_list); + return (PCAP_ERROR); + } + + /* + * OK, for real Ethernet devices, add DLT_DOCSIS to the + * list, so that an application can let you choose it, + * in case you're capturing DOCSIS traffic that a Cisco + * Cable Modem Termination System is putting out onto + * an Ethernet (it doesn't put an Ethernet header onto + * the wire, it puts raw DOCSIS frames out on the wire + * inside the low-level Ethernet framing). + * + * A "real Ethernet device" is defined here as a device + * that has a link-layer type of DLT_EN10MB and that has + * no alternate link-layer types; that's done to exclude + * 802.11 interfaces (which might or might not be the + * right thing to do, but I suspect it is - Ethernet <-> + * 802.11 bridges would probably badly mishandle frames + * that don't have Ethernet headers). + * + * On Solaris with BPF, Ethernet devices also offer + * DLT_IPNET, so we, if DLT_IPNET is defined, we don't + * treat it as an indication that the device isn't an + * Ethernet. + */ + if (v == DLT_EN10MB) { + is_ethernet = 1; + for (i = 0; i < bdlp->bfl_len; i++) { + if (bdlp->bfl_list[i] != DLT_EN10MB +#ifdef DLT_IPNET + && bdlp->bfl_list[i] != DLT_IPNET +#endif + ) { + is_ethernet = 0; + break; + } + } + if (is_ethernet) { + /* + * We reserved one more slot at the end of + * the list. + */ + bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS; + bdlp->bfl_len++; + } + } + } else { + /* + * EINVAL just means "we don't support this ioctl on + * this device"; don't treat it as an error. + */ + if (errno != EINVAL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLTLIST"); + return (PCAP_ERROR); + } + } + return (0); +} +#endif + +#if defined(__APPLE__) +static int +pcap_can_set_rfmon_bpf(pcap_t *p) +{ + struct utsname osinfo; + int fd; +#ifdef BIOCGDLTLIST + struct bpf_dltlist bdl; + int err; +#endif + + /* + * The joys of monitor mode on Mac OS X/OS X/macOS. + * + * Prior to 10.4, it's not supported at all. + * + * In 10.4, if adapter enN supports monitor mode, there's a + * wltN adapter corresponding to it; you open it, instead of + * enN, to get monitor mode. You get whatever link-layer + * headers it supplies. + * + * In 10.5, and, we assume, later releases, if adapter enN + * supports monitor mode, it offers, among its selectable + * DLT_ values, values that let you get the 802.11 header; + * selecting one of those values puts the adapter into monitor + * mode (i.e., you can't get 802.11 headers except in monitor + * mode, and you can't get Ethernet headers in monitor mode). + */ + if (uname(&osinfo) == -1) { + /* + * Can't get the OS version; just say "no". + */ + return (0); + } + /* + * We assume osinfo.sysname is "Darwin", because + * __APPLE__ is defined. We just check the version. + */ + if (osinfo.release[0] < '8' && osinfo.release[1] == '.') { + /* + * 10.3 (Darwin 7.x) or earlier. + * Monitor mode not supported. + */ + return (0); + } + if (osinfo.release[0] == '8' && osinfo.release[1] == '.') { + char *wlt_name; + int status; + + /* + * 10.4 (Darwin 8.x). s/en/wlt/, and check + * whether the device exists. + */ + if (strncmp(p->opt.device, "en", 2) != 0) { + /* + * Not an enN device; no monitor mode. + */ + return (0); + } + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + return (PCAP_ERROR); + } + if (pcapint_asprintf(&wlt_name, "wlt%s", p->opt.device + 2) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + close(fd); + return (PCAP_ERROR); + } + status = device_exists(fd, wlt_name, p->errbuf); + free(wlt_name); + close(fd); + if (status != 0) { + if (status == PCAP_ERROR_NO_SUCH_DEVICE) + return (0); + + /* + * Error. + */ + return (status); + } + return (1); + } + +#ifdef BIOCGDLTLIST + /* + * Everything else is 10.5 or later; for those, + * we just open the enN device, and check whether + * we have any 802.11 devices. + * + * First, open a BPF device. + */ + fd = bpf_open(p->errbuf); + if (fd < 0) + return (fd); /* fd is the appropriate error code */ + + /* + * Now bind to the device. + */ + err = bpf_bind(fd, p->opt.device, p->errbuf); + if (err != BPF_BIND_SUCCEEDED) { + close(fd); + if (err == BPF_BIND_BUFFER_TOO_BIG) { + /* + * We didn't specify a buffer size, so + * this *really* shouldn't fail because + * there's no buffer space. Fail. + */ + return (PCAP_ERROR); + } + return (err); + } + + /* + * We know the default link type -- now determine all the DLTs + * this interface supports. If this fails with EINVAL, it's + * not fatal; we just don't get to use the feature later. + * (We don't care about DLT_DOCSIS, so we pass DLT_NULL + * as the default DLT for this adapter.) + */ + if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == PCAP_ERROR) { + close(fd); + return (PCAP_ERROR); + } + if (find_802_11(&bdl) != -1) { + /* + * We have an 802.11 DLT, so we can set monitor mode. + */ + free(bdl.bfl_list); + close(fd); + return (1); + } + free(bdl.bfl_list); + close(fd); +#endif /* BIOCGDLTLIST */ + return (0); +} +#elif defined(HAVE_BSD_IEEE80211) +static int +pcap_can_set_rfmon_bpf(pcap_t *p) +{ + int ret; + + ret = monitor_mode(p, 0); + if (ret == PCAP_ERROR_RFMON_NOTSUP) + return (0); /* not an error, just a "can't do" */ + if (ret == 0) + return (1); /* success */ + return (ret); +} +#else +static int +pcap_can_set_rfmon_bpf(pcap_t *p _U_) +{ + return (0); +} +#endif + +static int +pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) +{ + struct bpf_stat s; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. This includes packets later dropped + * because we ran out of buffer space. + * + * "ps_drop" counts packets dropped inside the BPF device + * because we ran out of buffer space. It doesn't count + * packets dropped by the interface driver. It counts + * only packets that passed the filter. + * + * Both statistics include packets not yet read from the kernel + * by libpcap, and thus not yet seen by the application. + */ + if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGSTATS"); + return (PCAP_ERROR); + } + + /* + * On illumos, NetBSD and Solaris these values are 64-bit, but struct + * pcap_stat is what it is, so the integer precision loss is expected. + */ + ps->ps_recv = (u_int)s.bs_recv; + ps->ps_drop = (u_int)s.bs_drop; + ps->ps_ifdrop = 0; + return (0); +} + +static int +pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_bpf *pb = p->priv; + ssize_t cc; + int n = 0; + register u_char *bp, *ep; + u_char *datap; +#ifdef PCAP_FDDIPAD + register u_int pad; +#endif +#ifdef HAVE_ZEROCOPY_BPF + int i; +#endif + + again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + cc = p->cc; + if (p->cc == 0) { + /* + * When reading without zero-copy from a file descriptor, we + * use a single buffer and return a length of data in the + * buffer. With zero-copy, we update the p->buffer pointer + * to point at whatever underlying buffer contains the next + * data and update cc to reflect the data found in the + * buffer. + */ +#ifdef HAVE_ZEROCOPY_BPF + if (pb->zerocopy) { + if (p->buffer != NULL) + pcap_ack_zbuf(p); + i = pcap_next_zbuf(p, &cc); + if (i == 0) + goto again; + if (i < 0) + return (PCAP_ERROR); + } else +#endif + { + cc = read(p->fd, p->buffer, p->bufsize); + } + if (cc < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + goto again; + +#ifdef _AIX + case EFAULT: + /* + * Sigh. More AIX wonderfulness. + * + * For some unknown reason the uiomove() + * operation in the bpf kernel extension + * used to copy the buffer into user + * space sometimes returns EFAULT. I have + * no idea why this is the case given that + * a kernel debugger shows the user buffer + * is correct. This problem appears to + * be mostly mitigated by the memset of + * the buffer before it is first used. + * Very strange.... Shaun Clowes + * + * In any case this means that we shouldn't + * treat EFAULT as a fatal error; as we + * don't have an API for returning + * a "some packets were dropped since + * the last packet you saw" indication, + * we just ignore EFAULT and keep reading. + */ + goto again; +#endif + + case EWOULDBLOCK: + return (0); + + case ENXIO: /* FreeBSD, DragonFly BSD, and Darwin */ + case EIO: /* OpenBSD */ + /* NetBSD appears not to return an error in this case */ + /* + * The device on which we're capturing + * went away. + * + * XXX - we should really return + * an appropriate error for that, + * but pcap_dispatch() etc. aren't + * documented as having error returns + * other than PCAP_ERROR or PCAP_ERROR_BREAK. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The interface disappeared"); + return (PCAP_ERROR); + +#if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4) + /* + * Due to a SunOS bug, after 2^31 bytes, the kernel + * file offset overflows and read fails with EINVAL. + * The lseek() to 0 will fix things. + */ + case EINVAL: + if (lseek(p->fd, 0L, SEEK_CUR) + + p->bufsize < 0) { + (void)lseek(p->fd, 0L, SEEK_SET); + goto again; + } + /* fall through */ +#endif + } + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "read"); + return (PCAP_ERROR); + } + bp = (u_char *)p->buffer; + } else + bp = p->bp; + + /* + * Loop through each packet. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ +#ifdef BIOCSTSTAMP +#define bhp ((struct bpf_xhdr *)bp) +#else +#define bhp ((struct bpf_hdr *)bp) +#endif + ep = bp + cc; +#ifdef PCAP_FDDIPAD + pad = p->fddipad; +#endif + while (bp < ep) { + register u_int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (p->break_loop) { + p->bp = bp; + p->cc = (int)(ep - bp); + /* + * ep is set based on the return value of read(), + * but read() from a BPF device doesn't necessarily + * return a value that's a multiple of the alignment + * value for BPF_WORDALIGN(). However, whenever we + * increment bp, we round up the increment value by + * a value rounded up by BPF_WORDALIGN(), so we + * could increment bp past ep after processing the + * last packet in the buffer. + * + * We treat ep < bp as an indication that this + * happened, and just set p->cc to 0. + */ + if (p->cc < 0) + p->cc = 0; + if (n == 0) { + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } else + return (n); + } + + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + datap = bp + hdrlen; + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * +#ifdef PCAP_FDDIPAD + * Note: the filter code was generated assuming + * that p->fddipad was the amount of padding + * before the header, as that's what's required + * in the kernel, so we run the filter before + * skipping that padding. +#endif + */ + if (pb->filtering_in_kernel || + pcapint_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { + struct pcap_pkthdr pkthdr; +#ifdef BIOCSTSTAMP + struct bintime bt; + + bt.sec = bhp->bh_tstamp.bt_sec; + bt.frac = bhp->bh_tstamp.bt_frac; + if (p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { + struct timespec ts; + + bintime2timespec(&bt, &ts); + pkthdr.ts.tv_sec = ts.tv_sec; + pkthdr.ts.tv_usec = ts.tv_nsec; + } else { + struct timeval tv; + + bintime2timeval(&bt, &tv); + pkthdr.ts.tv_sec = tv.tv_sec; + pkthdr.ts.tv_usec = tv.tv_usec; + } +#else + pkthdr.ts.tv_sec = bhp->bh_tstamp.tv_sec; +#ifdef _AIX + /* + * AIX's BPF returns seconds/nanoseconds time + * stamps, not seconds/microseconds time stamps. + */ + pkthdr.ts.tv_usec = bhp->bh_tstamp.tv_usec/1000; +#else + /* + * On NetBSD the former (timeval.tv_usec) is an int via + * suseconds_t and the latter (bpf_timeval.tv_usec) is + * a long. In any case, the value is supposed to be + * within the [0 .. 999999] interval. + */ + pkthdr.ts.tv_usec = (suseconds_t)bhp->bh_tstamp.tv_usec; +#endif +#endif /* BIOCSTSTAMP */ +#ifdef PCAP_FDDIPAD + if (caplen > pad) + pkthdr.caplen = caplen - pad; + else + pkthdr.caplen = 0; + if (bhp->bh_datalen > pad) + pkthdr.len = bhp->bh_datalen - pad; + else + pkthdr.len = 0; + datap += pad; +#else + pkthdr.caplen = caplen; + pkthdr.len = bhp->bh_datalen; +#endif + (*callback)(user, &pkthdr, datap); + bp += BPF_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->bp = bp; + p->cc = (int)(ep - bp); + /* + * See comment above about p->cc < 0. + */ + if (p->cc < 0) + p->cc = 0; + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += BPF_WORDALIGN(caplen + hdrlen); + } + } +#undef bhp + p->cc = 0; + return (n); +} + +static int +pcap_inject_bpf(pcap_t *p, const void *buf, int size) +{ + int ret; + + ret = (int)write(p->fd, buf, size); +#ifdef __APPLE__ + if (ret == -1 && errno == EAFNOSUPPORT) { + /* + * In some versions of macOS, there's a bug wherein setting + * the BIOCSHDRCMPLT flag causes writes to fail; see, for + * example: + * + * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch + * + * So, if, on macOS, we get EAFNOSUPPORT from the write, we + * assume it's due to that bug, and turn off that flag + * and try again. If we succeed, it either means that + * somebody applied the fix from that URL, or other patches + * for that bug from + * + * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/ + * + * and are running a Darwin kernel with those fixes, or + * that Apple fixed the problem in some macOS release. + */ + u_int spoof_eth_src = 0; + + if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send: can't turn off BIOCSHDRCMPLT"); + return (PCAP_ERROR); + } + + /* + * Now try the write again. + */ + ret = (int)write(p->fd, buf, size); + } +#endif /* __APPLE__ */ + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (PCAP_ERROR); + } + return (ret); +} + +#ifdef _AIX +static int +bpf_odminit(char *errbuf) +{ + char *errstr; + + if (odm_initialize() == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_initialize failed: %s", + errstr); + return (PCAP_ERROR); + } + + if ((odmlockid = odm_lock("/etc/objrepos/config_lock", ODM_WAIT)) == -1) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s", + errstr); + (void)odm_terminate(); + return (PCAP_ERROR); + } + + return (0); +} + +static int +bpf_odmcleanup(char *errbuf) +{ + char *errstr; + + if (odm_unlock(odmlockid) == -1) { + if (errbuf != NULL) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_unlock failed: %s", + errstr); + } + return (PCAP_ERROR); + } + + if (odm_terminate() == -1) { + if (errbuf != NULL) { + if (odm_err_msg(odmerrno, &errstr) == -1) + errstr = "Unknown error"; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "bpf_load: odm_terminate failed: %s", + errstr); + } + return (PCAP_ERROR); + } + + return (0); +} + +static int +bpf_load(char *errbuf) +{ + long major; + int *minors; + int numminors, i, rc; + char buf[1024]; + struct stat sbuf; + struct bpf_config cfg_bpf; + struct cfg_load cfg_ld; + struct cfg_kmod cfg_km; + + /* + * This is very very close to what happens in the real implementation + * but I've fixed some (unlikely) bug situations. + */ + if (bpfloadedflag) + return (0); + + if (bpf_odminit(errbuf) == PCAP_ERROR) + return (PCAP_ERROR); + + major = genmajor(BPF_NAME); + if (major == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: genmajor failed"); + (void)bpf_odmcleanup(NULL); + return (PCAP_ERROR); + } + + minors = getminor(major, &numminors, BPF_NAME); + if (!minors) { + minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); + if (!minors) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: genminor failed"); + (void)bpf_odmcleanup(NULL); + return (PCAP_ERROR); + } + } + + if (bpf_odmcleanup(errbuf) == PCAP_ERROR) + return (PCAP_ERROR); + + rc = stat(BPF_NODE "0", &sbuf); + if (rc == -1 && errno != ENOENT) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: can't stat %s", BPF_NODE "0"); + return (PCAP_ERROR); + } + + if (rc == -1 || getmajor(sbuf.st_rdev) != major) { + for (i = 0; i < BPF_MINORS; i++) { + snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i); + unlink(buf); + if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "bpf_load: can't mknod %s", buf); + return (PCAP_ERROR); + } + } + } + + /* Check if the driver is loaded */ + memset(&cfg_ld, 0x0, sizeof(cfg_ld)); + snprintf(buf, sizeof(buf), "%s/%s", DRIVER_PATH, BPF_NAME); + cfg_ld.path = buf; + if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || + (cfg_ld.kmid == 0)) { + /* Driver isn't loaded, load it now */ + if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: could not load driver"); + return (PCAP_ERROR); + } + } + + /* Configure the driver */ + cfg_km.cmd = CFG_INIT; + cfg_km.kmid = cfg_ld.kmid; + cfg_km.mdilen = sizeof(cfg_bpf); + cfg_km.mdiptr = (void *)&cfg_bpf; + for (i = 0; i < BPF_MINORS; i++) { + cfg_bpf.devno = domakedev(major, i); + if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: could not configure driver"); + return (PCAP_ERROR); + } + } + + bpfloadedflag = 1; + + return (0); +} +#endif + +/* + * Undo any operations done when opening the device when necessary. + */ +static void +pcap_cleanup_bpf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; +#ifdef HAVE_BSD_IEEE80211 + int sock; + struct ifmediareq req; + struct ifreq ifr; +#endif + + if (pb->must_do_on_close != 0) { + /* + * There's something we have to do when closing this + * pcap_t. + */ +#ifdef HAVE_BSD_IEEE80211 + if (pb->must_do_on_close & MUST_CLEAR_RFMON) { + /* + * We put the interface into rfmon mode; + * take it out of rfmon mode. + * + * XXX - if somebody else wants it in rfmon + * mode, this code cannot know that, so it'll take + * it out of rfmon mode. + */ + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + fprintf(stderr, + "Can't restore interface flags (socket() failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } else { + memset(&req, 0, sizeof(req)); + pcapint_strlcpy(req.ifm_name, pb->device, + sizeof(req.ifm_name)); + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + fprintf(stderr, + "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } else { + if (req.ifm_current & IFM_IEEE80211_MONITOR) { + /* + * Rfmon mode is currently on; + * turn it off. + */ + memset(&ifr, 0, sizeof(ifr)); + (void)pcapint_strlcpy(ifr.ifr_name, + pb->device, + sizeof(ifr.ifr_name)); + ifr.ifr_media = + req.ifm_current & ~IFM_IEEE80211_MONITOR; + if (ioctl(sock, SIOCSIFMEDIA, + &ifr) == -1) { + fprintf(stderr, + "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n" + "Please adjust manually.\n", + strerror(errno)); + } + } + } + close(sock); + } + } +#endif /* HAVE_BSD_IEEE80211 */ + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + /* + * Attempt to destroy the usbusN interface that we created. + */ + if (pb->must_do_on_close & MUST_DESTROY_USBUS) { + if (if_nametoindex(pb->device) > 0) { + int s; + + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s >= 0) { + pcapint_strlcpy(ifr.ifr_name, pb->device, + sizeof(ifr.ifr_name)); + ioctl(s, SIOCIFDESTROY, &ifr); + close(s); + } + } + } +#endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ + /* + * Take this pcap out of the list of pcaps for which we + * have to take the interface out of some mode. + */ + pcapint_remove_from_pcaps_to_close(p); + pb->must_do_on_close = 0; + } + +#ifdef HAVE_ZEROCOPY_BPF + if (pb->zerocopy) { + /* + * Delete the mappings. Note that p->buffer gets + * initialized to one of the mmapped regions in + * this case, so do not try and free it directly; + * null it out so that pcapint_cleanup_live_common() + * doesn't try to free it. + */ + if (pb->zbuf1 != MAP_FAILED && pb->zbuf1 != NULL) + (void) munmap(pb->zbuf1, pb->zbufsize); + if (pb->zbuf2 != MAP_FAILED && pb->zbuf2 != NULL) + (void) munmap(pb->zbuf2, pb->zbufsize); + p->buffer = NULL; + } +#endif + if (pb->device != NULL) { + free(pb->device); + pb->device = NULL; + } + pcapint_cleanup_live_common(p); +} + +#ifdef __APPLE__ +static int +check_setif_failure(pcap_t *p, int error) +{ + int fd; + int err; + + if (error == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * No such device exists. + */ + if (p->opt.rfmon && strncmp(p->opt.device, "wlt", 3) == 0) { + /* + * Monitor mode was requested, and we're trying + * to open a "wltN" device. Assume that this + * is 10.4 and that we were asked to open an + * "enN" device; if that device exists, return + * "monitor mode not supported on the device". + */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd != -1) { + char *en_name; + + if (pcapint_asprintf(&en_name, "en%s", + p->opt.device + 3) == -1) { + /* + * We can't find out whether there's + * an underlying "enN" device, so + * just report "no such device". + */ + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + close(fd); + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + err = device_exists(fd, en_name, p->errbuf); + free(en_name); + if (err != 0) { + if (err == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * The underlying "enN" device + * exists, but there's no + * corresponding "wltN" device; + * that means that the "enN" + * device doesn't support + * monitor mode, probably + * because it's an Ethernet + * device rather than a + * wireless device. + */ + err = PCAP_ERROR_RFMON_NOTSUP; + } + } + close(fd); + } else { + /* + * We can't find out whether there's + * an underlying "enN" device, so + * just report "no such device". + */ + err = PCAP_ERROR_NO_SUCH_DEVICE; + pcapint_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, + "socket() failed"); + } + return (err); + } + + /* + * No such device. + */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + + /* + * Just return the error status; it's what we want, and, if it's + * PCAP_ERROR, the error string has been filled in. + */ + return (error); +} +#else +static int +check_setif_failure(pcap_t *p _U_, int error) +{ + /* + * Just return the error status; it's what we want, and, if it's + * PCAP_ERROR, the error string has been filled in. + */ + return (error); +} +#endif + +/* + * Default capture buffer size. + * 32K isn't very much for modern machines with fast networks; we + * pick .5M, as that's the maximum on at least some systems with BPF. + * + * However, on AIX 3.5, the larger buffer sized caused unrecoverable + * read failures under stress, so we leave it as 32K; yet another + * place where AIX's BPF is broken. + */ +#ifdef _AIX +#define DEFAULT_BUFSIZE 32768 +#else +#define DEFAULT_BUFSIZE 524288 +#endif + +static int +pcap_activate_bpf(pcap_t *p) +{ + struct pcap_bpf *pb = p->priv; + int status = 0; +#ifdef HAVE_BSD_IEEE80211 + int retv; +#endif + int fd; + struct bpf_version bv; +#ifdef __APPLE__ + int sockfd; + char *wltdev = NULL; +#endif +#ifdef BIOCGDLTLIST + struct bpf_dltlist bdl; +#if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) + int new_dlt; +#endif +#endif /* BIOCGDLTLIST */ +#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) + u_int spoof_eth_src = 1; +#endif + u_int v; + struct bpf_insn total_insn; + struct bpf_program total_prog; + struct utsname osinfo; + int have_osinfo = 0; +#ifdef HAVE_ZEROCOPY_BPF + struct bpf_zbuf bz; + u_int bufmode, zbufmax; +#endif + + fd = bpf_open(p->errbuf); + if (fd < 0) { + status = fd; + goto bad; + } + + p->fd = fd; + + if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCVERSION"); + status = PCAP_ERROR; + goto bad; + } + if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "kernel bpf filter out of date"); + status = PCAP_ERROR; + goto bad; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + pb->device = strdup(p->opt.device); + if (pb->device == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "strdup"); + status = PCAP_ERROR; + goto bad; + } + + /* + * Attempt to find out the version of the OS on which we're running. + */ + if (uname(&osinfo) == 0) + have_osinfo = 1; + +#ifdef __APPLE__ + /* + * See comment in pcap_can_set_rfmon_bpf() for an explanation + * of why we check the version number. + */ + if (p->opt.rfmon) { + if (have_osinfo) { + /* + * We assume osinfo.sysname is "Darwin", because + * __APPLE__ is defined. We just check the version. + */ + if (osinfo.release[0] < '8' && + osinfo.release[1] == '.') { + /* + * 10.3 (Darwin 7.x) or earlier. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + if (osinfo.release[0] == '8' && + osinfo.release[1] == '.') { + /* + * 10.4 (Darwin 8.x). s/en/wlt/ + */ + if (strncmp(p->opt.device, "en", 2) != 0) { + /* + * Not an enN device; check + * whether the device even exists. + */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd != -1) { + status = device_exists(sockfd, + p->opt.device, p->errbuf); + if (status == 0) { + /* + * The device exists, + * but it's not an + * enN device; that + * means it doesn't + * support monitor + * mode. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + } + close(sockfd); + } else { + /* + * We can't find out whether + * the device exists, so just + * report "no such device". + */ + status = PCAP_ERROR_NO_SUCH_DEVICE; + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "socket() failed"); + } + goto bad; + } + wltdev = malloc(strlen(p->opt.device) + 2); + if (wltdev == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + status = PCAP_ERROR; + goto bad; + } + strcpy(wltdev, "wlt"); + strcat(wltdev, p->opt.device + 2); + free(p->opt.device); + p->opt.device = wltdev; + } + /* + * Everything else is 10.5 or later; for those, + * we just open the enN device, and set the DLT. + */ + } + } +#endif /* __APPLE__ */ + + /* + * If this is FreeBSD, and the device name begins with "usbus", + * try to create the interface if it's not available. + */ +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + if (strncmp(p->opt.device, usbus_prefix, USBUS_PREFIX_LEN) == 0) { + /* + * Do we already have an interface with that name? + */ + if (if_nametoindex(p->opt.device) == 0) { + /* + * No. We need to create it, and, if we + * succeed, remember that we should destroy + * it when the pcap_t is closed. + */ + int s; + struct ifreq ifr; + + /* + * Open a socket to use for ioctls to + * create the interface. + */ + s = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (s < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't open socket"); + status = PCAP_ERROR; + goto bad; + } + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcapint_do_addexit(p)) { + /* + * "atexit()" failed; don't create the + * interface, just give up. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "atexit failed"); + close(s); + status = PCAP_ERROR; + goto bad; + } + + /* + * Create the interface. + */ + pcapint_strlcpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) { + if (errno == EINVAL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Invalid USB bus interface %s", + p->opt.device); + } else { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't create interface for %s", + p->opt.device); + } + close(s); + status = PCAP_ERROR; + goto bad; + } + + /* + * Make sure we clean this up when we close. + */ + pb->must_do_on_close |= MUST_DESTROY_USBUS; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcapint_add_to_pcaps_to_close(p); + } + } +#endif /* defined(__FreeBSD__) && defined(SIOCIFCREATE2) */ + +#ifdef HAVE_ZEROCOPY_BPF + /* + * If the BPF extension to set buffer mode is present, try setting + * the mode to zero-copy. If that fails, use regular buffering. If + * it succeeds but other setup fails, return an error to the user. + */ + bufmode = BPF_BUFMODE_ZBUF; + if (ioctl(fd, BIOCSETBUFMODE, (caddr_t)&bufmode) == 0) { + /* + * We have zerocopy BPF; use it. + */ + pb->zerocopy = 1; + + /* + * How to pick a buffer size: first, query the maximum buffer + * size supported by zero-copy. This also lets us quickly + * determine whether the kernel generally supports zero-copy. + * Then, if a buffer size was specified, use that, otherwise + * query the default buffer size, which reflects kernel + * policy for a desired default. Round to the nearest page + * size. + */ + if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGETZMAX"); + status = PCAP_ERROR; + goto bad; + } + + if (p->opt.buffer_size != 0) { + /* + * A buffer size was explicitly specified; use it. + */ + v = p->opt.buffer_size; + } else { + if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || + v < DEFAULT_BUFSIZE) + v = DEFAULT_BUFSIZE; + } +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#endif + pb->zbufsize = roundup(v, getpagesize()); + if (pb->zbufsize > zbufmax) + pb->zbufsize = zbufmax; + pb->zbuf1 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, + MAP_ANON, -1, 0); + pb->zbuf2 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, + MAP_ANON, -1, 0); + if (pb->zbuf1 == MAP_FAILED || pb->zbuf2 == MAP_FAILED) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "mmap"); + status = PCAP_ERROR; + goto bad; + } + memset(&bz, 0, sizeof(bz)); /* bzero() deprecated, replaced with memset() */ + bz.bz_bufa = pb->zbuf1; + bz.bz_bufb = pb->zbuf2; + bz.bz_buflen = pb->zbufsize; + if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETZBUF"); + status = PCAP_ERROR; + goto bad; + } + status = bpf_bind(fd, p->opt.device, ifnamsiz, p->errbuf); + if (status != BPF_BIND_SUCCEEDED) { + if (status == BPF_BIND_BUFFER_TOO_BIG) { + /* + * The requested buffer size + * is too big. Fail. + * + * XXX - should we do the "keep cutting + * the buffer size in half" loop here if + * we're using the default buffer size? + */ + status = PCAP_ERROR; + } + goto bad; + } + v = pb->zbufsize - sizeof(struct bpf_zbuf_header); + } else +#endif + { + /* + * We don't have zerocopy BPF. + * Set the buffer size. + */ + if (p->opt.buffer_size != 0) { + /* + * A buffer size was explicitly specified; use it. + */ + if (ioctl(fd, BIOCSBLEN, + (caddr_t)&p->opt.buffer_size) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "BIOCSBLEN: %s", p->opt.device); + status = PCAP_ERROR; + goto bad; + } + + /* + * Now bind to the device. + */ + status = bpf_bind(fd, p->opt.device, p->errbuf); + if (status != BPF_BIND_SUCCEEDED) { + if (status == BPF_BIND_BUFFER_TOO_BIG) { + /* + * The requested buffer size + * is too big. Fail. + */ + status = PCAP_ERROR; + goto bad; + } + + /* + * Special checks on macOS to deal with + * the way monitor mode was done on + * 10.4 Tiger. + */ + status = check_setif_failure(p, status); + goto bad; + } + } else { + /* + * No buffer size was explicitly specified. + * + * Try finding a good size for the buffer; + * DEFAULT_BUFSIZE may be too big, so keep + * cutting it in half until we find a size + * that works, or run out of sizes to try. + * If the default is larger, don't make it smaller. + */ + if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || + v < DEFAULT_BUFSIZE) + v = DEFAULT_BUFSIZE; + for ( ; v != 0; v >>= 1) { + /* + * Ignore the return value - this is because the + * call fails on BPF systems that don't have + * kernel malloc. And if the call fails, it's + * no big deal, we just continue to use the + * standard buffer size. + */ + (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v); + + status = bpf_bind(fd, p->opt.device, p->errbuf); + if (status == BPF_BIND_SUCCEEDED) + break; /* that size worked; we're done */ + + /* + * If the attempt failed because the + * buffer was too big, cut the buffer + * size in half and try again. + * + * Otherwise, fail. + */ + if (status != BPF_BIND_BUFFER_TOO_BIG) { + /* + * Special checks on macOS to deal + * with the way monitor mode was + * done on 10.4 Tiger. + */ + status = check_setif_failure(p, status); + goto bad; + } + } + + if (v == 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCSBLEN: %s: No buffer size worked", + p->opt.device); + status = PCAP_ERROR; + goto bad; + } + } + } + + /* Get the data link layer type. */ + if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLT"); + status = PCAP_ERROR; + goto bad; + } + +#ifdef _AIX + /* + * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT. + */ + switch (v) { + + case IFT_ETHER: + case IFT_ISO88023: + v = DLT_EN10MB; + break; + + case IFT_FDDI: + v = DLT_FDDI; + break; + + case IFT_ISO88025: + v = DLT_IEEE802; + break; + + case IFT_LOOP: + v = DLT_NULL; + break; + + default: + /* + * We don't know what to map this to yet. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u", + v); + status = PCAP_ERROR; + goto bad; + } +#endif +#if defined(_BSDI_VERSION) && _BSDI_VERSION >= 199510 + /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ + switch (v) { + + case DLT_SLIP: + v = DLT_SLIP_BSDOS; + break; + + case DLT_PPP: + v = DLT_PPP_BSDOS; + break; + + case 11: /*DLT_FR*/ + v = DLT_FRELAY; + break; + + case 12: /*DLT_C_HDLC*/ + v = DLT_CHDLC; + break; + } +#endif + +#ifdef BIOCGDLTLIST + /* + * We know the default link type -- now determine all the DLTs + * this interface supports. If this fails with EINVAL, it's + * not fatal; we just don't get to use the feature later. + */ + if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) { + status = PCAP_ERROR; + goto bad; + } + p->dlt_count = bdl.bfl_len; + p->dlt_list = bdl.bfl_list; + +#ifdef __APPLE__ + /* + * Monitor mode fun, continued. + * + * For 10.5 and, we're assuming, later releases, as noted above, + * 802.1 adapters that support monitor mode offer both DLT_EN10MB, + * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information + * DLT_ value. Choosing one of the 802.11 DLT_ values will turn + * monitor mode on. + * + * Therefore, if the user asked for monitor mode, we filter out + * the DLT_EN10MB value, as you can't get that in monitor mode, + * and, if the user didn't ask for monitor mode, we filter out + * the 802.11 DLT_ values, because selecting those will turn + * monitor mode on. Then, for monitor mode, if an 802.11-plus- + * radio DLT_ value is offered, we try to select that, otherwise + * we try to select DLT_IEEE802_11. + */ + if (have_osinfo) { + if (PCAP_ISDIGIT((unsigned)osinfo.release[0]) && + (osinfo.release[0] == '9' || + PCAP_ISDIGIT((unsigned)osinfo.release[1]))) { + /* + * 10.5 (Darwin 9.x), or later. + */ + new_dlt = find_802_11(&bdl); + if (new_dlt != -1) { + /* + * We have at least one 802.11 DLT_ value, + * so this is an 802.11 interface. + * new_dlt is the best of the 802.11 + * DLT_ values in the list. + */ + if (p->opt.rfmon) { + /* + * Our caller wants monitor mode. + * Purge DLT_EN10MB from the list + * of link-layer types, as selecting + * it will keep monitor mode off. + */ + remove_non_802_11(p); + + /* + * If the new mode we want isn't + * the default mode, attempt to + * select the new mode. + */ + if ((u_int)new_dlt != v) { + if (ioctl(p->fd, BIOCSDLT, + &new_dlt) != -1) { + /* + * We succeeded; + * make this the + * new DLT_ value. + */ + v = new_dlt; + } + } + } else { + /* + * Our caller doesn't want + * monitor mode. Unless this + * is being done by pcap_open_live(), + * purge the 802.11 link-layer types + * from the list, as selecting + * one of them will turn monitor + * mode on. + */ + if (!p->oldstyle) + remove_802_11(p); + } + } else { + if (p->opt.rfmon) { + /* + * The caller requested monitor + * mode, but we have no 802.11 + * link-layer types, so they + * can't have it. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + } + } + } +#elif defined(HAVE_BSD_IEEE80211) + /* + * *BSD with the new 802.11 ioctls. + * Do we want monitor mode? + */ + if (p->opt.rfmon) { + /* + * Try to put the interface into monitor mode. + */ + retv = monitor_mode(p, 1); + if (retv != 0) { + /* + * We failed. + */ + status = retv; + goto bad; + } + + /* + * We're in monitor mode. + * Try to find the best 802.11 DLT_ value and, if we + * succeed, try to switch to that mode if we're not + * already in that mode. + */ + new_dlt = find_802_11(&bdl); + if (new_dlt != -1) { + /* + * We have at least one 802.11 DLT_ value. + * new_dlt is the best of the 802.11 + * DLT_ values in the list. + * + * If the new mode we want isn't the default mode, + * attempt to select the new mode. + */ + if ((u_int)new_dlt != v) { + if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) { + /* + * We succeeded; make this the + * new DLT_ value. + */ + v = new_dlt; + } + } + } + } +#endif /* various platforms */ +#endif /* BIOCGDLTLIST */ + + /* + * If this is an Ethernet device, and we don't have a DLT_ list, + * give it a list with DLT_EN10MB and DLT_DOCSIS. (That'd give + * 802.11 interfaces DLT_DOCSIS, which isn't the right thing to + * do, but there's not much we can do about that without finding + * some other way of determining whether it's an Ethernet or 802.11 + * device.) + */ + if (v == DLT_EN10MB && p->dlt_count == 0) { + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + status = PCAP_ERROR; + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } +#ifdef PCAP_FDDIPAD + if (v == DLT_FDDI) + p->fddipad = PCAP_FDDIPAD; + else +#endif + p->fddipad = 0; + p->linktype = v; + +#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) + /* + * Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so + * the link-layer source address isn't forcibly overwritten. + * (Should we ignore errors? Should we do this only if + * we're open for writing?) + * + * XXX - I seem to remember some packet-sending bug in some + * BSDs - check CVS log for "bpf.c"? + */ + if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSHDRCMPLT"); + status = PCAP_ERROR; + goto bad; + } +#endif + /* set timeout */ +#ifdef HAVE_ZEROCOPY_BPF + /* + * In zero-copy mode, we just use the timeout in select(). + * XXX - what if we're in non-blocking mode and the *application* + * is using select() or poll() or kqueues or....? + */ + if (p->opt.timeout && !pb->zerocopy) { +#else + if (p->opt.timeout) { +#endif + /* + * XXX - is this seconds/nanoseconds in AIX? + * (Treating it as such doesn't fix the timeout + * problem described below.) + * + * XXX - Mac OS X 10.6 mishandles BIOCSRTIMEOUT in + * 64-bit userland - it takes, as an argument, a + * "struct BPF_TIMEVAL", which has 32-bit tv_sec + * and tv_usec, rather than a "struct timeval". + * + * If this platform defines "struct BPF_TIMEVAL", + * we check whether the structure size in BIOCSRTIMEOUT + * is that of a "struct timeval" and, if not, we use + * a "struct BPF_TIMEVAL" rather than a "struct timeval". + * (That way, if the bug is fixed in a future release, + * we will still do the right thing.) + */ + struct timeval to; +#ifdef HAVE_STRUCT_BPF_TIMEVAL + struct BPF_TIMEVAL bpf_to; + + if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) { + bpf_to.tv_sec = p->opt.timeout / 1000; + bpf_to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT"); + status = PCAP_ERROR; + goto bad; + } + } else { +#endif + to.tv_sec = p->opt.timeout / 1000; + to.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT"); + status = PCAP_ERROR; + goto bad; + } +#ifdef HAVE_STRUCT_BPF_TIMEVAL + } +#endif + } + +#ifdef BIOCIMMEDIATE + /* + * Darren Reed notes that + * + * On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the + * timeout appears to be ignored and it waits until the buffer + * is filled before returning. The result of not having it + * set is almost worse than useless if your BPF filter + * is reducing things to only a few packets (i.e. one every + * second or so). + * + * so we always turn BIOCIMMEDIATE mode on if this is AIX. + * + * For other platforms, we don't turn immediate mode on by default, + * as that would mean we get woken up for every packet, which + * probably isn't what you want for a packet sniffer. + * + * We set immediate mode if the caller requested it by calling + * pcap_set_immediate() before calling pcap_activate(). + */ +#ifndef _AIX + if (p->opt.immediate) { +#endif /* _AIX */ + v = 1; + if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCIMMEDIATE"); + status = PCAP_ERROR; + goto bad; + } +#ifndef _AIX + } +#endif /* _AIX */ +#else /* BIOCIMMEDIATE */ + if (p->opt.immediate) { + /* + * We don't support immediate mode. Fail. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Immediate mode not supported"); + status = PCAP_ERROR; + goto bad; + } +#endif /* BIOCIMMEDIATE */ + + if (p->opt.promisc) { + /* set promiscuous mode, just warn if it fails */ + if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCPROMISC"); + status = PCAP_WARNING_PROMISC_NOTSUP; + } + } + +#ifdef BIOCSTSTAMP + v = BPF_T_BINTIME; + if (ioctl(p->fd, BIOCSTSTAMP, &v) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSTSTAMP"); + status = PCAP_ERROR; + goto bad; + } +#endif /* BIOCSTSTAMP */ + + if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGBLEN"); + status = PCAP_ERROR; + goto bad; + } + p->bufsize = v; +#ifdef HAVE_ZEROCOPY_BPF + if (!pb->zerocopy) { +#endif + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + status = PCAP_ERROR; + goto bad; + } +#ifdef _AIX + /* For some strange reason this seems to prevent the EFAULT + * problems we have experienced from AIX BPF. */ + memset(p->buffer, 0x0, p->bufsize); +#endif +#ifdef HAVE_ZEROCOPY_BPF + } +#endif + + /* + * If there's no filter program installed, there's + * no indication to the kernel of what the snapshot + * length should be, so no snapshotting is done. + * + * Therefore, when we open the device, we install + * an "accept everything" filter with the specified + * snapshot length. + */ + total_insn.code = (u_short)(BPF_RET | BPF_K); + total_insn.jt = 0; + total_insn.jf = 0; + total_insn.k = p->snapshot; + + total_prog.bf_len = 1; + total_prog.bf_insns = &total_insn; + if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETF"); + status = PCAP_ERROR; + goto bad; + } + + /* + * On most BPF platforms, either you can do a "select()" or + * "poll()" on a BPF file descriptor and it works correctly, + * or you can do it and it will return "readable" if the + * hold buffer is full but not if the timeout expires *and* + * a non-blocking read will, if the hold buffer is empty + * but the store buffer isn't empty, rotate the buffers + * and return what packets are available. + * + * In the latter case, the fact that a non-blocking read + * will give you the available packets means you can work + * around the failure of "select()" and "poll()" to wake up + * and return "readable" when the timeout expires by using + * the timeout as the "select()" or "poll()" timeout, putting + * the BPF descriptor into non-blocking mode, and read from + * it regardless of whether "select()" reports it as readable + * or not. + * + * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()" + * won't wake up and return "readable" if the timer expires + * and non-blocking reads return EWOULDBLOCK if the hold + * buffer is empty, even if the store buffer is non-empty. + * + * This means the workaround in question won't work. + * + * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd" + * to -1, which means "sorry, you can't use 'select()' or 'poll()' + * here". On all other BPF platforms, we set it to the FD for + * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking + * read will, if the hold buffer is empty and the store buffer + * isn't empty, rotate the buffers and return what packets are + * there (and in sufficiently recent versions of OpenBSD + * "select()" and "poll()" should work correctly). + * + * XXX - what about AIX? + */ + p->selectable_fd = p->fd; /* assume select() works until we know otherwise */ + if (have_osinfo) { + /* + * We can check what OS this is. + */ + if (strcmp(osinfo.sysname, "FreeBSD") == 0) { + if (strncmp(osinfo.release, "4.3-", 4) == 0 || + strncmp(osinfo.release, "4.4-", 4) == 0) + p->selectable_fd = -1; + } + } + + p->read_op = pcap_read_bpf; + p->inject_op = pcap_inject_bpf; + p->setfilter_op = pcap_setfilter_bpf; + p->setdirection_op = pcap_setdirection_bpf; + p->set_datalink_op = pcap_set_datalink_bpf; + p->getnonblock_op = pcap_getnonblock_bpf; + p->setnonblock_op = pcap_setnonblock_bpf; + p->stats_op = pcap_stats_bpf; + p->cleanup_op = pcap_cleanup_bpf; + + return (status); + bad: + pcap_cleanup_bpf(p); + return (status); +} + +/* + * Not all interfaces can be bound to by BPF, so try to bind to + * the specified interface; return 0 if we fail with + * PCAP_ERROR_NO_SUCH_DEVICE (which means we got an ENXIO when we tried + * to bind, which means this interface isn't in the list of interfaces + * attached to BPF) and 1 otherwise. + */ +static int +check_bpf_bindable(const char *name) +{ + int fd; + char errbuf[PCAP_ERRBUF_SIZE]; + + /* + * On macOS, we don't do this check if the device name begins + * with "wlt"; at least some versions of macOS (actually, it + * was called "Mac OS X" then...) offer monitor mode capturing + * by having a separate "monitor mode" device for each wireless + * adapter, rather than by implementing the ioctls that + * {Free,Net,Open,DragonFly}BSD provide. Opening that device + * puts the adapter into monitor mode, which, at least for + * some adapters, causes them to disassociate from the network + * with which they're associated. + * + * Instead, we try to open the corresponding "en" device (so + * that we don't end up with, for users without sufficient + * privilege to open capture devices, a list of adapters that + * only includes the wlt devices). + */ +#ifdef __APPLE__ + if (strncmp(name, "wlt", 3) == 0) { + char *en_name; + size_t en_name_len; + + /* + * Try to allocate a buffer for the "en" + * device's name. + */ + en_name_len = strlen(name) - 1; + en_name = malloc(en_name_len + 1); + if (en_name == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + strcpy(en_name, "en"); + strcat(en_name, name + 3); + fd = bpf_open_and_bind(en_name, errbuf); + free(en_name); + } else +#endif /* __APPLE */ + fd = bpf_open_and_bind(name, errbuf); + if (fd < 0) { + /* + * Error - was it PCAP_ERROR_NO_SUCH_DEVICE? + */ + if (fd == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * Yes, so we can't bind to this because it's + * not something supported by BPF. + */ + return (0); + } + /* + * No, so we don't know whether it's supported or not; + * say it is, so that the user can at least try to + * open it and report the error (which is probably + * "you don't have permission to open BPF devices"; + * reporting those interfaces means users will ask + * "why am I getting a permissions error when I try + * to capture" rather than "why am I not seeing any + * interfaces", making the underlying problem clearer). + */ + return (1); + } + + /* + * Success. + */ + close(fd); + return (1); +} + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) +static int +get_usb_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * XXX - if there's a way to determine whether there's something + * plugged into a given USB bus, use that to determine whether + * this device is "connected" or not. + */ + return (0); +} + +static int +finddevs_usb(pcap_if_list_t *devlistp, char *errbuf) +{ + DIR *usbdir; + struct dirent *usbitem; + size_t name_max; + char *name; + + /* + * We might have USB sniffing support, so try looking for USB + * interfaces. + * + * We want to report a usbusN device for each USB bus, but + * usbusN interfaces might, or might not, exist for them - + * we create one if there isn't already one. + * + * So, instead, we look in /dev/usb for all buses and create + * a "usbusN" device for each one. + */ + usbdir = opendir("/dev/usb"); + if (usbdir == NULL) { + /* + * Just punt. + */ + return (0); + } + + /* + * Leave enough room for a 32-bit (10-digit) bus number. + * Yes, that's overkill, but we won't be using + * the buffer very long. + */ + name_max = USBUS_PREFIX_LEN + 10 + 1; + name = malloc(name_max); + if (name == NULL) { + closedir(usbdir); + return (0); + } + while ((usbitem = readdir(usbdir)) != NULL) { + char *p; + size_t busnumlen; + + if (strcmp(usbitem->d_name, ".") == 0 || + strcmp(usbitem->d_name, "..") == 0) { + /* + * Ignore these. + */ + continue; + } + p = strchr(usbitem->d_name, '.'); + if (p == NULL) + continue; + busnumlen = p - usbitem->d_name; + memcpy(name, usbus_prefix, USBUS_PREFIX_LEN); + memcpy(name + USBUS_PREFIX_LEN, usbitem->d_name, busnumlen); + *(name + USBUS_PREFIX_LEN + busnumlen) = '\0'; + /* + * There's an entry in this directory for every USB device, + * not for every bus; if there's more than one device on + * the bus, there'll be more than one entry for that bus, + * so we need to avoid adding multiple capture devices + * for each bus. + */ + if (pcapint_find_or_add_dev(devlistp, name, PCAP_IF_UP, + get_usb_if_flags, NULL, errbuf) == NULL) { + free(name); + closedir(usbdir); + return (PCAP_ERROR); + } + } + free(name); + closedir(usbdir); + return (0); +} +#endif + +/* + * Get additional flags for a device, using SIOCGIFMEDIA. + */ +#ifdef SIOCGIFMEDIA +static int +get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) +{ + int sock; + struct ifmediareq req; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "Can't create socket to get media information for %s", + name); + return (-1); + } + memset(&req, 0, sizeof(req)); + pcapint_strlcpy(req.ifm_name, name, sizeof(req.ifm_name)); + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + if (errno == EOPNOTSUPP || errno == EINVAL || errno == ENOTTY || + errno == ENODEV || errno == EPERM +#ifdef EPWROFF + || errno == EPWROFF +#endif + ) { + /* + * Not supported, so we can't provide any + * additional information. Assume that + * this means that "connected" vs. + * "disconnected" doesn't apply. + * + * The ioctl routine for Apple's pktap devices, + * annoyingly, checks for "are you root?" before + * checking whether the ioctl is valid, so it + * returns EPERM, rather than ENOTSUP, for the + * invalid SIOCGIFMEDIA, unless you're root. + * So, just as we do for some ethtool ioctls + * on Linux, which makes the same mistake, we + * also treat EPERM as meaning "not supported". + * + * And it appears that Apple's llw0 device, which + * appears to be part of the Skywalk subsystem: + * + * http://newosxbook.com/bonus/vol1ch16.html + * + * can sometimes return EPWROFF ("Device power + * is off") for that ioctl, so we treat *that* + * as another indication that we can't get a + * connection status. (If it *isn't* "powered + * off", it's reported as a wireless device, + * complete with an active/inactive state.) + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + close(sock); + return (0); + } + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "SIOCGIFMEDIA on %s failed", name); + close(sock); + return (-1); + } + close(sock); + + /* + * OK, what type of network is this? + */ + switch (IFM_TYPE(req.ifm_active)) { + + case IFM_IEEE80211: + /* + * Wireless. + */ + *flags |= PCAP_IF_WIRELESS; + break; + } + + /* + * Do we know whether it's connected? + */ + if (req.ifm_status & IFM_AVALID) { + /* + * Yes. + */ + if (req.ifm_status & IFM_ACTIVE) { + /* + * It's connected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; + } else { + /* + * It's disconnected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + } + } + return (0); +} +#else +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags, char *errbuf _U_) +{ + /* + * Nothing we can do other than mark loopback devices as "the + * connected/disconnected status doesn't apply". + * + * XXX - on Solaris, can we do what the dladm command does, + * i.e. get a connected/disconnected indication from a kstat? + * (Note that you can also get the link speed, and possibly + * other information, from a kstat as well.) + */ + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + return (0); +} +#endif + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + /* + * Get the list of regular interfaces first. + */ + if (pcapint_findalldevs_interfaces(devlistp, errbuf, check_bpf_bindable, + get_if_flags) == -1) + return (-1); /* failure */ + +#if defined(HAVE_SOLARIS_ANY_DEVICE) + /* + * Add the "any" device. + */ + if (pcap_add_any_dev(devlistp, errbuf) == NULL) + return (-1); +#endif + +#if defined(__FreeBSD__) && defined(SIOCIFCREATE2) + if (finddevs_usb(devlistp, errbuf) == -1) + return (-1); +#endif + + return (0); +} + +#ifdef HAVE_BSD_IEEE80211 +static int +monitor_mode(pcap_t *p, int set) +{ + struct pcap_bpf *pb = p->priv; + int sock; + struct ifmediareq req; + IFM_ULIST_TYPE *media_list; + int i; + int can_do; + struct ifreq ifr; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't open socket"); + return (PCAP_ERROR); + } + + memset(&req, 0, sizeof req); + pcapint_strlcpy(req.ifm_name, p->opt.device, sizeof req.ifm_name); + + /* + * Find out how many media types we have. + */ + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + /* + * Can't get the media types. + */ + switch (errno) { + + case ENXIO: + /* + * There's no such device. + * + * There's nothing more to say, so clear the + * error message. + */ + p->errbuf[0] = '\0'; + close(sock); + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case EINVAL: + /* + * Interface doesn't support SIOC{G,S}IFMEDIA. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + + default: + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMEDIA"); + close(sock); + return (PCAP_ERROR); + } + } + if (req.ifm_count == 0) { + /* + * No media types. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Allocate a buffer to hold all the media types, and + * get the media types. + */ + media_list = malloc(req.ifm_count * sizeof(*media_list)); + if (media_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + close(sock); + return (PCAP_ERROR); + } + req.ifm_ulist = media_list; + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMEDIA"); + free(media_list); + close(sock); + return (PCAP_ERROR); + } + + /* + * Look for an 802.11 "automatic" media type. + * We assume that all 802.11 adapters have that media type, + * and that it will carry the monitor mode supported flag. + */ + can_do = 0; + for (i = 0; i < req.ifm_count; i++) { + if (IFM_TYPE(media_list[i]) == IFM_IEEE80211 + && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) { + /* OK, does it do monitor mode? */ + if (media_list[i] & IFM_IEEE80211_MONITOR) { + can_do = 1; + break; + } + } + } + free(media_list); + if (!can_do) { + /* + * This adapter doesn't support monitor mode. + */ + close(sock); + return (PCAP_ERROR_RFMON_NOTSUP); + } + + if (set) { + /* + * Don't just check whether we can enable monitor mode, + * do so, if it's not already enabled. + */ + if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) { + /* + * Monitor mode isn't currently on, so turn it on, + * and remember that we should turn it off when the + * pcap_t is closed. + */ + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcapint_do_addexit(p)) { + /* + * "atexit()" failed; don't put the interface + * in monitor mode, just give up. + */ + close(sock); + return (PCAP_ERROR); + } + memset(&ifr, 0, sizeof(ifr)); + (void)pcapint_strlcpy(ifr.ifr_name, p->opt.device, + sizeof(ifr.ifr_name)); + ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; + if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, "SIOCSIFMEDIA"); + close(sock); + return (PCAP_ERROR); + } + + pb->must_do_on_close |= MUST_CLEAR_RFMON; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcapint_add_to_pcaps_to_close(p); + } + } + return (0); +} +#endif /* HAVE_BSD_IEEE80211 */ + +#if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) +/* + * Check whether we have any 802.11 link-layer types; return the best + * of the 802.11 link-layer types if we find one, and return -1 + * otherwise. + * + * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the + * best 802.11 link-layer type; any of the other 802.11-plus-radio + * headers are second-best; 802.11 with no radio information is + * the least good. + */ +static int +find_802_11(struct bpf_dltlist *bdlp) +{ + int new_dlt; + u_int i; + + /* + * Scan the list of DLT_ values, looking for 802.11 values, + * and, if we find any, choose the best of them. + */ + new_dlt = -1; + for (i = 0; i < bdlp->bfl_len; i++) { + switch (bdlp->bfl_list[i]) { + + case DLT_IEEE802_11: + /* + * 802.11, but no radio. + * + * Offer this, and select it as the new mode + * unless we've already found an 802.11 + * header with radio information. + */ + if (new_dlt == -1) + new_dlt = bdlp->bfl_list[i]; + break; + +#ifdef DLT_PRISM_HEADER + case DLT_PRISM_HEADER: +#endif +#ifdef DLT_AIRONET_HEADER + case DLT_AIRONET_HEADER: +#endif + case DLT_IEEE802_11_RADIO_AVS: + /* + * 802.11 with radio, but not radiotap. + * + * Offer this, and select it as the new mode + * unless we've already found the radiotap DLT_. + */ + if (new_dlt != DLT_IEEE802_11_RADIO) + new_dlt = bdlp->bfl_list[i]; + break; + + case DLT_IEEE802_11_RADIO: + /* + * 802.11 with radiotap. + * + * Offer this, and select it as the new mode. + */ + new_dlt = bdlp->bfl_list[i]; + break; + + default: + /* + * Not 802.11. + */ + break; + } + } + + return (new_dlt); +} +#endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */ + +#if defined(__APPLE__) && defined(BIOCGDLTLIST) +/* + * Remove non-802.11 header types from the list of DLT_ values, as we're in + * monitor mode, and those header types aren't supported in monitor mode. + */ +static void +remove_non_802_11(pcap_t *p) +{ + int i, j; + + /* + * Scan the list of DLT_ values and discard non-802.11 ones. + */ + j = 0; + for (i = 0; i < p->dlt_count; i++) { + switch (p->dlt_list[i]) { + + case DLT_EN10MB: + case DLT_RAW: + /* + * Not 802.11. Don't offer this one. + */ + continue; + + default: + /* + * Just copy this mode over. + */ + break; + } + + /* + * Copy this DLT_ value to its new position. + */ + p->dlt_list[j] = p->dlt_list[i]; + j++; + } + + /* + * Set the DLT_ count to the number of entries we copied. + */ + p->dlt_count = j; +} + +/* + * Remove 802.11 link-layer types from the list of DLT_ values, as + * we're not in monitor mode, and those DLT_ values will switch us + * to monitor mode. + */ +static void +remove_802_11(pcap_t *p) +{ + int i, j; + + /* + * Scan the list of DLT_ values and discard 802.11 values. + */ + j = 0; + for (i = 0; i < p->dlt_count; i++) { + switch (p->dlt_list[i]) { + + case DLT_IEEE802_11: +#ifdef DLT_PRISM_HEADER + case DLT_PRISM_HEADER: +#endif +#ifdef DLT_AIRONET_HEADER + case DLT_AIRONET_HEADER: +#endif + case DLT_IEEE802_11_RADIO: + case DLT_IEEE802_11_RADIO_AVS: +#ifdef DLT_PPI + case DLT_PPI: +#endif + /* + * 802.11. Don't offer this one. + */ + continue; + + default: + /* + * Just copy this mode over. + */ + break; + } + + /* + * Copy this DLT_ value to its new position. + */ + p->dlt_list[j] = p->dlt_list[i]; + j++; + } + + /* + * Set the DLT_ count to the number of entries we copied. + */ + p->dlt_count = j; +} +#endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */ + +static int +pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_bpf *pb = p->priv; + + /* + * Free any user-mode filter we might happen to have installed. + */ + pcap_freecode(&p->fcode); + + /* + * Try to install the kernel filter. + */ + if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) == 0) { + /* + * It worked. + */ + pb->filtering_in_kernel = 1; /* filtering in the kernel */ + + /* + * Discard any previously-received packets, as they might + * have passed whatever filter was formerly in effect, but + * might not pass this filter (BIOCSETF discards packets + * buffered in the kernel, so you can lose packets in any + * case). + */ + p->cc = 0; + return (0); + } + + /* + * We failed. + * + * If it failed with EINVAL, that's probably because the program + * is invalid or too big. Validate it ourselves; if we like it + * (we currently allow backward branches, to support protochain), + * run it in userland. (There's no notion of "too big" for + * userland.) + * + * Otherwise, just give up. + * XXX - if the copy of the program into the kernel failed, + * we will get EINVAL rather than, say, EFAULT on at least + * some kernels. + */ + if (errno != EINVAL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETF"); + return (-1); + } + + /* + * pcapint_install_bpf_program() validates the program. + * + * XXX - what if we already have a filter in the kernel? + */ + if (pcapint_install_bpf_program(p, fp) < 0) + return (-1); + pb->filtering_in_kernel = 0; /* filtering in userland */ + return (0); +} + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +#if defined(BIOCSDIRECTION) +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) +{ + u_int direction; + const char *direction_name; + + /* + * FreeBSD and NetBSD. + */ + switch (d) { + + case PCAP_D_IN: + /* + * Incoming, but not outgoing, so accept only + * incoming packets. + */ + direction = BPF_D_IN; + direction_name = "\"incoming only\""; + break; + + case PCAP_D_OUT: + /* + * Outgoing, but not incoming, so accept only + * outgoing packets. + */ + direction = BPF_D_OUT; + direction_name = "\"outgoing only\""; + break; + + default: + /* + * Incoming and outgoing, so accept both + * incoming and outgoing packets. + * + * It's guaranteed, at this point, that d is a valid + * direction value, so we know that this is PCAP_D_INOUT + * if it's not PCAP_D_IN or PCAP_D_OUT. + */ + direction = BPF_D_INOUT; + direction_name = "\"incoming and outgoing\""; + break; + } + + if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set direction to %s", direction_name); + return (-1); + } + return (0); +} +#elif defined(BIOCSDIRFILT) +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) +{ + u_int dirfilt; + const char *direction_name; + + /* + * OpenBSD; same functionality, different names, different + * semantics (the flags mean "*don't* capture packets in + * that direction", not "*capture only* packets in that + * direction"). + */ + switch (d) { + + case PCAP_D_IN: + /* + * Incoming, but not outgoing, so filter out + * outgoing packets. + */ + dirfilt = BPF_DIRECTION_OUT; + direction_name = "\"incoming only\""; + break; + + case PCAP_D_OUT: + /* + * Outgoing, but not incoming, so filter out + * incoming packets. + */ + dirfilt = BPF_DIRECTION_IN; + direction_name = "\"outgoing only\""; + break; + + default: + /* + * Incoming and outgoing, so don't filter out + * any packets based on direction. + * + * It's guaranteed, at this point, that d is a valid + * direction value, so we know that this is PCAP_D_INOUT + * if it's not PCAP_D_IN or PCAP_D_OUT. + */ + dirfilt = 0; + direction_name = "\"incoming and outgoing\""; + break; + } + if (ioctl(p->fd, BIOCSDIRFILT, &dirfilt) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set direction to %s", direction_name); + return (-1); + } + return (0); +} +#elif defined(BIOCSSEESENT) +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) +{ + u_int seesent; + const char *direction_name; + + /* + * OS with just BIOCSSEESENT. + */ + switch (d) { + + case PCAP_D_IN: + /* + * Incoming, but not outgoing, so we don't want to + * see transmitted packets. + */ + seesent = 0; + direction_name = "\"incoming only\""; + break; + + case PCAP_D_OUT: + /* + * Outgoing, but not incoming; we can't specify that. + */ + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction to \"outgoing only\" is not supported on this device"); + return (-1); + + default: + /* + * Incoming and outgoing, so we want to see transmitted + * packets. + * + * It's guaranteed, at this point, that d is a valid + * direction value, so we know that this is PCAP_D_INOUT + * if it's not PCAP_D_IN or PCAP_D_OUT. + */ + seesent = 1; + direction_name = "\"incoming and outgoing\""; + break; + } + + if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set direction to %s", direction_name); + return (-1); + } + return (0); +} +#else +static int +pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d _U_) +{ + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction is not supported on this device"); + return (-1); +} +#endif + +#ifdef BIOCSDLT +static int +pcap_set_datalink_bpf(pcap_t *p, int dlt) +{ + if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set DLT %d", dlt); + return (-1); + } + return (0); +} +#else +static int +pcap_set_datalink_bpf(pcap_t *p _U_, int dlt _U_) +{ + return (0); +} +#endif + +/* + * Platform-specific information. + */ +const char * +pcap_lib_version(void) +{ +#ifdef HAVE_ZEROCOPY_BPF + return (PCAP_VERSION_STRING " (with zerocopy support)"); +#else + return (PCAP_VERSION_STRING); +#endif +} diff --git a/src/libpcap-1.10.5/pcap-bpf.h b/src/libpcap-1.10.5/pcap-bpf.h new file mode 100644 index 0000000000..ebb64c3f96 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bpf.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/src/libpcap-1.10.5/pcap-bt-linux.c b/src/libpcap-1.10.5/pcap-bt-linux.c new file mode 100644 index 0000000000..2fc51665e4 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bt-linux.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Bluetooth sniffing API implementation for Linux platform + * By Paolo Abeni + * + */ + +#include + +#include "pcap-int.h" +#include "pcap-bt-linux.h" +#include "pcap/bluetooth.h" +#include "diag-control.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BT_IFACE "bluetooth" +#define BT_CTRL_SIZE 128 + +/* forward declaration */ +static int bt_activate(pcap_t *); +static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *); +static int bt_inject_linux(pcap_t *, const void *, int); +static int bt_setdirection_linux(pcap_t *, pcap_direction_t); +static int bt_stats_linux(pcap_t *, struct pcap_stat *); + +/* + * Private data for capturing on Linux Bluetooth devices. + */ +struct pcap_bt { + int dev_id; /* device ID of device we're bound to */ +}; + +int +bt_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + struct hci_dev_list_req *dev_list; + struct hci_dev_req *dev_req; + int sock; + unsigned i; + int ret = 0; + + sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (sock < 0) + { + /* if bluetooth is not supported this is not fatal*/ + if (errno == EAFNOSUPPORT) + return 0; + pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, + errno, "Can't open raw Bluetooth socket"); + return PCAP_ERROR; + } + + dev_list = malloc(HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + if (!dev_list) + { + snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't allocate %zu bytes for Bluetooth device list", + HCI_MAX_DEV * sizeof(*dev_req) + sizeof(*dev_list)); + ret = PCAP_ERROR; + goto done; + } + + /* + * Zero the complete header, which is larger than dev_num because of tail + * padding, to silence Valgrind, which overshoots validating that dev_num + * has been set. + * https://github.com/the-tcpdump-group/libpcap/issues/1083 + * https://bugs.kde.org/show_bug.cgi?id=448464 + */ + memset(dev_list, 0, sizeof(*dev_list)); + dev_list->dev_num = HCI_MAX_DEV; + + if (ioctl(sock, HCIGETDEVLIST, (void *) dev_list) < 0) + { + pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, + errno, "Can't get Bluetooth device list via ioctl"); + ret = PCAP_ERROR; + goto free; + } + + dev_req = dev_list->dev_req; + for (i = 0; i < dev_list->dev_num; i++, dev_req++) { + char dev_name[20], dev_descr[40]; + + snprintf(dev_name, sizeof(dev_name), BT_IFACE"%u", dev_req->dev_id); + snprintf(dev_descr, sizeof(dev_descr), "Bluetooth adapter number %u", i); + + /* + * Bluetooth is a wireless technology. + * XXX - if there's the notion of associating with a + * network, and we can determine whether the interface + * is associated with a network, check that and set + * the status to PCAP_IF_CONNECTION_STATUS_CONNECTED + * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED. + */ + if (pcapint_add_dev(devlistp, dev_name, PCAP_IF_WIRELESS, dev_descr, err_str) == NULL) + { + ret = PCAP_ERROR; + break; + } + } + +free: + free(dev_list); + +done: + close(sock); + return ret; +} + +pcap_t * +bt_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; + + /* Does this look like a Bluetooth device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with BT_IFACE? */ + if (strncmp(cp, BT_IFACE, sizeof BT_IFACE - 1) != 0) { + /* Nope, doesn't begin with BT_IFACE */ + *is_ours = 0; + return NULL; + } + /* Yes - is BT_IFACE followed by a number? */ + cp += sizeof BT_IFACE - 1; + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt); + if (p == NULL) + return (NULL); + + p->activate_op = bt_activate; + return (p); +} + +static int +bt_activate(pcap_t* handle) +{ + struct pcap_bt *handlep = handle->priv; + struct sockaddr_hci addr; + int opt; + int dev_id; + struct hci_filter flt; + int err = PCAP_ERROR; + + /* get bt interface id */ + if (sscanf(handle->opt.device, BT_IFACE"%d", &dev_id) != 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get Bluetooth device index from %s", + handle->opt.device); + return PCAP_ERROR; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header)+handle->snapshot; + handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR; + + handle->read_op = bt_read_linux; + handle->inject_op = bt_inject_linux; + handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = bt_setdirection_linux; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + handle->stats_op = bt_stats_linux; + handlep->dev_id = dev_id; + + /* Create HCI socket */ + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't create raw socket"); + return PCAP_ERROR; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't allocate dump buffer"); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't enable data direction info"); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't enable time stamp"); + goto close_fail; + } + + /* Setup filter, do not call hci function to avoid dependence on + * external libs */ + memset(&flt, 0, sizeof(flt)); + memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask)); + memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask)); + if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't set filter"); + goto close_fail; + } + + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = handlep->dev_id; +#ifdef HAVE_STRUCT_SOCKADDR_HCI_HCI_CHANNEL + addr.hci_channel = HCI_CHANNEL_RAW; +#endif + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't attach to device %d", handlep->dev_id); + goto close_fail; + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to Bluetooth devices. + */ + err = PCAP_ERROR_RFMON_NOTSUP; + goto close_fail; + } + + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, + &handle->opt.buffer_size, + sizeof(handle->opt.buffer_size)) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + errno, PCAP_ERRBUF_SIZE, "SO_RCVBUF"); + goto close_fail; + } + } + + handle->selectable_fd = handle->fd; + return 0; + +close_fail: + pcapint_cleanup_live_common(handle); + return err; +} + +static int +bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv; + ssize_t ret; + struct pcap_pkthdr pkth; + pcap_bluetooth_h4_header* bthdr; + u_char *pktd; + int in = 0; + + pktd = (u_char *)handle->buffer + BT_CTRL_SIZE; + bthdr = (pcap_bluetooth_h4_header*)(void *)pktd; + iv.iov_base = pktd + sizeof(pcap_bluetooth_h4_header); + iv.iov_len = handle->snapshot; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iv; + msg.msg_iovlen = 1; + msg.msg_control = handle->buffer; + msg.msg_controllen = BT_CTRL_SIZE; + + /* ignore interrupt system call error */ + do { + if (handle->break_loop) + { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + ret = recvmsg(handle->fd, &msg, 0); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Nonblocking mode, no data */ + return 0; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't receive packet"); + return PCAP_ERROR; + } + + pkth.caplen = (bpf_u_int32)ret; + + /* get direction and timestamp*/ + cmsg = CMSG_FIRSTHDR(&msg); + while (cmsg) { + switch (cmsg->cmsg_type) { + case HCI_CMSG_DIR: + memcpy(&in, CMSG_DATA(cmsg), sizeof in); + break; + case HCI_CMSG_TSTAMP: + memcpy(&pkth.ts, CMSG_DATA(cmsg), + sizeof pkth.ts); + break; + } + // for musl libc CMSG_NXTHDR() +DIAG_OFF_SIGN_COMPARE + cmsg = CMSG_NXTHDR(&msg, cmsg); +DIAG_ON_SIGN_COMPARE + } + switch (handle->direction) { + + case PCAP_D_IN: + if (!in) + return 0; + break; + + case PCAP_D_OUT: + if (in) + return 0; + break; + + default: + break; + } + + bthdr->direction = htonl(in != 0); + pkth.caplen+=sizeof(pcap_bluetooth_h4_header); + pkth.len = pkth.caplen; + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { + callback(user, &pkth, pktd); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +bt_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on Bluetooth devices"); + return (-1); +} + + +static int +bt_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_bt *handlep = handle->priv; + int ret; + struct hci_dev_info dev_info; + struct hci_dev_stats * s = &dev_info.stat; + dev_info.dev_id = handlep->dev_id; + + /* ignore eintr */ + do { + ret = ioctl(handle->fd, HCIGETDEVINFO, (void *)&dev_info); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't get stats via ioctl"); + return (-1); + + } + + /* we receive both rx and tx frames, so cumulate all stats */ + stats->ps_recv = s->evt_rx + s->acl_rx + s->sco_rx + s->cmd_tx + + s->acl_tx +s->sco_tx; + stats->ps_drop = s->err_rx + s->err_tx; + stats->ps_ifdrop = 0; + return 0; +} + +static int +bt_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + /* + * It's guaranteed, at this point, that d is a valid + * direction value. + */ + p->direction = d; + return 0; +} diff --git a/src/libpcap-1.10.5/pcap-bt-linux.h b/src/libpcap-1.10.5/pcap-bt-linux.h new file mode 100644 index 0000000000..163bd341fc --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bt-linux.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Bluetooth sniffing API implementation for Linux platform + * By Paolo Abeni + */ + +/* + * Prototypes for Bluetooth-related functions + */ +int bt_findalldevs(pcap_if_list_t *devlistp, char *err_str); +pcap_t *bt_create(const char *device, char *ebuf, int *is_ours); diff --git a/src/libpcap-1.10.5/pcap-bt-monitor-linux.c b/src/libpcap-1.10.5/pcap-bt-monitor-linux.c new file mode 100644 index 0000000000..dfba80516d --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bt-monitor-linux.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "pcap/bluetooth.h" +#include "pcap-int.h" +#include "diag-control.h" + +#include "pcap-bt-monitor-linux.h" + +#define BT_CONTROL_SIZE 32 +#define INTERFACE_NAME "bluetooth-monitor" + +/* + * Private data. + * Currently contains nothing. + */ +struct pcap_bt_monitor { + int dummy; +}; + +/* + * Fields and alignment must match the declaration in the Linux kernel 3.4+. + * See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h. + */ +struct hci_mon_hdr { + uint16_t opcode; + uint16_t index; + uint16_t len; +} __attribute__((packed)); + +int +bt_monitor_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + int ret = 0; + + /* + * Bluetooth is a wireless technology. + * + * This is a device to monitor all Bluetooth interfaces, so + * there's no notion of "connected" or "disconnected", any + * more than there's a notion of "connected" or "disconnected" + * for the "any" device. + */ + if (pcapint_add_dev(devlistp, INTERFACE_NAME, + PCAP_IF_WIRELESS|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, + "Bluetooth Linux Monitor", err_str) == NULL) + { + ret = PCAP_ERROR; + } + + return ret; +} + +static int +bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv[2]; + ssize_t ret; + struct pcap_pkthdr pkth; + pcap_bluetooth_linux_monitor_header *bthdr; + u_char *pktd; + struct hci_mon_hdr hdr; + + pktd = (u_char *)handle->buffer + BT_CONTROL_SIZE; + bthdr = (pcap_bluetooth_linux_monitor_header*)(void *)pktd; + + iv[0].iov_base = &hdr; + iv[0].iov_len = sizeof(hdr); + iv[1].iov_base = pktd + sizeof(pcap_bluetooth_linux_monitor_header); + iv[1].iov_len = handle->snapshot; + + memset(&pkth.ts, 0, sizeof(pkth.ts)); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iv; + msg.msg_iovlen = 2; + msg.msg_control = handle->buffer; + msg.msg_controllen = BT_CONTROL_SIZE; + + do { + if (handle->break_loop) + { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + ret = recvmsg(handle->fd, &msg, 0); + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Nonblocking mode, no data */ + return 0; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't receive packet"); + return PCAP_ERROR; + } + + pkth.caplen = (bpf_u_int32)(ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header)); + pkth.len = pkth.caplen; + + // for musl libc CMSG_NXTHDR() +DIAG_OFF_SIGN_COMPARE + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { +DIAG_ON_SIGN_COMPARE + if (cmsg->cmsg_level != SOL_SOCKET) continue; + + if (cmsg->cmsg_type == SCM_TIMESTAMP) { + memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts)); + } + } + + bthdr->adapter_id = htons(hdr.index); + bthdr->opcode = htons(hdr.opcode); + + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { + callback(user, &pkth, pktd); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +bt_monitor_inject(pcap_t *handle, const void *buf _U_, int size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported yet on Bluetooth monitor devices"); + return PCAP_ERROR; +} + +static int +bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats) +{ + stats->ps_recv = 0; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + + return 0; +} + +static int +bt_monitor_activate(pcap_t* handle) +{ + struct sockaddr_hci addr; + int err = PCAP_ERROR; + int opt; + + if (handle->opt.rfmon) { + /* monitor mode doesn't apply here */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + handle->bufsize = BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header) + handle->snapshot; + handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR; + + handle->read_op = bt_monitor_read; + handle->inject_op = bt_monitor_inject; + handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = NULL; /* Not implemented */ + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + handle->stats_op = bt_monitor_stats; + + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't create raw socket"); + return PCAP_ERROR; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't allocate dump buffer"); + goto close_fail; + } + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = HCI_DEV_NONE; + addr.hci_channel = HCI_CHANNEL_MONITOR; + + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't attach to interface"); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't enable time stamp"); + goto close_fail; + } + + handle->selectable_fd = handle->fd; + + return 0; + +close_fail: + pcapint_cleanup_live_common(handle); + return err; +} + +pcap_t * +bt_monitor_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + const char *cp; + + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + + if (strcmp(cp, INTERFACE_NAME) != 0) { + *is_ours = 0; + return NULL; + } + + *is_ours = 1; + p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt_monitor); + if (p == NULL) + return NULL; + + p->activate_op = bt_monitor_activate; + + return p; +} diff --git a/src/libpcap-1.10.5/pcap-bt-monitor-linux.h b/src/libpcap-1.10.5/pcap-bt-monitor-linux.h new file mode 100644 index 0000000000..8133710a26 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-bt-monitor-linux.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int bt_monitor_findalldevs(pcap_if_list_t *devlistp, char *err_str); +pcap_t *bt_monitor_create(const char *device, char *ebuf, int *is_ours); diff --git a/src/libpcap-1.10.5/pcap-common.c b/src/libpcap-1.10.5/pcap-common.c new file mode 100644 index 0000000000..26042d959b --- /dev/null +++ b/src/libpcap-1.10.5/pcap-common.c @@ -0,0 +1,1577 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-common.c - common code for pcap and pcapng files + */ + +#include + +#include + +#include "pcap-int.h" + +#include "pcap-common.h" + +/* + * We don't write DLT_* values to capture files, because they're not the + * same on all platforms. + * + * Unfortunately, the various flavors of BSD have not always used the same + * numerical values for the same data types, and various patches to + * libpcap for non-BSD OSes have added their own DLT_* codes for link + * layer encapsulation types seen on those OSes, and those codes have had, + * in some cases, values that were also used, on other platforms, for other + * link layer encapsulation types. + * + * This means that capture files of a type whose numerical DLT_* code + * means different things on different BSDs, or with different versions + * of libpcap, can't always be read on systems other than those like + * the one running on the machine on which the capture was made. + * + * Instead, we define here a set of LINKTYPE_* codes, and map DLT_* codes + * to LINKTYPE_* codes when writing a savefile header, and map LINKTYPE_* + * codes to DLT_* codes when reading a savefile header. + * + * For those DLT_* codes that have, as far as we know, the same values on + * all platforms (DLT_NULL through DLT_FDDI), we define LINKTYPE_xxx as + * DLT_xxx; that way, captures of those types can still be read by + * versions of libpcap that map LINKTYPE_* values to DLT_* values, and + * captures of those types written by versions of libpcap that map DLT_ + * values to LINKTYPE_ values can still be read by older versions + * of libpcap. + * + * The other LINKTYPE_* codes are given values starting at 100, in the + * hopes that no DLT_* code will be given one of those values. + * + * In order to ensure that a given LINKTYPE_* code's value will refer to + * the same encapsulation type on all platforms, you should not allocate + * a new LINKTYPE_* value without consulting + * "tcpdump-workers@lists.tcpdump.org". The tcpdump developers will + * allocate a value for you, and will not subsequently allocate it to + * anybody else; that value will be added to the "pcap.h" in the + * tcpdump.org Git repository, so that a future libpcap release will + * include it. + * + * You should, if possible, also contribute patches to libpcap and tcpdump + * to handle the new encapsulation type, so that they can also be checked + * into the tcpdump.org Git repository and so that they will appear in + * future libpcap and tcpdump releases. + * + * Do *NOT* assume that any values after the largest value in this file + * are available; you might not have the most up-to-date version of this + * file, and new values after that one might have been assigned. Also, + * do *NOT* use any values below 100 - those might already have been + * taken by one (or more!) organizations. + * + * Any platform that defines additional DLT_* codes should: + * + * request a LINKTYPE_* code and value from tcpdump.org, + * as per the above; + * + * add, in their version of libpcap, an entry to map + * those DLT_* codes to the corresponding LINKTYPE_* + * code; + * + * redefine, in their "net/bpf.h", any DLT_* values + * that collide with the values used by their additional + * DLT_* codes, to remove those collisions (but without + * making them collide with any of the LINKTYPE_* + * values equal to 50 or above; they should also avoid + * defining DLT_* values that collide with those + * LINKTYPE_* values, either). + */ + +/* + * These values the DLT_ values for which are the same on all platforms, + * and that have been defined by for ages. + * + * For those, the LINKTYPE_ values are equal to the DLT_ values. + * + * LINKTYPE_LOW_MATCHING_MIN is the lowest such value; + * LINKTYPE_LOW_MATCHING_MAX is the highest such value. + */ +#define LINKTYPE_LOW_MATCHING_MIN 0 /* lowest value in this "matching" range */ +#define LINKTYPE_NULL DLT_NULL +#define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */ +#define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */ +#define LINKTYPE_AX25 DLT_AX25 +#define LINKTYPE_PRONET DLT_PRONET +#define LINKTYPE_CHAOS DLT_CHAOS +#define LINKTYPE_IEEE802_5 DLT_IEEE802 /* DLT_IEEE802 is used for 802.5 Token Ring */ +#define LINKTYPE_ARCNET_BSD DLT_ARCNET /* BSD-style headers */ +#define LINKTYPE_SLIP DLT_SLIP +#define LINKTYPE_PPP DLT_PPP +#define LINKTYPE_FDDI DLT_FDDI + +#define LINKTYPE_LOW_MATCHING_MAX LINKTYPE_FDDI /* highest value in this "matching" range */ + +/* + * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662 + * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol + * field) at the beginning of the packet. + * + * This is for use when there is always such a header; the address field + * might be 0xff, for regular PPP, or it might be an address field for Cisco + * point-to-point with HDLC framing as per section 4.3.1 of RFC 1547 ("Cisco + * HDLC"). This is, for example, what you get with NetBSD's DLT_PPP_SERIAL. + * + * We give it the same value as NetBSD's DLT_PPP_SERIAL, in the hopes that + * nobody else will choose a DLT_ value of 50, and so that DLT_PPP_SERIAL + * captures will be written out with a link type that NetBSD's tcpdump + * can read. + */ +#define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */ + +#define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */ + +#define LINKTYPE_SYMANTEC_FIREWALL 99 /* Symantec Enterprise Firewall */ + +/* + * These correspond to DLT_s that have different values on different + * platforms; we map between these values in capture files and + * the DLT_ values as returned by pcap_datalink() and passed to + * pcap_open_dead(). + */ +#define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */ +#define LINKTYPE_RAW 101 /* raw IP */ +#define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */ +#define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */ + +/* + * Values starting with 104 are used for newly-assigned link-layer + * header type values; for those link-layer header types, the DLT_ + * value returned by pcap_datalink() and passed to pcap_open_dead(), + * and the LINKTYPE_ value that appears in capture files, are the + * same. + * + * LINKTYPE_HIGH_MATCHING_MIN is the lowest such value; + * LINKTYPE_HIGH_MATCHING_MAX is the highest such value. + */ +#define LINKTYPE_HIGH_MATCHING_MIN 104 /* lowest value in the "matching" range */ + +#define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ +#define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ +#define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */ +#define LINKTYPE_FRELAY 107 /* Frame Relay */ +#define LINKTYPE_LOOP 108 /* OpenBSD loopback */ +#define LINKTYPE_ENC 109 /* OpenBSD IPSEC enc */ + +/* + * These two types are reserved for future use. + */ +#define LINKTYPE_LANE8023 110 /* ATM LANE + 802.3 */ +#define LINKTYPE_HIPPI 111 /* NetBSD HIPPI */ + +/* + * Used for NetBSD DLT_HDLC; from looking at the one driver in NetBSD + * that uses it, it's Cisco HDLC, so it's the same as DLT_C_HDLC/ + * LINKTYPE_C_HDLC, but we define a separate value to avoid some + * compatibility issues with programs on NetBSD. + * + * All code should treat LINKTYPE_NETBSD_HDLC and LINKTYPE_C_HDLC the same. + */ +#define LINKTYPE_NETBSD_HDLC 112 /* NetBSD HDLC framing */ + +#define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */ +#define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */ +#define LINKTYPE_ECONET 115 /* Acorn Econet */ + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define LINKTYPE_IPFILTER 116 + +#define LINKTYPE_PFLOG 117 /* OpenBSD DLT_PFLOG */ +#define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */ +#define LINKTYPE_IEEE802_11_PRISM 119 /* 802.11 plus Prism II monitor mode radio metadata header */ +#define LINKTYPE_IEEE802_11_AIRONET 120 /* 802.11 plus FreeBSD Aironet driver radio metadata header */ + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define LINKTYPE_HHDLC 121 + +#define LINKTYPE_IP_OVER_FC 122 /* RFC 2625 IP-over-Fibre Channel */ +#define LINKTYPE_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define LINKTYPE_RIO 124 /* RapidIO */ +#define LINKTYPE_PCI_EXP 125 /* PCI Express */ +#define LINKTYPE_AURORA 126 /* Xilinx Aurora link layer */ + +#define LINKTYPE_IEEE802_11_RADIOTAP 127 /* 802.11 plus radiotap radio metadata header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define LINKTYPE_TZSP 128 /* Tazmen Sniffer Protocol */ + +#define LINKTYPE_ARCNET_LINUX 129 /* Linux-style headers */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MLPPP 130 +#define LINKTYPE_JUNIPER_MLFR 131 +#define LINKTYPE_JUNIPER_ES 132 +#define LINKTYPE_JUNIPER_GGSN 133 +#define LINKTYPE_JUNIPER_MFR 134 +#define LINKTYPE_JUNIPER_ATM2 135 +#define LINKTYPE_JUNIPER_SERVICES 136 +#define LINKTYPE_JUNIPER_ATM1 137 + +#define LINKTYPE_APPLE_IP_OVER_IEEE1394 138 /* Apple IP-over-IEEE 1394 cooked header */ + +#define LINKTYPE_MTP2_WITH_PHDR 139 +#define LINKTYPE_MTP2 140 +#define LINKTYPE_MTP3 141 +#define LINKTYPE_SCCP 142 + +#define LINKTYPE_DOCSIS 143 /* DOCSIS MAC frames */ + +#define LINKTYPE_LINUX_IRDA 144 /* Linux-IrDA */ + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define LINKTYPE_IBM_SP 145 +#define LINKTYPE_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that LINKTYPE_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, in those cases, ask "tcpdump-workers@lists.tcpdump.org" for a + * new DLT_ and LINKTYPE_ value, as per the comment in pcap/bpf.h, and use + * the type you're given. + */ +#define LINKTYPE_USER0 147 +#define LINKTYPE_USER1 148 +#define LINKTYPE_USER2 149 +#define LINKTYPE_USER3 150 +#define LINKTYPE_USER4 151 +#define LINKTYPE_USER5 152 +#define LINKTYPE_USER6 153 +#define LINKTYPE_USER7 154 +#define LINKTYPE_USER8 155 +#define LINKTYPE_USER9 156 +#define LINKTYPE_USER10 157 +#define LINKTYPE_USER11 158 +#define LINKTYPE_USER12 159 +#define LINKTYPE_USER13 160 +#define LINKTYPE_USER14 161 +#define LINKTYPE_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + */ +#define LINKTYPE_IEEE802_11_AVS 163 /* 802.11 plus AVS radio metadata header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The corresponding + * DLT_s are used for passing on chassis-internal + * metainformation such as QOS profiles, etc.. + */ +#define LINKTYPE_JUNIPER_MONITOR 164 + +/* + * BACnet MS/TP frames. + */ +#define LINKTYPE_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accommodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define LINKTYPE_PPP_PPPD 166 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define LINKTYPE_JUNIPER_PPPOE 167 +#define LINKTYPE_JUNIPER_PPPOE_ATM 168 + +#define LINKTYPE_GPRS_LLC 169 /* GPRS LLC */ +#define LINKTYPE_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define LINKTYPE_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define LINKTYPE_GCOM_T1E1 172 +#define LINKTYPE_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define LINKTYPE_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define LINKTYPE_ERF_ETH 175 /* Ethernet */ +#define LINKTYPE_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define LINKTYPE_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The Link Types are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define LINKTYPE_JUNIPER_ETHER 178 +#define LINKTYPE_JUNIPER_PPP 179 +#define LINKTYPE_JUNIPER_FRELAY 180 +#define LINKTYPE_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define LINKTYPE_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define LINKTYPE_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define LINKTYPE_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define LINKTYPE_A653_ICM 185 + +/* + * This used to be "USB packets, beginning with a USB setup header; + * requested by Paolo Abeni ." + * + * However, that header didn't work all that well - it left out some + * useful information - and was abandoned in favor of the DLT_USB_LINUX + * header. + * + * This is now used by FreeBSD for its BPF taps for USB; that has its + * own headers. So it is written, so it is done. + */ +#define LINKTYPE_USB_FREEBSD 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define LINKTYPE_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define LINKTYPE_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define LINKTYPE_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define LINKTYPE_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define LINKTYPE_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * LINKTYPE_ requested by Gianluca Varenni . + */ +#define LINKTYPE_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define LINKTYPE_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define LINKTYPE_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), and with the FCS at the end of the frame; requested by + * Mikko Saarnivala . + * + * This should only be used if the FCS is present at the end of the + * frame; if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be + * used. + */ +#define LINKTYPE_IEEE802_15_4_WITHFCS 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define LINKTYPE_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define LINKTYPE_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define LINKTYPE_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with a 2-byte header, followed by + * the I2C slave address, followed by the netFn and LUN, etc.. + * Requested by Chanthy Toeung . + * + * XXX - its DLT_ value used to be called DLT_IPMB, back when we got the + * impression from the email thread requesting it that the packet + * had no extra 2-byte header. We've renamed it; if anybody used + * DLT_IPMB and assumed no 2-byte header, this will cause the compile + * to fail, at which point we'll have to figure out what to do about + * the two header types using the same DLT_/LINKTYPE_ value. If that + * doesn't happen, we'll assume nobody used it and that the redefinition + * is safe. + */ +#define LINKTYPE_IPMB_KONTRON 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define LINKTYPE_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define LINKTYPE_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define LINKTYPE_LAPD 203 + +/* + * PPP, with a one-byte direction pseudo-header prepended - zero means + * "received by this host", non-zero (any non-zero value) means "sent by + * this host" - as per Will Barker . + */ +#define LINKTYPE_PPP_WITH_DIR 204 /* Don't confuse with LINKTYPE_PPP_PPPD */ + +/* + * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero + * means "received by this host", non-zero (any non-zero value) means + * "sent by this host" - as per Will Barker . + */ +#define LINKTYPE_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ + +/* + * Frame Relay, with a one-byte direction pseudo-header prepended - zero + * means "received by this host" (DCE -> DTE), non-zero (any non-zero + * value) means "sent by this host" (DTE -> DCE) - as per Will Barker + * . + */ +#define LINKTYPE_FRELAY_WITH_DIR 206 /* Frame Relay */ + +/* + * LAPB, with a one-byte direction pseudo-header prepended - zero means + * "received by this host" (DCE -> DTE), non-zero (any non-zero value) + * means "sent by this host" (DTE -> DCE)- as per Will Barker + * . + */ +#define LINKTYPE_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define LINKTYPE_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define LINKTYPE_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - https://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define LINKTYPE_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define LINKTYPE_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define LINKTYPE_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define LINKTYPE_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define LINKTYPE_IEEE802_15_4_NONASK_PHY 215 + +/* + * David Gibson requested this for + * captures from the Linux kernel /dev/input/eventN devices. This + * is used to communicate keystrokes and mouse movements from the + * Linux kernel to display systems, such as Xorg. + */ +#define LINKTYPE_LINUX_EVDEV 216 + +/* + * GSM Um and Abis interfaces, preceded by a "gsmtap" header. + * + * Requested by Harald Welte . + */ +#define LINKTYPE_GSMTAP_UM 217 +#define LINKTYPE_GSMTAP_ABIS 218 + +/* + * MPLS, with an MPLS label as the link-layer header. + * Requested by Michele Marchetto on behalf + * of OpenBSD. + */ +#define LINKTYPE_MPLS 219 + +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define LINKTYPE_USB_LINUX_MMAPPED 220 + +/* + * DECT packets, with a pseudo-header; requested by + * Matthias Wenzel . + */ +#define LINKTYPE_DECT 221 + +/* + * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" + * Date: Mon, 11 May 2009 11:18:30 -0500 + * + * DLT_AOS. We need it for AOS Space Data Link Protocol. + * I have already written dissectors for but need an OK from + * legal before I can submit a patch. + * + */ +#define LINKTYPE_AOS 222 + +/* + * WirelessHART (Highway Addressable Remote Transducer) + * From the HART Communication Foundation + * IEC/PAS 62591 + * + * Requested by Sam Roberts . + */ +#define LINKTYPE_WIHART 223 + +/* + * Fibre Channel FC-2 frames, beginning with a Frame_Header. + * Requested by Kahou Lei . + */ +#define LINKTYPE_FC_2 224 + +/* + * Fibre Channel FC-2 frames, beginning with an encoding of the + * SOF, and ending with an encoding of the EOF. + * + * The encodings represent the frame delimiters as 4-byte sequences + * representing the corresponding ordered sets, with K28.5 + * represented as 0xBC, and the D symbols as the corresponding + * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, + * is represented as 0xBC 0xB5 0x55 0x55. + * + * Requested by Kahou Lei . + */ +#define LINKTYPE_FC_2_WITH_FRAME_DELIMS 225 + +/* + * Solaris ipnet pseudo-header; requested by Darren Reed . + * + * The pseudo-header starts with a one-byte version number; for version 2, + * the pseudo-header is: + * + * struct dl_ipnetinfo { + * uint8_t dli_version; + * uint8_t dli_family; + * uint16_t dli_htype; + * uint32_t dli_pktlen; + * uint32_t dli_ifindex; + * uint32_t dli_grifindex; + * uint32_t dli_zsrc; + * uint32_t dli_zdst; + * }; + * + * dli_version is 2 for the current version of the pseudo-header. + * + * dli_family is a Solaris address family value, so it's 2 for IPv4 + * and 26 for IPv6. + * + * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing + * packets, and 2 for packets arriving from another zone on the same + * machine. + * + * dli_pktlen is the length of the packet data following the pseudo-header + * (so the captured length minus dli_pktlen is the length of the + * pseudo-header, assuming the entire pseudo-header was captured). + * + * dli_ifindex is the interface index of the interface on which the + * packet arrived. + * + * dli_grifindex is the group interface index number (for IPMP interfaces). + * + * dli_zsrc is the zone identifier for the source of the packet. + * + * dli_zdst is the zone identifier for the destination of the packet. + * + * A zone number of 0 is the global zone; a zone number of 0xffffffff + * means that the packet arrived from another host on the network, not + * from another zone on the same machine. + * + * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates + * which of those it is. + */ +#define LINKTYPE_IPNET 226 + +/* + * CAN (Controller Area Network) frames, with a pseudo-header as supplied + * by Linux SocketCAN, and with multi-byte numerical fields in that header + * in big-endian byte order. + * + * See Documentation/networking/can.txt in the Linux source. + * + * Requested by Felix Obenhuber . + */ +#define LINKTYPE_CAN_SOCKETCAN 227 + +/* + * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies + * whether it's v4 or v6. Requested by Darren Reed . + */ +#define LINKTYPE_IPV4 228 +#define LINKTYPE_IPV6 229 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), and with no FCS at the end of the frame; requested by + * Jon Smirl . + */ +#define LINKTYPE_IEEE802_15_4_NOFCS 230 + +/* + * Raw D-Bus: + * + * https://www.freedesktop.org/wiki/Software/dbus + * + * messages: + * + * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * starting with the endianness flag, followed by the message type, etc., + * but without the authentication handshake before the message sequence: + * + * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol + * + * Requested by Martin Vidner . + */ +#define LINKTYPE_DBUS 231 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define LINKTYPE_JUNIPER_VS 232 +#define LINKTYPE_JUNIPER_SRX_E2E 233 +#define LINKTYPE_JUNIPER_FIBRECHANNEL 234 + +/* + * DVB-CI (DVB Common Interface for communication between a PC Card + * module and a DVB receiver). See + * + * https://www.kaiser.cx/pcap-dvbci.html + * + * for the specification. + * + * Requested by Martin Kaiser . + */ +#define LINKTYPE_DVB_CI 235 + +/* + * Variant of 3GPP TS 27.010 multiplexing protocol. Requested + * by Hans-Christoph Schemmel . + */ +#define LINKTYPE_MUX27010 236 + +/* + * STANAG 5066 D_PDUs. Requested by M. Baris Demiray + * . + */ +#define LINKTYPE_STANAG_5066_D_PDU 237 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define LINKTYPE_JUNIPER_ATM_CEMIC 238 + +/* + * NetFilter LOG messages + * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) + * + * Requested by Jakub Zawadzki + */ +#define LINKTYPE_NFLOG 239 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and always + * with the payload including the FCS, as supplied by their + * netANALYZER hardware and software. + * + * Requested by Holger P. Frommer + */ +#define LINKTYPE_NETANALYZER 240 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and FCS and + * 1 byte of SFD, as supplied by their netANALYZER hardware and + * software. + * + * Requested by Holger P. Frommer + */ +#define LINKTYPE_NETANALYZER_TRANSPARENT 241 + +/* + * IP-over-InfiniBand, as specified by RFC 4391. + * + * Requested by Petr Sumbera . + */ +#define LINKTYPE_IPOIB 242 + +/* + * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). + * + * Requested by Guy Martin . + */ +#define LINKTYPE_MPEG_2_TS 243 + +/* + * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as + * used by their ng40 protocol tester. + * + * Requested by Jens Grimmer . + */ +#define LINKTYPE_NG40 244 + +/* + * Pseudo-header giving adapter number and flags, followed by an NFC + * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, + * as specified by NFC Forum Logical Link Control Protocol Technical + * Specification LLCP 1.1. + * + * Requested by Mike Wakerly . + */ +#define LINKTYPE_NFC_LLCP 245 + +/* + * pfsync output; DLT_PFSYNC is 18, which collides with DLT_CIP in + * SuSE 6.3, on OpenBSD, NetBSD, DragonFly BSD, and macOS, and + * is 121, which collides with DLT_HHDLC, in FreeBSD. We pick a + * shiny new link-layer header type value that doesn't collide with + * anything, in the hopes that future pfsync savefiles, if any, + * won't require special hacks to distinguish from other savefiles. + */ +#define LINKTYPE_PFSYNC 246 + +/* + * Raw InfiniBand packets, starting with the Local Routing Header. + * + * Requested by Oren Kladnitsky . + */ +#define LINKTYPE_INFINIBAND 247 + +/* + * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). + * + * Requested by Michael Tuexen . + */ +#define LINKTYPE_SCTP 248 + +/* + * USB packets, beginning with a USBPcap header. + * + * Requested by Tomasz Mon + */ +#define LINKTYPE_USBPCAP 249 + +/* + * Schweitzer Engineering Laboratories "RTAC" product serial-line + * packets. + * + * Requested by Chris Bontje . + */ +#define LINKTYPE_RTAC_SERIAL 250 + +/* + * Bluetooth Low Energy air interface link-layer packets. + * + * Requested by Mike Kershaw . + */ +#define LINKTYPE_BLUETOOTH_LE_LL 251 + +/* + * Link-layer header type for upper-protocol layer PDU saves from wireshark. + * + * the actual contents are determined by two TAGs, one or more of + * which is stored with each packet: + * + * EXP_PDU_TAG_DISSECTOR_NAME the name of the Wireshark dissector + * that can make sense of the data stored. + * + * EXP_PDU_TAG_HEUR_DISSECTOR_NAME the name of the Wireshark heuristic + * dissector that can make sense of the + * data stored. + */ +#define LINKTYPE_WIRESHARK_UPPER_PDU 252 + +/* + * Link-layer header type for the netlink protocol (nlmon devices). + */ +#define LINKTYPE_NETLINK 253 + +/* + * Bluetooth Linux Monitor headers for the BlueZ stack. + */ +#define LINKTYPE_BLUETOOTH_LINUX_MONITOR 254 + +/* + * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as + * captured by Ubertooth. + */ +#define LINKTYPE_BLUETOOTH_BREDR_BB 255 + +/* + * Bluetooth Low Energy link layer packets, as captured by Ubertooth. + */ +#define LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR 256 + +/* + * PROFIBUS data link layer. + */ +#define LINKTYPE_PROFIBUS_DL 257 + +/* + * Apple's DLT_PKTAP headers. + * + * Sadly, the folks at Apple either had no clue that the DLT_USERn values + * are for internal use within an organization and partners only, and + * didn't know that the right way to get a link-layer header type is to + * ask tcpdump.org for one, or knew and didn't care, so they just + * used DLT_USER2, which causes problems for everything except for + * their version of tcpdump. + * + * So I'll just give them one; hopefully this will show up in a + * libpcap release in time for them to get this into 10.10 Big Sur + * or whatever Mavericks' successor is called. LINKTYPE_PKTAP + * will be 258 *even on macOS*; that is *intentional*, so that + * PKTAP files look the same on *all* OSes (different OSes can have + * different numerical values for a given DLT_, but *MUST NOT* have + * different values for what goes in a file, as files can be moved + * between OSes!). + */ +#define LINKTYPE_PKTAP 258 + +/* + * Ethernet packets preceded by a header giving the last 6 octets + * of the preamble specified by 802.3-2012 Clause 65, section + * 65.1.3.2 "Transmit". + */ +#define LINKTYPE_EPON 259 + +/* + * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" + * in the PICMG HPM.2 specification. + */ +#define LINKTYPE_IPMI_HPM_2 260 + +/* + * per Joshua Wright , formats for Zwave captures. + */ +#define LINKTYPE_ZWAVE_R1_R2 261 +#define LINKTYPE_ZWAVE_R3 262 + +/* + * per Steve Karg , formats for Wattstopper + * Digital Lighting Management room bus serial protocol captures. + */ +#define LINKTYPE_WATTSTOPPER_DLM 263 + +/* + * ISO 14443 contactless smart card messages. + */ +#define LINKTYPE_ISO_14443 264 + +/* + * Radio data system (RDS) groups. IEC 62106. + * Per Jonathan Brucker . + */ +#define LINKTYPE_RDS 265 + +/* + * USB packets, beginning with a Darwin (macOS, etc.) header. + */ +#define LINKTYPE_USB_DARWIN 266 + +/* + * OpenBSD DLT_OPENFLOW. + */ +#define LINKTYPE_OPENFLOW 267 + +/* + * SDLC frames containing SNA PDUs. + */ +#define LINKTYPE_SDLC 268 + +/* + * per "Selvig, Bjorn" used for + * TI protocol sniffer. + */ +#define LINKTYPE_TI_LLN_SNIFFER 269 + +/* + * per: Erik de Jong for + * https://github.com/eriknl/LoRaTap/releases/tag/v0.1 + */ +#define LINKTYPE_LORATAP 270 + +/* + * per: Stefanha at gmail.com for + * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html + * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h + * for: https://qemu-project.org/Features/VirtioVsock + */ +#define LINKTYPE_VSOCK 271 + +/* + * Nordic Semiconductor Bluetooth LE sniffer. + */ +#define LINKTYPE_NORDIC_BLE 272 + +/* + * Excentis DOCSIS 3.1 RF sniffer (XRA-31) + * per: bruno.verstuyft at excentis.com + * https://www.xra31.com/xra-header + */ +#define LINKTYPE_DOCSIS31_XRA31 273 + +/* + * mPackets, as specified by IEEE 802.3br Figure 99-4, starting + * with the preamble and always ending with a CRC field. + */ +#define LINKTYPE_ETHERNET_MPACKET 274 + +/* + * DisplayPort AUX channel monitoring data as specified by VESA + * DisplayPort(DP) Standard preceded by a pseudo-header. + * per dirk.eibach at gdsys.cc + */ +#define LINKTYPE_DISPLAYPORT_AUX 275 + +/* + * Linux cooked sockets v2. + */ +#define LINKTYPE_LINUX_SLL2 276 + +/* + * Sercos Monitor, per Manuel Jacob + */ +#define LINKTYPE_SERCOS_MONITOR 277 + +/* + * OpenVizsla http://openvizsla.org is open source USB analyzer hardware. + * It consists of FPGA with attached USB phy and FTDI chip for streaming + * the data to the host PC. + * + * Current OpenVizsla data encapsulation format is described here: + * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description + * + */ +#define LINKTYPE_OPENVIZSLA 278 + +/* + * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced + * by a PCIe Card for interfacing high speed automotive interfaces. + * + * The specification for this frame format can be found at: + * https://www.elektrobit.com/ebhscr + * + * for Guenter.Ebermann at elektrobit.com + * + */ +#define LINKTYPE_EBHSCR 279 + +/* + * The https://fd.io vpp graph dispatch tracer produces pcap trace files + * in the format documented here: + * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing + */ +#define LINKTYPE_VPP_DISPATCH 280 + +/* + * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format. + */ +#define LINKTYPE_DSA_TAG_BRCM 281 +#define LINKTYPE_DSA_TAG_BRCM_PREPEND 282 + +/* + * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload + * exactly as it appears in the spec (no padding, no nothing), and FCS if + * specified by FCS Type TLV; requested by James Ko . + * Specification at https://github.com/jkcko/ieee802.15.4-tap + */ +#define LINKTYPE_IEEE802_15_4_TAP 283 + +/* + * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format. + */ +#define LINKTYPE_DSA_TAG_DSA 284 +#define LINKTYPE_DSA_TAG_EDSA 285 + +/* + * Payload of lawful intercept packets using the ELEE protocol; + * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml + * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii + */ +#define LINKTYPE_ELEE 286 + +/* + * Serial frames transmitted between a host and a Z-Wave chip. + */ +#define LINKTYPE_Z_WAVE_SERIAL 287 + +/* + * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + */ +#define LINKTYPE_USB_2_0 288 + +/* + * ATSC Link-Layer Protocol (A/330) packets. + */ +#define LINKTYPE_ATSC_ALP 289 + +#define LINKTYPE_HIGH_MATCHING_MAX 289 /* highest value in the "matching" range */ + +/* + * The DLT_ and LINKTYPE_ values in the "matching" range should be the + * same, so DLT_HIGH_MATCHING_MAX and LINKTYPE_HIGH_MATCHING_MAX should be the + * same. + */ +#if LINKTYPE_HIGH_MATCHING_MAX != DLT_HIGH_MATCHING_MAX +#error The LINKTYPE_ high matching range does not match the DLT_ matching range +#endif + +/* + * Map a DLT_* code to the corresponding LINKTYPE_* code. + * Used to generate link-layer types written to savefiles. + */ +int +dlt_to_linktype(int dlt) +{ + /* + * All values in the low matching range were handed out before + * assigning DLT_* codes became a free-for-all, so they're the + * same on all platforms, and thus are given LINKTYPE_* codes + * with the same numerical values as the corresponding DLT_* + * code. + */ + if (dlt >= DLT_LOW_MATCHING_MIN && dlt <= DLT_LOW_MATCHING_MAX) + return (dlt); + +#if DLT_PFSYNC != LINKTYPE_PFSYNC + /* + * DLT_PFSYNC has a code on several platforms that's in the + * non-matching range, a code on FreeBSD that's in the high + * matching range and that's *not* equal to LINKTYPE_PFSYNC, + * and has a code on the rmaining platforms that's equal + * to LINKTYPE_PFSYNC, which is in the high matching range. + * + * Map it to LINKTYPE_PFSYNC if it's not equal to LINKTYPE_PFSYNC. + */ + if (dlt == DLT_PFSYNC) + return (LINKTYPE_PFSYNC); +#endif + + /* + * DLT_PKTAP is defined as DLT_USER2 - which is in the high + * matching range - on Darwin because Apple used DLT_USER2 + * on systems that users ran, not just as an internal thing. + * + * We map it to LINKTYPE_PKTAP if it's not equal to LINKTYPE_PKTAP + * so that DLT_PKTAP captures from Apple machines can be read by + * software that either doesn't handle DLT_USER2 or that handles it + * as something other than Apple PKTAP. + */ +#if DLT_PKTAP != LINKTYPE_PKTAP + if (dlt == DLT_PKTAP) + return (LINKTYPE_PKTAP); +#endif + + /* + * For all other DLT_* codes in the high matching range, the DLT + * code value is the same as the LINKTYPE_* code value. + */ + if (dlt >= DLT_HIGH_MATCHING_MIN && dlt <= DLT_HIGH_MATCHING_MAX) + return (dlt); + + /* + * These DLT_* codes have different values on different + * platforms, so we assigned them LINKTYPE_* codes just + * below the lower bound of the high matchig range; + * those values should never be equal to any DLT_* + * code, so that should avoid collisions. + * + * That way, for example, "raw IP" packets will have + * LINKTYPE_RAW as the code in all savefiles for + * which the code that writes them maps to that + * value, regardless of the platform on which they + * were written, so they should be readable on all + * platforms without having to determine on which + * platform they were written. + * + * We map the DLT_* codes on this platform, whatever + * it might be, to the corresponding LINKTYPE_* codes. + */ + if (dlt == DLT_ATM_RFC1483) + return (LINKTYPE_ATM_RFC1483); + if (dlt == DLT_RAW) + return (LINKTYPE_RAW); + if (dlt == DLT_SLIP_BSDOS) + return (LINKTYPE_SLIP_BSDOS); + if (dlt == DLT_PPP_BSDOS) + return (LINKTYPE_PPP_BSDOS); + + /* + * These DLT_* codes were originally defined on some platform, + * and weren't defined on other platforms. + * + * At least some of them have values, on at least one platform, + * that collide with other DLT_* codes on other platforms, e.g. + * DLT_LOOP, so we don't just define them, on all platforms, + * as having the same value as on the original platform. + * + * Therefore, we assigned new LINKTYPE_* codes to them, and, + * on the platforms where they weren't originally defined, + * define the DLT_* codes to have the same value as the + * corresponding LINKTYPE_* codes. + * + * This means that, for capture files with the original + * platform's DLT_* code rather than the LINKTYPE_* code + * as a link-layer type, we will recognize those types + * on that platform, but not on other platforms. + */ +#ifdef DLT_FR + /* BSD/OS Frame Relay */ + if (dlt == DLT_FR) + return (LINKTYPE_FRELAY); +#endif +#if DLT_HDLC != LINKTYPE_NETBSD_HDLC + /* NetBSD HDLC */ + if (dlt == DLT_HDLC) + return (LINKTYPE_NETBSD_HDLC); +#endif +#if DLT_C_HDLC != LINKTYPE_C_HDLC + /* BSD/OS Cisco HDLC */ + if (dlt == DLT_C_HDLC) + return (LINKTYPE_C_HDLC); +#endif +#if DLT_LOOP != LINKTYPE_LOOP + /* OpenBSD DLT_LOOP */ + if (dlt == DLT_LOOP) + return (LINKTYPE_LOOP); +#endif +#if DLT_ENC != LINKTYPE_ENC + /* OpenBSD DLT_ENC */ + if (dlt == DLT_ENC) + return (LINKTYPE_ENC); +#endif + + /* + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* codes anyway, just in case. + */ + /* Linux ATM Classical IP */ + if (dlt == DLT_ATM_CLIP) + return (LINKTYPE_ATM_CLIP); + + /* + * A few other values, defined on some platforms, not in + * either matching range, but not colliding with anything + * else, so they're given the same LINKTYPE_* code as + * their DLT_* code. + */ + if (dlt == DLT_REDBACK_SMARTEDGE || dlt == DLT_PPP_SERIAL || + dlt == DLT_PPP_ETHER || dlt == DLT_SYMANTEC_FIREWALL) + return (dlt); + + /* + * If we don't have a mapping for this DLT_* code, return an + * error; that means that this is a DLT_* value with no + * corresponding LINKTYPE_ value, and we need to assign one. + */ + return (-1); +} + +/* + * Map a LINKTYPE_* code to the corresponding DLT_* code. + * Used to translate link-layer types in savefiles to the + * DLT_* codes to provide to callers of libpcap. + */ +int +linktype_to_dlt(int linktype) +{ + /* + * All values in the low matching range were handed out before + * assigning DLT_* codes became a free-for-all, so they're the + * same on all platforms, and are thus used as the LINKTYPE_* + * codes in capture files. + */ + if (linktype >= LINKTYPE_LOW_MATCHING_MIN && + linktype <= LINKTYPE_LOW_MATCHING_MAX) + return (linktype); + +#if LINKTYPE_PFSYNC != DLT_PFSYNC + /* + * DLT_PFSYNC has a code on several platforms that's in the + * non-matching range, a code on FreeBSD that's in the high + * matching range and that's *not* equal to LINKTYPE_PFSYNC, + * and has a code on the rmaining platforms that's equal + * to LINKTYPE_PFSYNC, which is in the high matching range. + * + * Map LINKTYPE_PFSYNC to whatever DLT_PFSYNC is on this + * platform, if the two aren't equal. + */ + if (linktype == LINKTYPE_PFSYNC) + return (DLT_PFSYNC); +#endif + + /* + * DLT_PKTAP is defined as DLT_USER2 - which is in the high + * matching range - on Darwin because Apple used DLT_USER2 + * on systems that users ran, not just as an internal thing. + * + * We map LINKTYPE_PKTAP to the platform's DLT_PKTAP for + * the benefit of software that's expecting DLT_PKTAP + * (even if that's DLT_USER2) for an Apple PKTAP capture. + * + * (Yes, this is an annoyance if you want to read a + * LINKTYPE_USER2 packet as something other than DLT_PKTAP + * on a Darwin-based OS, as, on that OS, DLT_PKTAP and DLT_USER2 + * are the same. Feel free to complain to Apple about this.) + */ +#if LINKTYPE_PKTAP != DLT_PKTAP + if (linktype == LINKTYPE_PKTAP) + return (DLT_PKTAP); +#endif + + /* + * These DLT_* codes have different values on different + * platforms, so we assigned them LINKTYPE_* codes just + * below the lower bound of the high matchig range; + * those values should never be equal to any DLT_* + * code, so that should avoid collisions. + * + * That way, for example, "raw IP" packets will have + * LINKTYPE_RAW as the code in all savefiles for + * which the code that writes them maps to that + * value, regardless of the platform on which they + * were written, so they should be readable on all + * platforms without having to determine on which + * platform they were written. + * + * We map the LINKTYPE_* codes to the corresponding + * DLT_* code on this platform. + */ + if (linktype == LINKTYPE_ATM_RFC1483) + return (DLT_ATM_RFC1483); + if (linktype == LINKTYPE_RAW) + return (DLT_RAW); + if (linktype == LINKTYPE_SLIP_BSDOS) + return (DLT_SLIP_BSDOS); + if (linktype == LINKTYPE_PPP_BSDOS) + return (DLT_PPP_BSDOS); + + /* + * These DLT_* codes were originally defined on some platform, + * and weren't defined on other platforms. + * + * At least some of them have values, on at least one platform, + * that collide with other DLT_* codes on other platforms, e.g. + * DLT_LOOP, so we don't just define them, on all platforms, + * as having the same value as on the original platform. + * + * Therefore, we assigned new LINKTYPE_* codes to them, and, + * on the platforms where they weren't originally defined, + * define the DLT_* codes to have the same value as the + * corresponding LINKTYPE_* codes. + * + * This means that, for capture files with the original + * platform's DLT_* code rather than the LINKTYPE_* code + * as a link-layer type, we will recognize those types + * on that platform, but not on other platforms. + * + * We map the LINKTYPE_* codes to the corresponding + * DLT_* code on platforms where the two codes differ.. + */ +#ifdef DLT_FR + /* BSD/OS Frame Relay */ + if (linktype == LINKTYPE_FRELAY) + return (DLT_FR); +#endif +#if LINKTYPE_NETBSD_HDLC != DLT_HDLC + /* NetBSD HDLC */ + if (linktype == LINKTYPE_NETBSD_HDLC) + return (DLT_HDLC); +#endif +#if LINKTYPE_C_HDLC != DLT_C_HDLC + /* BSD/OS Cisco HDLC */ + if (linktype == LINKTYPE_C_HDLC) + return (DLT_C_HDLC); +#endif +#if LINKTYPE_LOOP != DLT_LOOP + /* OpenBSD DLT_LOOP */ + if (linktype == LINKTYPE_LOOP) + return (DLT_LOOP); +#endif +#if LINKTYPE_ENC != DLT_ENC + /* OpenBSD DLT_ENC */ + if (linktype == LINKTYPE_ENC) + return (DLT_ENC); +#endif + + /* + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* values anyway, just in case. + * + * LINKTYPE_ATM_CLIP is a special case. DLT_ATM_CLIP is + * not on all platforms, but, so far, there don't appear + * to be any platforms that define it as anything other + * than 19; we define LINKTYPE_ATM_CLIP as something + * other than 19, just in case. That value is in the + * high matching range, so we have to check for it. + */ + /* Linux ATM Classical IP */ + if (linktype == LINKTYPE_ATM_CLIP) + return (DLT_ATM_CLIP); + + /* + * For all other values, return the linktype code as the + * DLT_* code. + * + * If the code is in the high matching range, the + * DLT_* code is the same as the LINKTYPE_* code. + * + * If the code is greater than the maximum value in + * the high matching range, it may be a value from + * a newer version of libpcap; we provide it in case + * the program' capable of handling it. + * + * If the code is less than the minimum value in the + * high matching range, it might be from a capture + * written by code that doesn't map non-matching range + * DLT_* codes to the appropriate LINKTYPE_* code, so + * we'll just pass it through, so that *if it was written + * on this platform* it will be interpreted correctly. + * (We don't know whether it was written on this platform, + * but at least this way there's *some* chance that it + * can be read.) + */ + return linktype; +} + +/* + * Return the maximum snapshot length for a given DLT_ value. + * + * For most link-layer types, we use MAXIMUM_SNAPLEN. + * + * For DLT_DBUS, the maximum is 128MiB, as per + * + * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * For DLT_EBHSCR, the maximum is 8MiB, as per + * + * https://www.elektrobit.com/ebhscr + * + * For DLT_USBPCAP, the maximum is 1MiB, as per + * + * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=15985 + */ +u_int +max_snaplen_for_dlt(int dlt) +{ + switch (dlt) { + + case DLT_DBUS: + return 128*1024*1024; + + case DLT_EBHSCR: + return 8*1024*1024; + + case DLT_USBPCAP: + return 1024*1024; + + default: + return MAXIMUM_SNAPLEN; + } +} diff --git a/src/libpcap-1.10.5/pcap-common.h b/src/libpcap-1.10.5/pcap-common.h new file mode 100644 index 0000000000..d765c94763 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-common.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-common.h - common code for pcap and pcapng files + */ + +extern int dlt_to_linktype(int dlt); + +extern int linktype_to_dlt(int linktype); + +extern u_int max_snaplen_for_dlt(int dlt); diff --git a/src/libpcap-1.10.5/pcap-config.1 b/src/libpcap-1.10.5/pcap-config.1 new file mode 100644 index 0000000000..66af140bf0 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-config.1 @@ -0,0 +1,132 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP\-CONFIG 1 "17 April 2023" +.SH NAME +pcap-config \- write libpcap compiler and linker flags to standard output +.SH SYNOPSIS +.na +.B pcap-config +[ +.B \-\-help +] +[ +.B \-\-version +] +[ +.B \-\-cflags +] +.ti +12 +[ +.B \-\-libs +| +.B \-\-additional\-libs +] +.ti +12 +[ +.B \-\-static +| +.B \-\-static\-pcap\-only +] +.ad + +.SH DESCRIPTION +.LP +.I pcap\-config +writes to the standard output various compiler and linker flags required to +build a user program with libpcap. By default, it writes flags appropriate +for building with a dynamically\-linked version of libpcap; see below +for static linking. Depending on the manner of libpcap installation, some +options or their combinations may produce empty output \- this is by design. + +.SH OPTIONS +.TP +.B \-\-help +Produce a help message and exit. + +.TP +.B \-\-version +Produce libpcap version and exit. The version is the contents of +.I VERSION +file in libpcap source tree rather than the result of +.BR \%pcap_lib_version (3PCAP). + +.TP +.B \-\-cflags +Produce the +.B \-I +compiler flag required to include libpcap's header files. + +.TP +.B \-\-libs +Produce the +.B \-L +and +.B \-l +linker flags required to link with libpcap, including +.B \-l +flags for libraries required by libpcap. + +.TP +.B \-\-additional\-libs +Produce the +.B \-L +and +.B \-l +linker flags for libraries required by libpcap, but not the +.B \-l +flag to link with libpcap itself. + +.TP +.B \-\-static +This option causes +.B \-\-libs +and +.B \-\-additional\-libs +to produce linker flags appropriate for static linking with libpcap. + +.TP +.B \-\-static\-pcap\-only +This option causes +.B \-\-libs +and +.B \-\-additional\-libs +to produce linker flags appropriate for static linking with libpcap and +dynamic linking with all other libraries, including libraries required by +libpcap. + +.SH EXIT STATUS +.I pcap\-config +exits with a non-zero status when invoked with an invalid command\-line +option, and with status 0 otherwise. + +.SH BACKWARD COMPATIBILITY +.PP +Before libpcap release 1.10.2 +.I pcap\-config +did not treat invalid command\-line options as an error. The +.B \-\-static\-pcap\-only +flag became available in libpcap release 1.10.2. The +.B \-\-static +flag became available in libpcap release 1.1.0. + +.SH SEE ALSO +.BR pkg\-config (1), +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap-config.in b/src/libpcap-1.10.5/pcap-config.in new file mode 100644 index 0000000000..28427047e2 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-config.in @@ -0,0 +1,165 @@ +#! /bin/sh + +# +# Script to give the appropriate compiler flags and linker flags +# to use when building code that uses libpcap. +# +# These variables come from the configure script, so includedir and +# libdir may be defined in terms of prefix and exec_prefix, so the +# latter must be defined as well. +# +prefix="@prefix@" +exec_prefix="@exec_prefix@" +includedir="@includedir@" +libdir="@libdir@" +LIBS="@LIBS@" +LIBS_STATIC="@LIBS_STATIC@" +VERSION="@PACKAGE_VERSION@" + +usage() +{ + echo "Usage: pcap-config [ --help ] [ --version ] [ --cflags ]" + echo " [ --libs | --additional-libs ]" + echo " [ --static | --static-pcap-only ]" +} + +static=0 +static_pcap_only=0 +show_cflags=0 +show_libs=0 +show_additional_libs=0 +while [ "$#" != 0 ] +do + case "$1" in + + --static) + static=1 + ;; + + --static-pcap-only) + static_pcap_only=1 + ;; + + --cflags) + show_cflags=1 + ;; + + --libs) + show_libs=1 + ;; + + --additional-libs) + show_additional_libs=1 + ;; + + -h|--help) + usage + exit 0 + ;; + + --version) + echo "$VERSION" + exit 0 + ;; + + *) + echo "pcap-config: Invalid command-line option $1 specified" 1>&2 + usage 1>&2 + exit 1 + ;; + esac + shift +done + +# +# If we aren't installing in /usr, then provide a -L flag to let build +# processes find our library. +# +# (We must check $prefix, as $libdir isn't necessarily /usr/lib in this +# case - for example, Linux distributions for 64-bit platforms that +# also provide support for binaries for a 32-bit version of the +# platform may put the 64-bit libraries, the 32-bit libraries, or both +# in directories other than /usr/lib.) +# +if [ "$prefix" != "/usr" ] +then + LPATH=-L$libdir +fi +if [ "$static" = 1 ] +then + # + # Include LIBS_STATIC so that the flags include libraries + # containing routines that libpcap uses, and libraries + # containing routines those libraries use, etc., so that a + # completely statically linked program - i.e., linked only with + # static libraries - will be linked with all necessary + # libraries. + # + if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] + then + echo "-I$includedir $LPATH -l@PACKAGE_NAME@ $LIBS_STATIC" + elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] + then + echo "-I$includedir $LPATH $LIBS_STATIC" + elif [ "$show_cflags" = 1 ] + then + echo "-I$includedir" + elif [ "$show_libs" = 1 ] + then + echo "$LPATH -l@PACKAGE_NAME@ $LIBS_STATIC" + elif [ "$show_additional_libs" = 1 ] + then + echo "$LIBS_STATIC" + fi +elif [ "$static_pcap_only" = 1 ] +then + # + # Include LIBS so that the flags include libraries + # containing routines that libpcap uses, but not the libraries + # on which libpcap depends, so that an otherwise + # dynamically-linked program, linked statically only with + # libpcap - i.e., linked with a static libpcap and dynamic + # versions of other libraries - will be linked with all + # necessary libraries. + # + if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] + then + echo "-I$includedir $LPATH -l@PACKAGE_NAME@ $LIBS" + elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] + then + echo "-I$includedir $LPATH $LIBS" + elif [ "$show_cflags" = 1 ] + then + echo "-I$includedir" + elif [ "$show_libs" = 1 ] + then + echo "$LPATH -l@PACKAGE_NAME@ $LIBS" + elif [ "$show_additional_libs" = 1 ] + then + echo "$LIBS" + fi +else + # + # Don't included LIBS or LIBS_STATIC, for building a program + # with a dynamic libpcap; libpcap, being a dynamic library, will + # cause all of its dynamic-library dependencies to be pulled in + # at run time. + # + # Do, however, include RPATH, to make sure that, on platforms + # that require this, programs built with this version of + # libpcap can find it at run time. + # + if [ "$show_cflags" = 1 -a "$show_libs" = 1 ] + then + echo "-I$includedir $LPATH @RPATH@ -l@PACKAGE_NAME@" + elif [ "$show_cflags" = 1 -a "$show_additional_libs" = 1 ] + then + echo "-I$includedir" + elif [ "$show_cflags" = 1 ] + then + echo "-I$includedir" + elif [ "$show_libs" = 1 ] + then + echo "$LPATH @RPATH@ -l@PACKAGE_NAME@" + fi +fi diff --git a/src/libpcap-1.10.5/pcap-dag.c b/src/libpcap-1.10.5/pcap-dag.c new file mode 100644 index 0000000000..b21c2e3c9f --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dag.c @@ -0,0 +1,1441 @@ +/* + * pcap-dag.c: Packet capture interface for Endace DAG cards. + * + * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) + * Modifications: Jesper Peterson + * Koryn Grant + * Stephen Donnelly + */ + +#include + +#include /* optionally get BSD define */ + +#include +#include +#include + +#include "pcap-int.h" + +#include +#include +#include +#include +#include + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include + +#include "dagnew.h" +#include "dagapi.h" +#include "dagpci.h" +#include "dag_config_api.h" + +#include "pcap-dag.h" + +/* + * DAG devices have names beginning with "dag", followed by a number + * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number + * from 0 to DAG_STREAM_MAX. + */ +#ifndef DAG_MAX_BOARDS +#define DAG_MAX_BOARDS 32 +#endif + + +#ifndef ERF_TYPE_AAL5 +#define ERF_TYPE_AAL5 4 +#endif + +#ifndef ERF_TYPE_MC_HDLC +#define ERF_TYPE_MC_HDLC 5 +#endif + +#ifndef ERF_TYPE_MC_RAW +#define ERF_TYPE_MC_RAW 6 +#endif + +#ifndef ERF_TYPE_MC_ATM +#define ERF_TYPE_MC_ATM 7 +#endif + +#ifndef ERF_TYPE_MC_RAW_CHANNEL +#define ERF_TYPE_MC_RAW_CHANNEL 8 +#endif + +#ifndef ERF_TYPE_MC_AAL5 +#define ERF_TYPE_MC_AAL5 9 +#endif + +#ifndef ERF_TYPE_COLOR_HDLC_POS +#define ERF_TYPE_COLOR_HDLC_POS 10 +#endif + +#ifndef ERF_TYPE_COLOR_ETH +#define ERF_TYPE_COLOR_ETH 11 +#endif + +#ifndef ERF_TYPE_MC_AAL2 +#define ERF_TYPE_MC_AAL2 12 +#endif + +#ifndef ERF_TYPE_IP_COUNTER +#define ERF_TYPE_IP_COUNTER 13 +#endif + +#ifndef ERF_TYPE_TCP_FLOW_COUNTER +#define ERF_TYPE_TCP_FLOW_COUNTER 14 +#endif + +#ifndef ERF_TYPE_DSM_COLOR_HDLC_POS +#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 +#endif + +#ifndef ERF_TYPE_DSM_COLOR_ETH +#define ERF_TYPE_DSM_COLOR_ETH 16 +#endif + +#ifndef ERF_TYPE_COLOR_MC_HDLC_POS +#define ERF_TYPE_COLOR_MC_HDLC_POS 17 +#endif + +#ifndef ERF_TYPE_AAL2 +#define ERF_TYPE_AAL2 18 +#endif + +#ifndef ERF_TYPE_COLOR_HASH_POS +#define ERF_TYPE_COLOR_HASH_POS 19 +#endif + +#ifndef ERF_TYPE_COLOR_HASH_ETH +#define ERF_TYPE_COLOR_HASH_ETH 20 +#endif + +#ifndef ERF_TYPE_INFINIBAND +#define ERF_TYPE_INFINIBAND 21 +#endif + +#ifndef ERF_TYPE_IPV4 +#define ERF_TYPE_IPV4 22 +#endif + +#ifndef ERF_TYPE_IPV6 +#define ERF_TYPE_IPV6 23 +#endif + +#ifndef ERF_TYPE_RAW_LINK +#define ERF_TYPE_RAW_LINK 24 +#endif + +#ifndef ERF_TYPE_INFINIBAND_LINK +#define ERF_TYPE_INFINIBAND_LINK 25 +#endif + +#ifndef ERF_TYPE_META +#define ERF_TYPE_META 27 +#endif + +#ifndef ERF_TYPE_PAD +#define ERF_TYPE_PAD 48 +#endif + +#define ATM_CELL_SIZE 52 +#define ATM_HDR_SIZE 4 + +/* + * A header containing additional MTP information. + */ +#define MTP2_SENT_OFFSET 0 /* 1 byte */ +#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ +#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ +#define MTP2_HDR_LEN 4 /* length of the header */ + +#define MTP2_ANNEX_A_NOT_USED 0 +#define MTP2_ANNEX_A_USED 1 +#define MTP2_ANNEX_A_USED_UNKNOWN 2 + +/* SunATM pseudo header */ +struct sunatm_hdr { + unsigned char flags; /* destination and traffic type */ + unsigned char vpi; /* VPI */ + unsigned short vci; /* VCI */ +}; + +/* + * Private data for capturing on DAG devices. + */ +struct pcap_dag { + struct pcap_stat stat; + u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ + u_char *dag_mem_top; /* DAG card current memory top pointer */ + int dag_fcs_bits; /* Number of checksum bits from link layer */ + int dag_flags; /* Flags */ + int dag_stream; /* DAG stream number */ + int dag_timeout; /* timeout specified to pcap_open_live. + * Same as in linux above, introduce + * generally? */ + dag_card_ref_t dag_ref; /* DAG Configuration/Status API card reference */ + dag_component_t dag_root; /* DAG CSAPI Root component */ + attr_uuid_t drop_attr; /* DAG Stream Drop Attribute handle, if available */ + struct timeval required_select_timeout; + /* Timeout caller must use in event loops */ +}; + +typedef struct pcap_dag_node { + struct pcap_dag_node *next; + pcap_t *p; + pid_t pid; +} pcap_dag_node_t; + +static pcap_dag_node_t *pcap_dags = NULL; +static int atexit_handler_installed = 0; +static const unsigned short endian_test_word = 0x0100; + +#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) + +#define MAX_DAG_PACKET 65536 + +static unsigned char TempPkt[MAX_DAG_PACKET]; + +#ifndef HAVE_DAG_LARGE_STREAMS_API +#define dag_attach_stream64(a, b, c, d) dag_attach_stream(a, b, c, d) +#define dag_get_stream_poll64(a, b, c, d, e) dag_get_stream_poll(a, b, c, d, e) +#define dag_set_stream_poll64(a, b, c, d, e) dag_set_stream_poll(a, b, c, d, e) +#define dag_size_t uint32_t +#endif + +static int dag_stats(pcap_t *p, struct pcap_stat *ps); +static int dag_set_datalink(pcap_t *p, int dlt); +static int dag_get_datalink(pcap_t *p); +static int dag_setnonblock(pcap_t *p, int nonblock); + +static void +delete_pcap_dag(const pcap_t *p) +{ + pcap_dag_node_t *curr = NULL, *prev = NULL; + + for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { + /* empty */ + } + + if (curr != NULL && curr->p == p) { + if (prev != NULL) { + prev->next = curr->next; + } else { + pcap_dags = curr->next; + } + } +} + +/* + * Performs a graceful shutdown of the DAG card, frees dynamic memory held + * in the pcap_t structure, and closes the file descriptor for the DAG card. + */ + +static void +dag_platform_cleanup(pcap_t *p) +{ + struct pcap_dag *pd = p->priv; + + if(dag_stop_stream(p->fd, pd->dag_stream) < 0) + fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); + + if(dag_detach_stream(p->fd, pd->dag_stream) < 0) + fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); + + if(pd->dag_ref != NULL) { + dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or + * dag_close(p->fd), as dag_config_dispose(pd->dag_ref) + * does this. + * + * Set p->fd to -1 to make sure that's not done. + */ + p->fd = -1; + pd->dag_ref = NULL; + } + delete_pcap_dag(p); + pcapint_cleanup_live_common(p); +} + +static void +atexit_handler(void) +{ + while (pcap_dags != NULL) { + if (pcap_dags->pid == getpid()) { + if (pcap_dags->p != NULL) + dag_platform_cleanup(pcap_dags->p); + } else { + delete_pcap_dag(pcap_dags->p); + } + } +} + +static int +new_pcap_dag(pcap_t *p) +{ + pcap_dag_node_t *node = NULL; + + if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { + return -1; + } + + if (!atexit_handler_installed) { + atexit(atexit_handler); + atexit_handler_installed = 1; + } + + node->next = pcap_dags; + node->p = p; + node->pid = getpid(); + + pcap_dags = node; + + return 0; +} + +static unsigned int +dag_erf_ext_header_count(const uint8_t *erf, size_t len) +{ + uint32_t hdr_num = 0; + uint8_t hdr_type; + + /* basic sanity checks */ + if ( erf == NULL ) + return 0; + if ( len < 16 ) + return 0; + + /* check if we have any extension headers */ + if ( (erf[8] & 0x80) == 0x00 ) + return 0; + + /* loop over the extension headers */ + do { + + /* sanity check we have enough bytes */ + if ( len < (24 + (hdr_num * 8)) ) + return hdr_num; + + /* get the header type */ + hdr_type = erf[(16 + (hdr_num * 8))]; + hdr_num++; + + } while ( hdr_type & 0x80 ); + + return hdr_num; +} + +/* + * Read at most max_packets from the capture stream and call the callback + * for each of them. Returns the number of packets handled, -1 if an + * error occurred, or -2 if we were told to break out of the loop. + */ +static int +dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_dag *pd = p->priv; + unsigned int processed = 0; + unsigned int nonblocking = pd->dag_flags & DAGF_NONBLOCK; + unsigned int num_ext_hdr = 0; + unsigned int ticks_per_second; + + /* Get the next bufferful of packets (if necessary). */ + while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { + + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + /* dag_advance_stream() will block (unless nonblock is called) + * until 64kB of data has accumulated. + * If to_ms is set, it will timeout before 64kB has accumulated. + * We wait for 64kB because processing a few packets at a time + * can cause problems at high packet rates (>200kpps) due + * to inefficiencies. + * This does mean if to_ms is not specified the capture may 'hang' + * for long periods if the data rate is extremely slow (<64kB/sec) + * If non-block is specified it will return immediately. The user + * is then responsible for efficiency. + */ + if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { + return -1; + } + + if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) + { + /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ + return 0; + } + + if(!nonblocking && + pd->dag_timeout && + (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) + { + /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ + return 0; + } + + } + + /* + * Process the packets. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ + while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { + + unsigned short packet_len = 0; + int caplen = 0; + struct pcap_pkthdr pcap_header; + + dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); + + u_char *dp = ((u_char *)header); /* + dag_record_size; */ + unsigned short rlen; + + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + rlen = ntohs(header->rlen); + if (rlen < dag_record_size) + { + pcapint_strlcpy(p->errbuf, "dag_read: record too small", + PCAP_ERRBUF_SIZE); + return -1; + } + pd->dag_mem_bottom += rlen; + + /* Count lost packets. */ + switch((header->type & 0x7f)) { + /* in these types the color value overwrites the lctr */ + case ERF_TYPE_COLOR_HDLC_POS: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_DSM_COLOR_HDLC_POS: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_MC_HDLC_POS: + case ERF_TYPE_COLOR_HASH_ETH: + case ERF_TYPE_COLOR_HASH_POS: + break; + + default: + if ( (pd->drop_attr == kNullAttributeUuid) && (header->lctr) ) { + pd->stat.ps_drop += ntohs(header->lctr); + } + } + + if ((header->type & 0x7f) == ERF_TYPE_PAD) { + continue; + } + + num_ext_hdr = dag_erf_ext_header_count(dp, rlen); + + /* ERF encapsulation */ + /* The Extensible Record Format is not dropped for this kind of encapsulation, + * and will be handled as a pseudo header by the decoding application. + * The information carried in the ERF header and in the optional subheader (if present) + * could be merged with the libpcap information, to offer a better decoding. + * The packet length is + * o the length of the packet on the link (header->wlen), + * o plus the length of the ERF header (dag_record_size), as the length of the + * pseudo header will be adjusted during the decoding, + * o plus the length of the optional subheader (if present). + * + * The capture length is header.rlen and the byte stuffing for alignment will be dropped + * if the capture length is greater than the packet length. + */ + if (p->linktype == DLT_ERF) { + packet_len = ntohs(header->wlen) + dag_record_size; + caplen = rlen; + switch ((header->type & 0x7f)) { + case ERF_TYPE_MC_AAL5: + case ERF_TYPE_MC_ATM: + case ERF_TYPE_MC_HDLC: + case ERF_TYPE_MC_RAW_CHANNEL: + case ERF_TYPE_MC_RAW: + case ERF_TYPE_MC_AAL2: + case ERF_TYPE_COLOR_MC_HDLC_POS: + packet_len += 4; /* MC header */ + break; + + case ERF_TYPE_COLOR_HASH_ETH: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_ETH: + packet_len += 2; /* ETH header */ + break; + } /* switch type */ + + /* Include ERF extension headers */ + packet_len += (8 * num_ext_hdr); + + if (caplen > packet_len) { + caplen = packet_len; + } + } else { + /* Other kind of encapsulation according to the header Type */ + + /* Skip over generic ERF header */ + dp += dag_record_size; + /* Skip over extension headers */ + dp += 8 * num_ext_hdr; + + switch((header->type & 0x7f)) { + case ERF_TYPE_ATM: + case ERF_TYPE_AAL5: + if ((header->type & 0x7f) == ERF_TYPE_AAL5) { + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size; + } + case ERF_TYPE_MC_ATM: + if ((header->type & 0x7f) == ERF_TYPE_MC_ATM) { + caplen = packet_len = ATM_CELL_SIZE; + dp+=4; + } + case ERF_TYPE_MC_AAL5: + if ((header->type & 0x7f) == ERF_TYPE_MC_AAL5) { + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size - 4; + dp+=4; + } + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + + if ((header->type & 0x7f) == ERF_TYPE_ATM) { + caplen = packet_len = ATM_CELL_SIZE; + } + if (p->linktype == DLT_SUNATM) { + struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; + unsigned long rawatm; + + rawatm = ntohl(*((unsigned long *)dp)); + sunatm->vci = htons((rawatm >> 4) & 0xffff); + sunatm->vpi = (rawatm >> 20) & 0x00ff; + sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | + ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : + ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : + ((dp[ATM_HDR_SIZE] == 0xaa && + dp[ATM_HDR_SIZE+1] == 0xaa && + dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); + + } else if (p->linktype == DLT_ATM_RFC1483) { + packet_len -= ATM_HDR_SIZE; + caplen -= ATM_HDR_SIZE; + dp += ATM_HDR_SIZE; + } else + continue; + break; + + case ERF_TYPE_COLOR_HASH_ETH: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_ETH: + if ((p->linktype != DLT_EN10MB) && + (p->linktype != DLT_DOCSIS)) + continue; + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size - 2; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + dp += 2; + break; + + case ERF_TYPE_COLOR_HASH_POS: + case ERF_TYPE_DSM_COLOR_HDLC_POS: + case ERF_TYPE_COLOR_HDLC_POS: + case ERF_TYPE_HDLC_POS: + if ((p->linktype != DLT_CHDLC) && + (p->linktype != DLT_PPP_SERIAL) && + (p->linktype != DLT_FRELAY)) + continue; + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + break; + + case ERF_TYPE_COLOR_MC_HDLC_POS: + case ERF_TYPE_MC_HDLC: + if ((p->linktype != DLT_CHDLC) && + (p->linktype != DLT_PPP_SERIAL) && + (p->linktype != DLT_FRELAY) && + (p->linktype != DLT_MTP2) && + (p->linktype != DLT_MTP2_WITH_PHDR) && + (p->linktype != DLT_LAPD)) + continue; + packet_len = ntohs(header->wlen); + packet_len -= (pd->dag_fcs_bits >> 3); + caplen = rlen - dag_record_size - 4; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + /* jump the MC_HDLC_HEADER */ + dp += 4; +#ifdef DLT_MTP2_WITH_PHDR + if (p->linktype == DLT_MTP2_WITH_PHDR) { + /* Add the MTP2 Pseudo Header */ + caplen += MTP2_HDR_LEN; + packet_len += MTP2_HDR_LEN; + + TempPkt[MTP2_SENT_OFFSET] = 0; + TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; + *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); + *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); + memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); + dp = TempPkt; + } +#endif + break; + + case ERF_TYPE_IPV4: + if ((p->linktype != DLT_RAW) && + (p->linktype != DLT_IPV4)) + continue; + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + break; + + case ERF_TYPE_IPV6: + if ((p->linktype != DLT_RAW) && + (p->linktype != DLT_IPV6)) + continue; + packet_len = ntohs(header->wlen); + caplen = rlen - dag_record_size; + /* Skip over extension headers */ + caplen -= (8 * num_ext_hdr); + if (caplen > packet_len) { + caplen = packet_len; + } + break; + + /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ + case ERF_TYPE_MC_RAW: + case ERF_TYPE_MC_RAW_CHANNEL: + case ERF_TYPE_IP_COUNTER: + case ERF_TYPE_TCP_FLOW_COUNTER: + case ERF_TYPE_INFINIBAND: + case ERF_TYPE_RAW_LINK: + case ERF_TYPE_INFINIBAND_LINK: + default: + /* Unhandled ERF type. + * Ignore rather than generating error + */ + continue; + } /* switch type */ + + } /* ERF encapsulation */ + + if (caplen > p->snapshot) + caplen = p->snapshot; + + /* Run the packet filter if there is one. */ + if ((p->fcode.bf_insns == NULL) || pcapint_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { + + /* convert between timestamp formats */ + register unsigned long long ts; + + if (IS_BIGENDIAN()) { + ts = SWAPLL(header->ts); + } else { + ts = header->ts; + } + + switch (p->opt.tstamp_precision) { + case PCAP_TSTAMP_PRECISION_NANO: + ticks_per_second = 1000000000; + break; + case PCAP_TSTAMP_PRECISION_MICRO: + default: + ticks_per_second = 1000000; + break; + + } + pcap_header.ts.tv_sec = ts >> 32; + ts = (ts & 0xffffffffULL) * ticks_per_second; + ts += 0x80000000; /* rounding */ + pcap_header.ts.tv_usec = ts >> 32; + if (pcap_header.ts.tv_usec >= ticks_per_second) { + pcap_header.ts.tv_usec -= ticks_per_second; + pcap_header.ts.tv_sec++; + } + + /* Fill in our own header data */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Count the packet. */ + pd->stat.ps_recv++; + + /* Call the user supplied callback function */ + callback(user, &pcap_header, dp); + + /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ + processed++; + if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) + { + /* Reached the user-specified limit. */ + return cnt; + } + } + } + + return processed; +} + +static int +dag_inject(pcap_t *p, const void *buf _U_, int size _U_) +{ + pcapint_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Get a handle for a live capture from the given DAG device. Passing a NULL + * device will result in a failure. The promisc flag is ignored because DAG + * cards are always promiscuous. The to_ms parameter is used in setting the + * API polling parameters. + * + * snaplen is now also ignored, until we get per-stream slen support. Set + * slen with appropriate DAG tool BEFORE pcap_activate(). + * + * See also pcap(3). + */ +static int dag_activate(pcap_t* p) +{ + struct pcap_dag *pd = p->priv; + char *s; + int n; + daginf_t* daginf; + char * newDev = NULL; + char * device = p->opt.device; + int ret; + dag_size_t mindata; + struct timeval maxwait; + struct timeval poll; + + if (device == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); + return PCAP_ERROR; + } + + /* Initialize some components of the pcap structure. */ + newDev = (char *)malloc(strlen(device) + 16); + if (newDev == NULL) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't allocate string for device name"); + goto fail; + } + + /* Parse input name to get dag device and stream number if provided */ + if (dag_parse_name(device, newDev, strlen(device) + 16, &pd->dag_stream) < 0) { + /* + * XXX - it'd be nice if this indicated what was wrong + * with the name. Does this reliably set errno? + * Should this return PCAP_ERROR_NO_SUCH_DEVICE in some + * cases? + */ + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_parse_name"); + goto fail; + } + device = newDev; + + if (pd->dag_stream%2) { + ret = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); + goto fail; + } + + /* setup device parameters */ + if((pd->dag_ref = dag_config_init((char *)device)) == NULL) { + /* + * XXX - does this reliably set errno? + */ + if (errno == ENOENT) { + /* + * There's nothing more to say, so clear + * the error message. + */ + ret = PCAP_ERROR_NO_SUCH_DEVICE; + p->errbuf[0] = '\0'; + } else if (errno == EPERM || errno == EACCES) { + ret = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with %s - additional privileges may be required", + device, (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_config_init %s", device); + } + goto fail; + } + + if((p->fd = dag_config_get_card_fd(pd->dag_ref)) < 0) { + /* + * XXX - does this reliably set errno? + */ + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_config_get_card_fd %s", device); + goto failclose; + } + + /* Open requested stream. Can fail if already locked or on error */ + if (dag_attach_stream64(p->fd, pd->dag_stream, 0, 0) < 0) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_attach_stream"); + goto failclose; + } + + /* Try to find Stream Drop attribute */ + pd->drop_attr = kNullAttributeUuid; + pd->dag_root = dag_config_get_root_component(pd->dag_ref); + if ( dag_component_get_subcomponent(pd->dag_root, kComponentStreamFeatures, 0) ) + { + pd->drop_attr = dag_config_get_indexed_attribute_uuid(pd->dag_ref, kUint32AttributeStreamDropCount, pd->dag_stream/2); + } + + /* Set up default poll parameters for stream + * Can be overridden by pcap_set_nonblock() + */ + if (dag_get_stream_poll64(p->fd, pd->dag_stream, + &mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_get_stream_poll"); + goto faildetach; + } + + /* Use the poll time as the required select timeout for callers + * who are using select()/etc. in an event loop waiting for + * packets to arrive. + */ + pd->required_select_timeout = poll; + p->required_select_timeout = &pd->required_select_timeout; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + if (p->opt.immediate) { + /* Call callback immediately. + * XXX - is this the right way to p this? + */ + mindata = 0; + } else { + /* Amount of data to collect in Bytes before calling callbacks. + * Important for efficiency, but can introduce latency + * at low packet rates if to_ms not set! + */ + mindata = 65536; + } + + /* Obey opt.timeout (was to_ms) if supplied. This is a good idea! + * Recommend 10-100ms. Calls will time out even if no data arrived. + */ + maxwait.tv_sec = p->opt.timeout/1000; + maxwait.tv_usec = (p->opt.timeout%1000) * 1000; + + if (dag_set_stream_poll64(p->fd, pd->dag_stream, + mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_set_stream_poll"); + goto faildetach; + } + + /* XXX Not calling dag_configure() to set slen; this is unsafe in + * multi-stream environments as the gpp config is global. + * Once the firmware provides 'per-stream slen' this can be supported + * again via the Config API without side-effects */ +#if 0 + /* set the card snap length to the specified snaplen parameter */ + /* This is a really bad idea, as different cards have different + * valid slen ranges. Should fix in Config API. */ + if (p->snapshot == 0 || p->snapshot > MAX_DAG_SNAPLEN) { + p->snapshot = MAX_DAG_SNAPLEN; + } else if (snaplen < MIN_DAG_SNAPLEN) { + p->snapshot = MIN_DAG_SNAPLEN; + } + /* snap len has to be a multiple of 4 */ +#endif + + if(dag_start_stream(p->fd, pd->dag_stream) < 0) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_start_stream %s", device); + goto faildetach; + } + + /* + * Important! You have to ensure bottom is properly + * initialized to zero on startup, it won't give you + * a compiler warning if you make this mistake! + */ + pd->dag_mem_bottom = 0; + pd->dag_mem_top = 0; + + /* + * Find out how many FCS bits we should strip. + * First, query the card to see if it strips the FCS. + */ + daginf = dag_info(p->fd); + if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { + /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ + pd->dag_fcs_bits = 0; + + /* Note that no FCS will be supplied. */ + p->linktype_ext = LT_FCS_DATALINK_EXT(0); + } else { + /* + * Start out assuming it's 32 bits. + */ + pd->dag_fcs_bits = 32; + + /* Allow an environment variable to override. */ + if ((s = getenv("ERF_FCS_BITS")) != NULL) { + if ((n = atoi(s)) == 0 || n == 16 || n == 32) { + pd->dag_fcs_bits = n; + } else { + ret = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n); + goto failstop; + } + } + + /* + * Did the user request that they not be stripped? + */ + if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { + /* Yes. Note the number of 16-bit words that will be + supplied. */ + p->linktype_ext = LT_FCS_DATALINK_EXT(pd->dag_fcs_bits/16); + + /* And don't strip them. */ + pd->dag_fcs_bits = 0; + } + } + + pd->dag_timeout = p->opt.timeout; + + p->linktype = -1; + if (dag_get_datalink(p) < 0) { + ret = PCAP_ERROR; + goto failstop; + } + + p->bufsize = 0; + + if (new_pcap_dag(p) < 0) { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "new_pcap_dag %s", device); + goto failstop; + } + + /* + * "select()" and "poll()" don't work on DAG device descriptors. + */ + p->selectable_fd = -1; + + if (newDev != NULL) { + free((char *)newDev); + } + + p->read_op = dag_read; + p->inject_op = dag_inject; + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = dag_set_datalink; + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = dag_setnonblock; + p->stats_op = dag_stats; + p->cleanup_op = dag_platform_cleanup; + pd->stat.ps_drop = 0; + pd->stat.ps_recv = 0; + pd->stat.ps_ifdrop = 0; + return 0; + +failstop: + if (dag_stop_stream(p->fd, pd->dag_stream) < 0) { + fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); + } + +faildetach: + if (dag_detach_stream(p->fd, pd->dag_stream) < 0) + fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); + +failclose: + dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or dag_close(p->fd), + * as dag_config_dispose(pd->dag_ref) does this. + * + * Set p->fd to -1 to make sure that's not done. + */ + p->fd = -1; + pd->dag_ref = NULL; + delete_pcap_dag(p); + +fail: + pcapint_cleanup_live_common(p); + if (newDev != NULL) { + free((char *)newDev); + } + + return ret; +} + +pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; + long stream = 0; + + /* Does this look like a DAG device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with "dag"? */ + if (strncmp(cp, "dag", 3) != 0) { + /* Nope, doesn't begin with "dag" */ + *is_ours = 0; + return NULL; + } + /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */ + cp += 3; + devnum = strtol(cp, &cpend, 10); + if (*cpend == ':') { + /* Followed by a stream number. */ + stream = strtol(++cpend, &cpend, 10); + } + + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + + if (devnum < 0 || devnum >= DAG_MAX_BOARDS) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + if (stream <0 || stream >= DAG_STREAM_MAX) { + /* Followed by a non-valid stream number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dag); + if (p == NULL) + return NULL; + + p->activate_op = dag_activate; + + /* + * We claim that we support microsecond and nanosecond time + * stamps. + * + * XXX Our native precision is 2^-32s, but libpcap doesn't support + * power of two precisions yet. We can convert to either MICRO or NANO. + */ + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + pcap_close(p); + return NULL; + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + p->tstamp_precision_count = 2; + return p; +} + +static int +dag_stats(pcap_t *p, struct pcap_stat *ps) { + struct pcap_dag *pd = p->priv; + uint32_t stream_drop; + dag_err_t dag_error; + + /* + * Packet records received (ps_recv) are counted in dag_read(). + * Packet records dropped (ps_drop) are read from Stream Drop attribute if present, + * otherwise integrate the ERF Header lctr counts (if available) in dag_read(). + * We are reporting that no records are dropped by the card/driver (ps_ifdrop). + */ + + if(pd->drop_attr != kNullAttributeUuid) { + /* Note this counter is cleared at start of capture and will wrap at UINT_MAX. + * The application is responsible for polling ps_drop frequently enough + * to detect each wrap and integrate total drop with a wider counter */ + if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop)) == kDagErrNone) { + pd->stat.ps_drop = stream_drop; + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s", + dag_config_strerror(dag_error)); + return -1; + } + } + + *ps = pd->stat; + + return 0; +} + +/* + * Add all DAG devices. + */ +int +dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf) +{ + char name[12]; /* XXX - pick a size */ + int c; + char dagname[DAGNAME_BUFSIZE]; + int dagstream; + int dagfd; + dag_card_inf_t *inf; + char *description; + int stream, rxstreams; + + /* Try all the DAGs 0-DAG_MAX_BOARDS */ + for (c = 0; c < DAG_MAX_BOARDS; c++) { + snprintf(name, 12, "dag%d", c); + if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) + { + (void) snprintf(errbuf, PCAP_ERRBUF_SIZE, + "dag: device name %s can't be parsed", name); + return (-1); + } + if ( (dagfd = dag_open(dagname)) >= 0 ) { + description = NULL; + if ((inf = dag_pciinfo(dagfd))) + description = dag_device_name(inf->device_code, 1); + /* + * XXX - is there a way to determine whether + * the card is plugged into a network or not? + * If so, we should check that and set + * PCAP_IF_CONNECTION_STATUS_CONNECTED or + * PCAP_IF_CONNECTION_STATUS_DISCONNECTED. + * + * Also, are there notions of "up" and "running"? + */ + if (pcapint_add_dev(devlistp, name, 0, description, errbuf) == NULL) { + /* + * Failure. + */ + return (-1); + } + rxstreams = dag_rx_get_stream_count(dagfd); + for(stream=0;streamlinktype = dlt; + + return (0); +} + +static int +dag_setnonblock(pcap_t *p, int nonblock) +{ + struct pcap_dag *pd = p->priv; + dag_size_t mindata; + struct timeval maxwait; + struct timeval poll; + + /* + * Set non-blocking mode on the FD. + * XXX - is that necessary? If not, don't bother calling it, + * and have a "dag_getnonblock()" function that looks at + * "pd->dag_flags". + */ + if (pcapint_setnonblock_fd(p, nonblock) < 0) + return (-1); + + if (dag_get_stream_poll64(p->fd, pd->dag_stream, + &mindata, &maxwait, &poll) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_get_stream_poll"); + return -1; + } + + /* Amount of data to collect in Bytes before calling callbacks. + * Important for efficiency, but can introduce latency + * at low packet rates if to_ms not set! + */ + if(nonblock) + mindata = 0; + else + mindata = 65536; + + if (dag_set_stream_poll64(p->fd, pd->dag_stream, + mindata, &maxwait, &poll) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_set_stream_poll"); + return -1; + } + + if (nonblock) { + pd->dag_flags |= DAGF_NONBLOCK; + } else { + pd->dag_flags &= ~DAGF_NONBLOCK; + } + return (0); +} + +static int +dag_get_datalink(pcap_t *p) +{ + struct pcap_dag *pd = p->priv; + int index=0, dlt_index=0; + uint8_t types[255]; + + memset(types, 0, 255); + + if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (-1); + } + + p->linktype = 0; + +#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES + /* Get list of possible ERF types for this card */ + if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "dag_get_stream_erf_types"); + return (-1); + } + + while (types[index]) { + +#elif defined HAVE_DAG_GET_ERF_TYPES + /* Get list of possible ERF types for this card */ + if (dag_get_erf_types(p->fd, types, 255) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "dag_get_erf_types"); + return (-1); + } + + while (types[index]) { +#else + /* Check the type through a dagapi call. */ + types[index] = dag_linktype(p->fd); + + { +#endif + switch((types[index] & 0x7f)) { + + case ERF_TYPE_HDLC_POS: + case ERF_TYPE_COLOR_HDLC_POS: + case ERF_TYPE_DSM_COLOR_HDLC_POS: + case ERF_TYPE_COLOR_HASH_POS: + p->dlt_list[dlt_index++] = DLT_CHDLC; + p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; + p->dlt_list[dlt_index++] = DLT_FRELAY; + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; + + case ERF_TYPE_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_HASH_ETH: + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list[dlt_index++] = DLT_EN10MB; + p->dlt_list[dlt_index++] = DLT_DOCSIS; + if(!p->linktype) + p->linktype = DLT_EN10MB; + break; + + case ERF_TYPE_ATM: + case ERF_TYPE_AAL5: + case ERF_TYPE_MC_ATM: + case ERF_TYPE_MC_AAL5: + p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; + p->dlt_list[dlt_index++] = DLT_SUNATM; + if(!p->linktype) + p->linktype = DLT_ATM_RFC1483; + break; + + case ERF_TYPE_COLOR_MC_HDLC_POS: + case ERF_TYPE_MC_HDLC: + p->dlt_list[dlt_index++] = DLT_CHDLC; + p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; + p->dlt_list[dlt_index++] = DLT_FRELAY; + p->dlt_list[dlt_index++] = DLT_MTP2; + p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; + p->dlt_list[dlt_index++] = DLT_LAPD; + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; + + case ERF_TYPE_IPV4: + p->dlt_list[dlt_index++] = DLT_RAW; + p->dlt_list[dlt_index++] = DLT_IPV4; + if(!p->linktype) + p->linktype = DLT_RAW; + break; + + case ERF_TYPE_IPV6: + p->dlt_list[dlt_index++] = DLT_RAW; + p->dlt_list[dlt_index++] = DLT_IPV6; + if(!p->linktype) + p->linktype = DLT_RAW; + break; + + case ERF_TYPE_LEGACY: + case ERF_TYPE_MC_RAW: + case ERF_TYPE_MC_RAW_CHANNEL: + case ERF_TYPE_IP_COUNTER: + case ERF_TYPE_TCP_FLOW_COUNTER: + case ERF_TYPE_INFINIBAND: + case ERF_TYPE_RAW_LINK: + case ERF_TYPE_INFINIBAND_LINK: + case ERF_TYPE_META: + default: + /* Libpcap cannot deal with these types yet */ + /* Add no 'native' DLTs, but still covered by DLT_ERF */ + break; + + } /* switch */ + index++; + } + + p->dlt_list[dlt_index++] = DLT_ERF; + + p->dlt_count = dlt_index; + + if(!p->linktype) + p->linktype = DLT_ERF; + + return p->linktype; +} + +#ifdef DAG_ONLY +/* + * This libpcap build supports only DAG cards, not regular network + * interfaces. + */ + +/* + * There are no regular interfaces, just DAG interfaces. + */ +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf) +{ + return (0); +} + +/* + * Attempts to open a regular interface fail. + */ +pcap_t * +pcapint_create_interface(const char *device, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "This version of libpcap only supports DAG cards"); + return NULL; +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING " (DAG-only)"); +} +#endif diff --git a/src/libpcap-1.10.5/pcap-dag.h b/src/libpcap-1.10.5/pcap-dag.h new file mode 100644 index 0000000000..67361af9ad --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dag.h @@ -0,0 +1,12 @@ +/* + * pcap-dag.c: Packet capture interface for Endace DAG card. + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is only needed when compiling in the DAG card code + * at the same time as another type of device. + * + * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) + */ + +pcap_t *dag_create(const char *, char *, int *); +int dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-dbus.c b/src/libpcap-1.10.5/pcap-dbus.c new file mode 100644 index 0000000000..df7eca788c --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dbus.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2012 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include +#include + +#include + +#include "pcap-int.h" +#include "pcap-dbus.h" + +/* + * Private data for capturing on D-Bus. + */ +struct pcap_dbus { + DBusConnection *conn; + u_int packets_read; /* count of packets read */ +}; + +static int +dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct pcap_dbus *handlep = handle->priv; + + struct pcap_pkthdr pkth; + DBusMessage *message; + + char *raw_msg; + int raw_msg_len; + + int count = 0; + + message = dbus_connection_pop_message(handlep->conn); + + while (!message) { + /* XXX handle->opt.timeout = timeout_ms; */ + if (!dbus_connection_read_write(handlep->conn, 100)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); + return -1; + } + + if (handle->break_loop) { + handle->break_loop = 0; + return -2; + } + + message = dbus_connection_pop_message(handlep->conn); + } + + if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); + return -1; + } + + if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { + pkth.caplen = pkth.len = raw_msg_len; + /* pkth.caplen = min (payload_len, handle->snapshot); */ + + gettimeofday(&pkth.ts, NULL); + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, (u_char *)raw_msg); + count++; + } + + dbus_free(raw_msg); + } + return count; +} + +static int +dbus_write(pcap_t *handle, const void *buf, int size) +{ + /* XXX, not tested */ + struct pcap_dbus *handlep = handle->priv; + + DBusError error = DBUS_ERROR_INIT; + DBusMessage *msg; + + if (!(msg = dbus_message_demarshal(buf, size, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); + dbus_error_free(&error); + return -1; + } + + dbus_connection_send(handlep->conn, msg, NULL); + dbus_connection_flush(handlep->conn); + + dbus_message_unref(msg); + return 0; +} + +static int +dbus_stats(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_dbus *handlep = handle->priv; + + stats->ps_recv = handlep->packets_read; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + return 0; +} + +static void +dbus_cleanup(pcap_t *handle) +{ + struct pcap_dbus *handlep = handle->priv; + + dbus_connection_unref(handlep->conn); + + pcapint_cleanup_live_common(handle); +} + +/* + * We don't support non-blocking mode. I'm not sure what we'd + * do to support it and, given that we don't support select()/ + * poll()/epoll_wait()/kevent() etc., it probably doesn't + * matter. + */ +static int +dbus_getnonblock(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for capturing on D-Bus"); + return (-1); +} + +static int +dbus_setnonblock(pcap_t *p, int nonblock _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for capturing on D-Bus"); + return (-1); +} + +static int +dbus_activate(pcap_t *handle) +{ +#define EAVESDROPPING_RULE "eavesdrop=true," + + static const char *rules[] = { + EAVESDROPPING_RULE "type='signal'", + EAVESDROPPING_RULE "type='method_call'", + EAVESDROPPING_RULE "type='method_return'", + EAVESDROPPING_RULE "type='error'", + }; + + #define N_RULES sizeof(rules)/sizeof(rules[0]) + + struct pcap_dbus *handlep = handle->priv; + const char *dev = handle->opt.device; + + DBusError error = DBUS_ERROR_INIT; + u_int i; + + if (strcmp(dev, "dbus-system") == 0) { + if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else if (strcmp(dev, "dbus-session") == 0) { + if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else if (strncmp(dev, "dbus://", 7) == 0) { + const char *addr = dev + 7; + + if (!(handlep->conn = dbus_connection_open(addr, &error))) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + if (!dbus_bus_register(handlep->conn, &error)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); + dbus_error_free(&error); + return PCAP_ERROR; + } + + } else { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device); + return PCAP_ERROR; + } + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 0; + handle->offset = 0; + handle->linktype = DLT_DBUS; + handle->read_op = dbus_read; + handle->inject_op = dbus_write; + handle->setfilter_op = pcapint_install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ + handle->setdirection_op = NULL; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = dbus_getnonblock; + handle->setnonblock_op = dbus_setnonblock; + handle->stats_op = dbus_stats; + handle->cleanup_op = dbus_cleanup; + +#ifndef _WIN32 + /* + * Unfortunately, trying to do a select()/poll()/epoll_wait()/ + * kevent()/etc. on a D-Bus connection isn't a simple + * case of "give me an FD on which to wait". + * + * Apparently, you have to register "add watch", "remove watch", + * and "toggle watch" functions with + * dbus_connection_set_watch_functions(), + * keep a *set* of FDs, add to that set in the "add watch" + * function, subtract from it in the "remove watch" function, + * and either add to or subtract from that set in the "toggle + * watch" function, and do the wait on *all* of the FDs in the + * set. (Yes, you need the "toggle watch" function, so that + * the main loop doesn't itself need to check for whether + * a given watch is enabled or disabled - most libpcap programs + * know nothing about D-Bus and shouldn't *have* to know anything + * about D-Bus other than how to decode D-Bus messages.) + * + * Implementing that would require considerable changes in + * the way libpcap exports "selectable FDs" to its client. + * Until that's done, we just say "you can't do that". + */ + handle->selectable_fd = handle->fd = -1; +#endif + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to dbus connections. + */ + dbus_cleanup(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum message length for D-Bus (128MB). + */ + if (handle->snapshot <= 0 || handle->snapshot > 134217728) + handle->snapshot = 134217728; + + /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ + if (handle->opt.buffer_size != 0) + dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); + + for (i = 0; i < N_RULES; i++) { + dbus_bus_add_match(handlep->conn, rules[i], &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + + /* try without eavesdrop */ + dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); + if (dbus_error_is_set(&error)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); + dbus_error_free(&error); + dbus_cleanup(handle); + return PCAP_ERROR; + } + } + } + + return 0; +} + +pcap_t * +dbus_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + + if (strcmp(device, "dbus-system") && + strcmp(device, "dbus-session") && + strncmp(device, "dbus://", 7)) + { + *is_ours = 0; + return NULL; + } + + *is_ours = 1; + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dbus); + if (p == NULL) + return (NULL); + + p->activate_op = dbus_activate; + /* + * Set these up front, so that, even if our client tries + * to set non-blocking mode before we're activated, or + * query the state of non-blocking mode, they get an error, + * rather than having the non-blocking mode option set + * for use later. + */ + p->getnonblock_op = dbus_getnonblock; + p->setnonblock_op = dbus_setnonblock; + return (p); +} + +int +dbus_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + /* + * The notion of "connected" vs. "disconnected" doesn't apply. + * XXX - what about the notions of "up" and "running"? + */ + if (pcapint_add_dev(devlistp, "dbus-system", + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus system bus", + err_str) == NULL) + return -1; + if (pcapint_add_dev(devlistp, "dbus-session", + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus session bus", + err_str) == NULL) + return -1; + return 0; +} + diff --git a/src/libpcap-1.10.5/pcap-dbus.h b/src/libpcap-1.10.5/pcap-dbus.h new file mode 100644 index 0000000000..c97f2e121e --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dbus.h @@ -0,0 +1,2 @@ +pcap_t *dbus_create(const char *, char *, int *); +int dbus_findalldevs(pcap_if_list_t *devlistp, char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-dll.rc b/src/libpcap-1.10.5/pcap-dll.rc new file mode 100644 index 0000000000..85de542f08 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dll.rc @@ -0,0 +1,36 @@ +#include "config.h" +#include + + VS_VERSION_INFO VERSIONINFO + FILEVERSION PACKAGE_VERSION_DLL + PRODUCTVERSION PACKAGE_VERSION_DLL + FILEFLAGSMASK 0x3fL + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "https://github.com/the-tcpdump-group/libpcap/" + VALUE "CompanyName", "The TCPdump Group" + VALUE "FileDescription", "System-Independent Interface for User-Level Packet Capture" + VALUE "FileVersion", PACKAGE_VERSION + VALUE "InternalName", PACKAGE_NAME + VALUE "LegalCopyright", "Copyright (c) The TCPdump Group" + VALUE "LegalTrademarks", "" + VALUE "OriginalFilename", PACKAGE_NAME ".dll" + VALUE "ProductName", "libpcap" + VALUE "ProductVersion", PACKAGE_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END + END diff --git a/src/libpcap-1.10.5/pcap-dlpi.c b/src/libpcap-1.10.5/pcap-dlpi.c new file mode 100644 index 0000000000..081f96a589 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dlpi.c @@ -0,0 +1,1937 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * This code contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), + * University College London, and subsequently modified by + * Guy Harris (guy@alum.mit.edu), Mark Pizzolato + * , + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya . + */ + +/* + * Packet capture routine for DLPI under SunOS 5, HP-UX 9/10/11, and AIX. + * + * Notes: + * + * - The DLIOCRAW ioctl() is specific to SunOS. + * + * - There is a bug in bufmod(7) such that setting the snapshot + * length results in data being left of the front of the packet. + * + * - It might be desirable to use pfmod(7) to filter packets in the + * kernel when possible. + * + * - An older version of the HP-UX DLPI Programmer's Guide, which + * I think was advertised as the 10.20 version, used to be available + * at + * + * http://docs.hp.com/hpux/onlinedocs/B2355-90093/B2355-90093.html + * + * but is no longer available; it can still be found at + * + * http://h21007.www2.hp.com/dspp/files/unprotected/Drivers/Docs/Refs/B2355-90093.pdf + * + * in PDF form. + * + * - The HP-UX 10.x, 11.0, and 11i v1.6 version of the HP-UX DLPI + * Programmer's Guide, which I think was once advertised as the + * 11.00 version is available at + * + * http://docs.hp.com/en/B2355-90139/index.html + * + * - The HP-UX 11i v2 version of the HP-UX DLPI Programmer's Guide + * is available at + * + * http://docs.hp.com/en/B2355-90871/index.html + * + * - All of the HP documents describe raw-mode services, which are + * what we use if DL_HP_RAWDLS is defined. XXX - we use __hpux + * in some places to test for HP-UX, but use DL_HP_RAWDLS in + * other places; do we support any versions of HP-UX without + * DL_HP_RAWDLS? + */ + +#include + +#include +#include +#ifdef HAVE_SYS_BUFMOD_H +#include +#endif +#include +#ifdef HAVE_SYS_DLPI_EXT_H +#include +#endif +#ifdef HAVE_HPUX9 +#include +#endif +#ifdef DL_HP_PPA_REQ +#include +#endif +#include +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +#include +#endif + +#ifdef HAVE_HPUX9 +#include +#endif + +#ifdef HAVE_HPUX9 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "dlpisubs.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#if defined(__hpux) + /* + * HP-UX has a /dev/dlpi device; you open it and set the PPA of the actual + * network device you want. + */ + #define HAVE_DEV_DLPI +#elif defined(_AIX) + /* + * AIX has a /dev/dlpi directory, with devices named after the interfaces + * underneath it. + */ + #define PCAP_DEV_PREFIX "/dev/dlpi" +#elif defined(HAVE_SOLARIS) + /* + * Solaris has devices named after the interfaces underneath /dev. + */ + #define PCAP_DEV_PREFIX "/dev" +#endif + +#define MAXDLBUF 8192 + +/* Forwards */ +static char *split_dname(char *, u_int *, char *); +static int dl_doattach(int, int, char *); +#ifdef DL_HP_RAWDLS +static int dl_dohpuxbind(int, char *); +#endif +static int dlpromiscon(pcap_t *, bpf_u_int32); +static int dlbindreq(int, bpf_u_int32, char *); +static int dlbindack(int, char *, char *, int *); +static int dlokack(int, const char *, char *, char *, int *); +static int dlinforeq(int, char *); +static int dlinfoack(int, char *, char *); + +#ifdef HAVE_DL_PASSIVE_REQ_T +static void dlpassive(int, char *); +#endif + +#ifdef DL_HP_RAWDLS +static int dlrawdatareq(int, const u_char *, int); +#endif +static int recv_ack(int, int, const char *, char *, char *, int *); +static char *dlstrerror(char *, size_t, bpf_u_int32); +static char *dlprim(char *, size_t, bpf_u_int32); +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +#define GET_RELEASE_BUFSIZE 32 +static void get_release(char *, size_t, bpf_u_int32 *, bpf_u_int32 *, + bpf_u_int32 *); +#endif +static int send_request(int, char *, int, char *, char *); +#ifdef HAVE_HPUX9 +static int dlpi_kread(int, off_t, void *, u_int, char *); +#endif +#ifdef HAVE_DEV_DLPI +static int get_dlpi_ppa(int, const char *, u_int, u_int *, char *); +#endif + +/* + * Cast a buffer to "union DL_primitives" without provoking warnings + * from the compiler. + */ +#define MAKE_DL_PRIMITIVES(ptr) ((union DL_primitives *)(void *)(ptr)) + +static int +pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + int cc; + u_char *bp; + int flags; + bpf_u_int32 ctlbuf[MAXDLBUF]; + struct strbuf ctl = { + MAXDLBUF, + 0, + (char *)ctlbuf + }; + struct strbuf data; + + flags = 0; + cc = p->cc; + if (cc == 0) { + data.buf = (char *)p->buffer + p->offset; + data.maxlen = p->bufsize; + data.len = 0; + do { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates + * that it has, and return -2 to + * indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + /* + * XXX - check for the DLPI primitive, which + * would be DL_HP_RAWDATA_IND on HP-UX + * if we're in raw mode? + */ + ctl.buf = (char *)ctlbuf; + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + if (getmsg(p->fd, &ctl, &data, &flags) < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + cc = 0; + continue; + + case EAGAIN: + return (0); + } + pcapint_fmt_errmsg_for_errno(p->errbuf, + sizeof(p->errbuf), errno, "getmsg"); + return (-1); + } + cc = data.len; + } while (cc == 0); + bp = (u_char *)p->buffer + p->offset; + } else + bp = p->bp; + + return (pcap_process_pkts(p, callback, user, cnt, bp, cc)); +} + +static int +pcap_inject_dlpi(pcap_t *p, const void *buf, int size) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; +#endif + int ret; + +#if defined(DLIOCRAW) + ret = write(p->fd, buf, size); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } +#elif defined(DL_HP_RAWDLS) + if (pd->send_fd < 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "send: Output FD couldn't be opened"); + return (-1); + } + ret = dlrawdatareq(pd->send_fd, buf, size); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + /* + * putmsg() returns either 0 or -1; it doesn't indicate how + * many bytes were written (presumably they were all written + * or none of them were written). OpenBSD's pcap_inject() + * returns the number of bytes written, so, for API compatibility, + * we return the number of bytes we were told to write. + */ + ret = size; +#else /* no raw mode */ + /* + * XXX - this is a pain, because you might have to extract + * the address from the packet and use it in a DL_UNITDATA_REQ + * request. That would be dependent on the link-layer type. + * + * I also don't know what SAP you'd have to bind the descriptor + * to, or whether you'd need separate "receive" and "send" FDs, + * nor do I know whether you'd need different bindings for + * D/I/X Ethernet and 802.3, or for {FDDI,Token Ring} plus + * 802.2 and {FDDI,Token Ring} plus 802.2 plus SNAP. + * + * So, for now, we just return a "you can't send" indication, + * and leave it up to somebody with a DLPI-based system lacking + * both DLIOCRAW and DL_HP_RAWDLS to supply code to implement + * packet transmission on that system. If they do, they should + * send it to us - but should not send us code that assumes + * Ethernet; if the code doesn't work on non-Ethernet interfaces, + * it should check "p->linktype" and reject the send request if + * it's anything other than DLT_EN10MB. + */ + pcapint_strlcpy(p->errbuf, "send: Not supported on this version of this OS", + PCAP_ERRBUF_SIZE); + ret = -1; +#endif /* raw mode */ + return (ret); +} + +#ifndef DL_IPATM +#define DL_IPATM 0x12 /* ATM Classical IP interface */ +#endif + +#ifdef HAVE_SOLARIS +/* + * For SunATM. + */ +#ifndef A_GET_UNITS +#define A_GET_UNITS (('A'<<8)|118) +#endif /* A_GET_UNITS */ +#ifndef A_PROMISCON_REQ +#define A_PROMISCON_REQ (('A'<<8)|121) +#endif /* A_PROMISCON_REQ */ +#endif /* HAVE_SOLARIS */ + +static void +pcap_cleanup_dlpi(pcap_t *p) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; + + if (pd->send_fd >= 0) { + close(pd->send_fd); + pd->send_fd = -1; + } +#endif + pcapint_cleanup_live_common(p); +} + +static int +open_dlpi_device(const char *name, u_int *ppa, char *errbuf) +{ + int status; + char dname[100]; + char *cp; + int fd; +#ifdef HAVE_DEV_DLPI + u_int unit; +#else + char dname2[100]; +#endif + +#ifdef HAVE_DEV_DLPI + /* + ** Remove any "/dev/" on the front of the device. + */ + cp = strrchr(name, '/'); + if (cp == NULL) + pcapint_strlcpy(dname, name, sizeof(dname)); + else + pcapint_strlcpy(dname, cp + 1, sizeof(dname)); + + /* + * Split the device name into a device type name and a unit number; + * chop off the unit number, so "dname" is just a device type name. + */ + cp = split_dname(dname, &unit, errbuf); + if (cp == NULL) { + /* + * split_dname() has filled in the error message. + */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + *cp = '\0'; + + /* + * Use "/dev/dlpi" as the device. + * + * XXX - HP's DLPI Programmer's Guide for HP-UX 11.00 says that + * the "dl_mjr_num" field is for the "major number of interface + * driver"; that's the major of "/dev/dlpi" on the system on + * which I tried this, but there may be DLPI devices that + * use a different driver, in which case we may need to + * search "/dev" for the appropriate device with that major + * device number, rather than hardwiring "/dev/dlpi". + */ + cp = "/dev/dlpi"; + if ((fd = open(cp, O_RDWR)) < 0) { + if (errno == EPERM || errno == EACCES) { + status = PCAP_ERROR_PERM_DENIED; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with %s - root privilege may be required", + cp, (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "Attempt to open %s failed", cp); + } + return (status); + } + + /* + * Get a table of all PPAs for that device, and search that + * table for the specified device type name and unit number. + */ + status = get_dlpi_ppa(fd, dname, unit, ppa, errbuf); + if (status < 0) { + close(fd); + return (status); + } +#else + /* + * If the device name begins with "/", assume it begins with + * the pathname of the directory containing the device to open; + * otherwise, concatenate the device directory name and the + * device name. + */ + if (*name == '/') + pcapint_strlcpy(dname, name, sizeof(dname)); + else + snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX, + name); + + /* + * Get the unit number, and a pointer to the end of the device + * type name. + */ + cp = split_dname(dname, ppa, errbuf); + if (cp == NULL) { + /* + * split_dname() has filled in the error message. + */ + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + + /* + * Make a copy of the device pathname, and then remove the unit + * number from the device pathname. + */ + pcapint_strlcpy(dname2, dname, sizeof(dname)); + *cp = '\0'; + + /* Try device without unit number */ + if ((fd = open(dname, O_RDWR)) < 0) { + if (errno != ENOENT) { + if (errno == EPERM || errno == EACCES) { + status = PCAP_ERROR_PERM_DENIED; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with %s - root privilege may be required", + dname, + (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "Attempt to open %s failed", dname); + } + return (status); + } + + /* Try again with unit number */ + if ((fd = open(dname2, O_RDWR)) < 0) { + if (errno == ENOENT) { + status = PCAP_ERROR_NO_SUCH_DEVICE; + + /* + * We provide an error message even + * for this error, for diagnostic + * purposes (so that, for example, + * the app can show the message if the + * user requests it). + * + * In it, we just report "No DLPI device + * found" with the device name, so people + * don't get confused and think, for example, + * that if they can't capture on "lo0" + * on Solaris prior to Solaris 11 the fix + * is to change libpcap (or the application + * that uses it) to look for something other + * than "/dev/lo0", as the fix is to use + * Solaris 11 or some operating system + * other than Solaris - you just *can't* + * capture on a loopback interface + * on Solaris prior to Solaris 11, the lack + * of a DLPI device for the loopback + * interface is just a symptom of that + * inability. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s: No DLPI device found", name); + } else { + if (errno == EPERM || errno == EACCES) { + status = PCAP_ERROR_PERM_DENIED; + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with %s - root privilege may be required", + dname2, + (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "Attempt to open %s failed", + dname2); + } + } + return (status); + } + /* XXX Assume unit zero */ + *ppa = 0; + } +#endif + return (fd); +} + +static int +pcap_activate_dlpi(pcap_t *p) +{ +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd = p->priv; +#endif + int status = 0; + int retv; + u_int ppa; +#ifdef HAVE_SOLARIS + int isatm = 0; +#endif + register dl_info_ack_t *infop; +#ifdef HAVE_SYS_BUFMOD_H + bpf_u_int32 ss; +#ifdef HAVE_SOLARIS + char release[GET_RELEASE_BUFSIZE]; + bpf_u_int32 osmajor, osminor, osmicro; +#endif +#endif + bpf_u_int32 buf[MAXDLBUF]; + + p->fd = open_dlpi_device(p->opt.device, &ppa, p->errbuf); + if (p->fd < 0) { + status = p->fd; + goto bad; + } + +#ifdef DL_HP_RAWDLS + /* + * XXX - HP-UX 10.20 and 11.xx don't appear to support sending and + * receiving packets on the same descriptor - you need separate + * descriptors for sending and receiving, bound to different SAPs. + * + * If the open fails, we just leave -1 in "pd->send_fd" and reject + * attempts to send packets, just as if, in pcap-bpf.c, we fail + * to open the BPF device for reading and writing, we just try + * to open it for reading only and, if that succeeds, just let + * the send attempts fail. + */ + pd->send_fd = open("/dev/dlpi", O_RDWR); +#endif + + /* + ** Attach if "style 2" provider + */ + if (dlinforeq(p->fd, p->errbuf) < 0 || + dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; +#ifdef HAVE_SOLARIS + if (infop->dl_mac_type == DL_IPATM) + isatm = 1; +#endif + if (infop->dl_provider_style == DL_STYLE2) { + retv = dl_doattach(p->fd, ppa, p->errbuf); + if (retv < 0) { + status = retv; + goto bad; + } +#ifdef DL_HP_RAWDLS + if (pd->send_fd >= 0) { + retv = dl_doattach(pd->send_fd, ppa, p->errbuf); + if (retv < 0) { + status = retv; + goto bad; + } + } +#endif + } + + if (p->opt.rfmon) { + /* + * This device exists, but we don't support monitor mode + * any platforms that support DLPI. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + +#ifdef HAVE_DL_PASSIVE_REQ_T + /* + * Enable Passive mode to be able to capture on aggregated link. + * Not supported in all Solaris versions. + */ + dlpassive(p->fd, p->errbuf); +#endif + /* + ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally + ** skip if using SINIX) + */ +#if !defined(HAVE_HPUX9) && !defined(HAVE_HPUX10_20_OR_LATER) && !defined(sinix) +#ifdef _AIX + /* + ** AIX. + ** According to IBM's AIX Support Line, the dl_sap value + ** should not be less than 0x600 (1536) for standard Ethernet. + ** However, we seem to get DL_BADADDR - "DLSAP addr in improper + ** format or invalid" - errors if we use 1537 on the "tr0" + ** device, which, given that its name starts with "tr" and that + ** it's IBM, probably means a Token Ring device. (Perhaps we + ** need to use 1537 on "/dev/dlpi/en" because that device is for + ** D/I/X Ethernet, the "SAP" is actually an Ethernet type, and + ** it rejects invalid Ethernet types.) + ** + ** So if 1537 fails, we try 2, as Hyung Sik Yoon of IBM Korea + ** says that works on Token Ring (he says that 0 does *not* + ** work; perhaps that's considered an invalid LLC SAP value - I + ** assume the SAP value in a DLPI bind is an LLC SAP for network + ** types that use 802.2 LLC). + */ + if ((dlbindreq(p->fd, 1537, p->errbuf) < 0 && + dlbindreq(p->fd, 2, p->errbuf) < 0) || + dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { + status = PCAP_ERROR; + goto bad; + } +#elif defined(DL_HP_RAWDLS) + /* + ** HP-UX 10.0x and 10.1x. + */ + if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + if (pd->send_fd >= 0) { + /* + ** XXX - if this fails, just close send_fd and + ** set it to -1, so that you can't send but can + ** still receive? + */ + if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + } +#else /* neither AIX nor HP-UX */ + /* + ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other + ** OS using DLPI. + **/ + if (dlbindreq(p->fd, 0, p->errbuf) < 0 || + dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0) { + status = PCAP_ERROR; + goto bad; + } +#endif /* AIX vs. HP-UX vs. other */ +#endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */ + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + +#ifdef HAVE_SOLARIS + if (isatm) { + /* + ** Have to turn on some special ATM promiscuous mode + ** for SunATM. + ** Do *NOT* turn regular promiscuous mode on; it doesn't + ** help, and may break things. + */ + if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "A_PROMISCON_REQ"); + goto bad; + } + } else +#endif + if (p->opt.promisc) { + /* + ** Enable promiscuous (not necessary on send FD) + */ + retv = dlpromiscon(p, DL_PROMISC_PHYS); + if (retv < 0) { + if (retv == PCAP_ERROR_PERM_DENIED) + status = PCAP_ERROR_PROMISC_PERM_DENIED; + else + status = retv; + goto bad; + } + + /* + ** Try to enable multicast (you would have thought + ** promiscuous would be sufficient). (Skip if using + ** HP-UX or SINIX) (Not necessary on send FD) + */ +#if !defined(__hpux) && !defined(sinix) + retv = dlpromiscon(p, DL_PROMISC_MULTI); + if (retv < 0) + status = PCAP_WARNING; +#endif + } + /* + ** Try to enable SAP promiscuity (when not in promiscuous mode + ** when using HP-UX, when not doing SunATM on Solaris, and never + ** under SINIX) (Not necessary on send FD) + */ +#ifndef sinix +#if defined(__hpux) + /* HP-UX - only do this when not in promiscuous mode */ + if (!p->opt.promisc) { +#elif defined(HAVE_SOLARIS) + /* Solaris - don't do this on SunATM devices */ + if (!isatm) { +#else + /* Everything else (except for SINIX) - always do this */ + { +#endif + retv = dlpromiscon(p, DL_PROMISC_SAP); + if (retv < 0) { + if (p->opt.promisc) { + /* + * Not fatal, since the DL_PROMISC_PHYS mode + * worked. + * + * Report it as a warning, however. + */ + status = PCAP_WARNING; + } else { + /* + * Fatal. + */ + status = retv; + goto bad; + } + } + } +#endif /* sinix */ + + /* + ** HP-UX 9, and HP-UX 10.20 or later, must bind after setting + ** promiscuous options. + */ +#if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER) + if (dl_dohpuxbind(p->fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + /* + ** We don't set promiscuous mode on the send FD, but we'll defer + ** binding it anyway, just to keep the HP-UX 9/10.20 or later + ** code together. + */ + if (pd->send_fd >= 0) { + /* + ** XXX - if this fails, just close send_fd and + ** set it to -1, so that you can't send but can + ** still receive? + */ + if (dl_dohpuxbind(pd->send_fd, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + } +#endif + + /* + ** Determine link type + ** XXX - get SAP length and address length as well, for use + ** when sending packets. + */ + if (dlinforeq(p->fd, p->errbuf) < 0 || + dlinfoack(p->fd, (char *)buf, p->errbuf) < 0) { + status = PCAP_ERROR; + goto bad; + } + + infop = &(MAKE_DL_PRIMITIVES(buf))->info_ack; + if (pcap_process_mactype(p, infop->dl_mac_type) != 0) { + status = PCAP_ERROR; + goto bad; + } + +#ifdef DLIOCRAW + /* + ** This is a non standard SunOS hack to get the full raw link-layer + ** header. + */ + if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "DLIOCRAW"); + goto bad; + } +#endif + +#ifdef HAVE_SYS_BUFMOD_H + ss = p->snapshot; + + /* + ** There is a bug in bufmod(7). When dealing with messages of + ** less than snaplen size it strips data from the beginning not + ** the end. + ** + ** This bug is fixed in 5.3.2. Also, there is a patch available. + ** Ask for bugid 1149065. + */ +#ifdef HAVE_SOLARIS + get_release(release, sizeof (release), &osmajor, &osminor, &osmicro); + if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && + getenv("BUFMOD_FIXED") == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "WARNING: bufmod is broken in SunOS %s; ignoring snaplen.", + release); + ss = 0; + status = PCAP_WARNING; + } +#endif + + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, ss) != 0) { + status = PCAP_ERROR; + goto bad; + } +#endif + + /* + ** As the last operation flush the read side. + */ + if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "FLUSHR"); + goto bad; + } + + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * Success. + * + * "p->fd" is an FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_dlpi; + p->inject_op = pcap_inject_dlpi; + p->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_dlpi; + p->cleanup_op = pcap_cleanup_dlpi; + + return (status); +bad: + pcap_cleanup_dlpi(p); + return (status); +} + +/* + * Split a device name into a device type name and a unit number; + * return the a pointer to the beginning of the unit number, which + * is the end of the device type name, and set "*unitp" to the unit + * number. + * + * Returns NULL on error, and fills "ebuf" with an error message. + */ +static char * +split_dname(char *device, u_int *unitp, char *ebuf) +{ + char *cp; + char *eos; + long unit; + + /* + * Look for a number at the end of the device name string. + */ + cp = device + strlen(device) - 1; + if (*cp < '0' || *cp > '9') { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s missing unit number", + device); + return (NULL); + } + + /* Digits at end of string are unit number */ + while (cp-1 >= device && *(cp-1) >= '0' && *(cp-1) <= '9') + cp--; + + errno = 0; + unit = strtol(cp, &eos, 10); + if (*eos != '\0') { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s bad unit number", device); + return (NULL); + } + if (errno == ERANGE || unit > INT_MAX) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number too large", + device); + return (NULL); + } + if (unit < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s unit number is negative", + device); + return (NULL); + } + *unitp = (u_int)unit; + return (cp); +} + +static int +dl_doattach(int fd, int ppa, char *ebuf) +{ + dl_attach_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + int err; + + req.dl_primitive = DL_ATTACH_REQ; + req.dl_ppa = ppa; + if (send_request(fd, (char *)&req, sizeof(req), "attach", ebuf) < 0) + return (PCAP_ERROR); + + err = dlokack(fd, "attach", (char *)buf, ebuf, NULL); + if (err < 0) + return (err); + return (0); +} + +#ifdef DL_HP_RAWDLS +static int +dl_dohpuxbind(int fd, char *ebuf) +{ + int hpsap; + int uerror; + bpf_u_int32 buf[MAXDLBUF]; + + /* + * XXX - we start at 22 because we used to use only 22, but + * that was just because that was the value used in some + * sample code from HP. With what value *should* we start? + * Does it matter, given that we're enabling SAP promiscuity + * on the input FD? + */ + hpsap = 22; + for (;;) { + if (dlbindreq(fd, hpsap, ebuf) < 0) + return (-1); + if (dlbindack(fd, (char *)buf, ebuf, &uerror) >= 0) + break; + /* + * For any error other than a UNIX EBUSY, give up. + */ + if (uerror != EBUSY) { + /* + * dlbindack() has already filled in ebuf for + * this error. + */ + return (-1); + } + + /* + * For EBUSY, try the next SAP value; that means that + * somebody else is using that SAP. Clear ebuf so + * that application doesn't report the "Device busy" + * error as a warning. + */ + *ebuf = '\0'; + hpsap++; + if (hpsap > 100) { + pcapint_strlcpy(ebuf, + "All SAPs from 22 through 100 are in use", + PCAP_ERRBUF_SIZE); + return (-1); + } + } + return (0); +} +#endif + +#define STRINGIFY(n) #n + +static int +dlpromiscon(pcap_t *p, bpf_u_int32 level) +{ + dl_promiscon_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + int err; + int uerror; + + req.dl_primitive = DL_PROMISCON_REQ; + req.dl_level = level; + if (send_request(p->fd, (char *)&req, sizeof(req), "promiscon", + p->errbuf) < 0) + return (PCAP_ERROR); + err = dlokack(p->fd, "promiscon" STRINGIFY(level), (char *)buf, + p->errbuf, &uerror); + if (err < 0) { + if (err == PCAP_ERROR_PERM_DENIED) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to set promiscuous mode failed with %s - root privilege may be required", + (uerror == EPERM) ? "EPERM" : "EACCES"); + err = PCAP_ERROR_PROMISC_PERM_DENIED; + } + return (err); + } + return (0); +} + +/* + * Not all interfaces are DLPI interfaces, and thus not all interfaces + * can be opened with DLPI (for example, the loopback interface is not + * a DLPI interface on Solaris prior to Solaris 11), so try to open + * the specified interface; return 0 if we fail with PCAP_ERROR_NO_SUCH_DEVICE + * and 1 otherwise. + */ +static int +is_dlpi_interface(const char *name) +{ + int fd; + u_int ppa; + char errbuf[PCAP_ERRBUF_SIZE]; + + fd = open_dlpi_device(name, &ppa, errbuf); + if (fd < 0) { + /* + * Error - was it PCAP_ERROR_NO_SUCH_DEVICE? + */ + if (fd == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * Yes, so we can't open this because it's + * not a DLPI interface. + */ + return (0); + } + /* + * No, so, in the case where there's a single DLPI + * device for all interfaces of this type ("style + * 2" providers?), we don't know whether it's a DLPI + * interface or not, as we didn't try an attach. + * Say it is a DLPI device, so that the user can at + * least try to open it and report the error (which + * is probably "you don't have permission to open that + * DLPI device"; reporting those interfaces means + * users will ask "why am I getting a permissions error + * when I try to capture" rather than "why am I not + * seeing any interfaces", making the underlying problem + * clearer). + */ + return (1); + } + + /* + * Success. + */ + close(fd); + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do other than mark loopback devices as "the + * connected/disconnected status doesn't apply". + * + * XXX - on Solaris, can we do what the dladm command does, + * i.e. get a connected/disconnected indication from a kstat? + * (Note that you can also get the link speed, and possibly + * other information, from a kstat as well.) + */ + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ +#ifdef HAVE_SOLARIS + int fd; + union { + u_int nunits; + char pad[516]; /* XXX - must be at least 513; is 516 + in "atmgetunits" */ + } buf; + char baname[2+1+1]; + u_int i; +#endif + + /* + * Get the list of regular interfaces first. + */ + if (pcapint_findalldevs_interfaces(devlistp, errbuf, is_dlpi_interface, + get_if_flags) == -1) + return (-1); /* failure */ + +#ifdef HAVE_SOLARIS + /* + * We may have to do special magic to get ATM devices. + */ + if ((fd = open("/dev/ba", O_RDWR)) < 0) { + /* + * We couldn't open the "ba" device. + * For now, just give up; perhaps we should + * return an error if the problem is neither + * a "that device doesn't exist" error (ENOENT, + * ENXIO, etc.) or a "you're not allowed to do + * that" error (EPERM, EACCES). + */ + return (0); + } + + if (strioctl(fd, A_GET_UNITS, sizeof(buf), (char *)&buf) < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "A_GET_UNITS"); + return (-1); + } + for (i = 0; i < buf.nunits; i++) { + snprintf(baname, sizeof baname, "ba%u", i); + /* + * XXX - is there a notion of "up" and "running"? + * And is there a way to determine whether the + * interface is plugged into a network? + */ + if (pcapint_add_dev(devlistp, baname, 0, NULL, errbuf) == NULL) + return (-1); + } +#endif + + return (0); +} + +static int +send_request(int fd, char *ptr, int len, char *what, char *ebuf) +{ + struct strbuf ctl; + int flags; + + ctl.maxlen = 0; + ctl.len = len; + ctl.buf = ptr; + + flags = 0; + if (putmsg(fd, &ctl, (struct strbuf *) NULL, flags) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "send_request: putmsg \"%s\"", what); + return (-1); + } + return (0); +} + +static int +recv_ack(int fd, int size, const char *what, char *bufp, char *ebuf, int *uerror) +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + char errmsgbuf[PCAP_ERRBUF_SIZE]; + char dlprimbuf[64]; + + /* + * Clear out "*uerror", so it's only set for DL_ERROR_ACK/DL_SYSERR, + * making that the only place where EBUSY is treated specially. + */ + if (uerror != NULL) + *uerror = 0; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + flags = 0; + if (getmsg(fd, &ctl, (struct strbuf*)NULL, &flags) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "recv_ack: %s getmsg", what); + return (PCAP_ERROR); + } + + dlp = MAKE_DL_PRIMITIVES(ctl.buf); + switch (dlp->dl_primitive) { + + case DL_INFO_ACK: + case DL_BIND_ACK: + case DL_OK_ACK: +#ifdef DL_HP_PPA_ACK + case DL_HP_PPA_ACK: +#endif + /* These are OK */ + break; + + case DL_ERROR_ACK: + switch (dlp->error_ack.dl_errno) { + + case DL_SYSERR: + if (uerror != NULL) + *uerror = dlp->error_ack.dl_unix_errno; + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + dlp->error_ack.dl_unix_errno, + "recv_ack: %s: UNIX error", what); + if (dlp->error_ack.dl_unix_errno == EPERM || + dlp->error_ack.dl_unix_errno == EACCES) + return (PCAP_ERROR_PERM_DENIED); + break; + + default: + /* + * Neither EPERM nor EACCES. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: %s", what, + dlstrerror(errmsgbuf, sizeof (errmsgbuf), dlp->error_ack.dl_errno)); + if (dlp->error_ack.dl_errno == DL_BADPPA) + return (PCAP_ERROR_NO_SUCH_DEVICE); + else if (dlp->error_ack.dl_errno == DL_ACCESS) + return (PCAP_ERROR_PERM_DENIED); + break; + } + return (PCAP_ERROR); + + default: + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: Unexpected primitive ack %s", + what, dlprim(dlprimbuf, sizeof (dlprimbuf), dlp->dl_primitive)); + return (PCAP_ERROR); + } + + if (ctl.len < size) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "recv_ack: %s: Ack too small (%d < %d)", + what, ctl.len, size); + return (PCAP_ERROR); + } + return (ctl.len); +} + +static char * +dlstrerror(char *errbuf, size_t errbufsize, bpf_u_int32 dl_errno) +{ + switch (dl_errno) { + + case DL_ACCESS: + return ("Improper permissions for request"); + + case DL_BADADDR: + return ("DLSAP addr in improper format or invalid"); + + case DL_BADCORR: + return ("Seq number not from outstand DL_CONN_IND"); + + case DL_BADDATA: + return ("User data exceeded provider limit"); + + case DL_BADPPA: +#ifdef HAVE_DEV_DLPI + /* + * With a single "/dev/dlpi" device used for all + * DLPI providers, PPAs have nothing to do with + * unit numbers. + */ + return ("Specified PPA was invalid"); +#else + /* + * We have separate devices for separate devices; + * the PPA is just the unit number. + */ + return ("Specified PPA (device unit) was invalid"); +#endif + + case DL_BADPRIM: + return ("Primitive received not known by provider"); + + case DL_BADQOSPARAM: + return ("QOS parameters contained invalid values"); + + case DL_BADQOSTYPE: + return ("QOS structure type is unknown/unsupported"); + + case DL_BADSAP: + return ("Bad LSAP selector"); + + case DL_BADTOKEN: + return ("Token used not an active stream"); + + case DL_BOUND: + return ("Attempted second bind with dl_max_conind"); + + case DL_INITFAILED: + return ("Physical link initialization failed"); + + case DL_NOADDR: + return ("Provider couldn't allocate alternate address"); + + case DL_NOTINIT: + return ("Physical link not initialized"); + + case DL_OUTSTATE: + return ("Primitive issued in improper state"); + + case DL_SYSERR: + return ("UNIX system error occurred"); + + case DL_UNSUPPORTED: + return ("Requested service not supplied by provider"); + + case DL_UNDELIVERABLE: + return ("Previous data unit could not be delivered"); + + case DL_NOTSUPPORTED: + return ("Primitive is known but not supported"); + + case DL_TOOMANY: + return ("Limit exceeded"); + + case DL_NOTENAB: + return ("Promiscuous mode not enabled"); + + case DL_BUSY: + return ("Other streams for PPA in post-attached"); + + case DL_NOAUTO: + return ("Automatic handling XID&TEST not supported"); + + case DL_NOXIDAUTO: + return ("Automatic handling of XID not supported"); + + case DL_NOTESTAUTO: + return ("Automatic handling of TEST not supported"); + + case DL_XIDAUTO: + return ("Automatic handling of XID response"); + + case DL_TESTAUTO: + return ("Automatic handling of TEST response"); + + case DL_PENDING: + return ("Pending outstanding connect indications"); + + default: + snprintf(errbuf, errbufsize, "Error %02x", dl_errno); + return (errbuf); + } +} + +static char * +dlprim(char *primbuf, size_t primbufsize, bpf_u_int32 prim) +{ + switch (prim) { + + case DL_INFO_REQ: + return ("DL_INFO_REQ"); + + case DL_INFO_ACK: + return ("DL_INFO_ACK"); + + case DL_ATTACH_REQ: + return ("DL_ATTACH_REQ"); + + case DL_DETACH_REQ: + return ("DL_DETACH_REQ"); + + case DL_BIND_REQ: + return ("DL_BIND_REQ"); + + case DL_BIND_ACK: + return ("DL_BIND_ACK"); + + case DL_UNBIND_REQ: + return ("DL_UNBIND_REQ"); + + case DL_OK_ACK: + return ("DL_OK_ACK"); + + case DL_ERROR_ACK: + return ("DL_ERROR_ACK"); + + case DL_SUBS_BIND_REQ: + return ("DL_SUBS_BIND_REQ"); + + case DL_SUBS_BIND_ACK: + return ("DL_SUBS_BIND_ACK"); + + case DL_UNITDATA_REQ: + return ("DL_UNITDATA_REQ"); + + case DL_UNITDATA_IND: + return ("DL_UNITDATA_IND"); + + case DL_UDERROR_IND: + return ("DL_UDERROR_IND"); + + case DL_UDQOS_REQ: + return ("DL_UDQOS_REQ"); + + case DL_CONNECT_REQ: + return ("DL_CONNECT_REQ"); + + case DL_CONNECT_IND: + return ("DL_CONNECT_IND"); + + case DL_CONNECT_RES: + return ("DL_CONNECT_RES"); + + case DL_CONNECT_CON: + return ("DL_CONNECT_CON"); + + case DL_TOKEN_REQ: + return ("DL_TOKEN_REQ"); + + case DL_TOKEN_ACK: + return ("DL_TOKEN_ACK"); + + case DL_DISCONNECT_REQ: + return ("DL_DISCONNECT_REQ"); + + case DL_DISCONNECT_IND: + return ("DL_DISCONNECT_IND"); + + case DL_RESET_REQ: + return ("DL_RESET_REQ"); + + case DL_RESET_IND: + return ("DL_RESET_IND"); + + case DL_RESET_RES: + return ("DL_RESET_RES"); + + case DL_RESET_CON: + return ("DL_RESET_CON"); + + default: + snprintf(primbuf, primbufsize, "unknown primitive 0x%x", + prim); + return (primbuf); + } +} + +static int +dlbindreq(int fd, bpf_u_int32 sap, char *ebuf) +{ + + dl_bind_req_t req; + + memset((char *)&req, 0, sizeof(req)); + req.dl_primitive = DL_BIND_REQ; + /* XXX - what if neither of these are defined? */ +#if defined(DL_HP_RAWDLS) + req.dl_max_conind = 1; /* XXX magic number */ + req.dl_service_mode = DL_HP_RAWDLS; +#elif defined(DL_CLDLS) + req.dl_service_mode = DL_CLDLS; +#endif + req.dl_sap = sap; + + return (send_request(fd, (char *)&req, sizeof(req), "bind", ebuf)); +} + +static int +dlbindack(int fd, char *bufp, char *ebuf, int *uerror) +{ + + return (recv_ack(fd, DL_BIND_ACK_SIZE, "bind", bufp, ebuf, uerror)); +} + +static int +dlokack(int fd, const char *what, char *bufp, char *ebuf, int *uerror) +{ + + return (recv_ack(fd, DL_OK_ACK_SIZE, what, bufp, ebuf, uerror)); +} + + +static int +dlinforeq(int fd, char *ebuf) +{ + dl_info_req_t req; + + req.dl_primitive = DL_INFO_REQ; + + return (send_request(fd, (char *)&req, sizeof(req), "info", ebuf)); +} + +static int +dlinfoack(int fd, char *bufp, char *ebuf) +{ + + return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); +} + +#ifdef HAVE_DL_PASSIVE_REQ_T +/* + * Enable DLPI passive mode. We do not care if this request fails, as this + * indicates the underlying DLPI device does not support link aggregation. + */ +static void +dlpassive(int fd, char *ebuf) +{ + dl_passive_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + + req.dl_primitive = DL_PASSIVE_REQ; + + if (send_request(fd, (char *)&req, sizeof(req), "dlpassive", ebuf) == 0) + (void) dlokack(fd, "dlpassive", (char *)buf, ebuf, NULL); +} +#endif + +#ifdef DL_HP_RAWDLS +/* + * There's an ack *if* there's an error. + */ +static int +dlrawdatareq(int fd, const u_char *datap, int datalen) +{ + struct strbuf ctl, data; + long buf[MAXDLBUF]; /* XXX - char? */ + union DL_primitives *dlp; + int dlen; + + dlp = MAKE_DL_PRIMITIVES(buf); + + dlp->dl_primitive = DL_HP_RAWDATA_REQ; + dlen = DL_HP_RAWDATA_REQ_SIZE; + + /* + * HP's documentation doesn't appear to show us supplying any + * address pointed to by the control part of the message. + * I think that's what raw mode means - you just send the raw + * packet, you don't specify where to send it to, as that's + * implied by the destination address. + */ + ctl.maxlen = 0; + ctl.len = dlen; + ctl.buf = (void *)buf; + + data.maxlen = 0; + data.len = datalen; + data.buf = (void *)datap; + + return (putmsg(fd, &ctl, &data, 0)); +} +#endif /* DL_HP_RAWDLS */ + +#if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) +static void +get_release(char *buf, size_t bufsize, bpf_u_int32 *majorp, + bpf_u_int32 *minorp, bpf_u_int32 *microp) +{ + char *cp; + + *majorp = 0; + *minorp = 0; + *microp = 0; + if (sysinfo(SI_RELEASE, buf, bufsize) < 0) { + pcapint_strlcpy(buf, "?", bufsize); + return; + } + cp = buf; + if (!PCAP_ISDIGIT((unsigned char)*cp)) + return; + *majorp = strtol(cp, &cp, 10); + if (*cp++ != '.') + return; + *minorp = strtol(cp, &cp, 10); + if (*cp++ != '.') + return; + *microp = strtol(cp, &cp, 10); +} +#endif + +#ifdef DL_HP_PPA_REQ +/* + * Under HP-UX 10 and HP-UX 11, we can ask for the ppa + */ + + +/* + * Determine ppa number that specifies ifname. + * + * If the "dl_hp_ppa_info_t" doesn't have a "dl_module_id_1" member, + * the code that's used here is the old code for HP-UX 10.x. + * + * However, HP-UX 10.20, at least, appears to have such a member + * in its "dl_hp_ppa_info_t" structure, so the new code is used. + * The new code didn't work on an old 10.20 system on which Rick + * Jones of HP tried it, but with later patches installed, it + * worked - it appears that the older system had those members but + * didn't put anything in them, so, if the search by name fails, we + * do the old search. + * + * Rick suggests that making sure your system is "up on the latest + * lancommon/DLPI/driver patches" is probably a good idea; it'd fix + * that problem, as well as allowing libpcap to see packets sent + * from the system on which the libpcap application is being run. + * (On 10.20, in addition to getting the latest patches, you need + * to turn the kernel "lanc_outbound_promisc_flag" flag on with ADB; + * a posting to "comp.sys.hp.hpux" at + * + * http://www.deja.com/[ST_rn=ps]/getdoc.xp?AN=558092266 + * + * says that, to see the machine's outgoing traffic, you'd need to + * apply the right patches to your system, and also set that variable + * with: + +echo 'lanc_outbound_promisc_flag/W1' | /usr/bin/adb -w /stand/vmunix /dev/kmem + + * which could be put in, for example, "/sbin/init.d/lan". + * + * Setting the variable is not necessary on HP-UX 11.x. + */ +static int +get_dlpi_ppa(register int fd, register const char *device, register u_int unit, + u_int *ppa, register char *ebuf) +{ + register dl_hp_ppa_ack_t *ap; + register dl_hp_ppa_info_t *ipstart, *ip; + register u_int i; + char dname[100]; + register u_long majdev; + struct stat statbuf; + dl_hp_ppa_req_t req; + char buf[MAXDLBUF]; + char *ppa_data_buf; + dl_hp_ppa_ack_t *dlp; + struct strbuf ctl; + int flags; + + memset((char *)&req, 0, sizeof(req)); + req.dl_primitive = DL_HP_PPA_REQ; + + memset((char *)buf, 0, sizeof(buf)); + if (send_request(fd, (char *)&req, sizeof(req), "hpppa", ebuf) < 0) + return (PCAP_ERROR); + + ctl.maxlen = DL_HP_PPA_ACK_SIZE; + ctl.len = 0; + ctl.buf = (char *)buf; + + flags = 0; + /* + * DLPI may return a big chunk of data for a DL_HP_PPA_REQ. The normal + * recv_ack will fail because it set the maxlen to MAXDLBUF (8192) + * which is NOT big enough for a DL_HP_PPA_REQ. + * + * This causes libpcap applications to fail on a system with HP-APA + * installed. + * + * To figure out how big the returned data is, we first call getmsg + * to get the small head and peek at the head to get the actual data + * length, and then issue another getmsg to get the actual PPA data. + */ + /* get the head first */ + if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "get_dlpi_ppa: hpppa getmsg"); + return (PCAP_ERROR); + } + if (ctl.len == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa getmsg: control buffer has no data"); + return (PCAP_ERROR); + } + + dlp = (dl_hp_ppa_ack_t *)ctl.buf; + if (dlp->dl_primitive != DL_HP_PPA_ACK) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa unexpected primitive ack 0x%x", + (bpf_u_int32)dlp->dl_primitive); + return (PCAP_ERROR); + } + + if ((size_t)ctl.len < DL_HP_PPA_ACK_SIZE) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa ack too small (%d < %lu)", + ctl.len, (unsigned long)DL_HP_PPA_ACK_SIZE); + return (PCAP_ERROR); + } + + /* allocate buffer */ + if ((ppa_data_buf = (char *)malloc(dlp->dl_length)) == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "get_dlpi_ppa: hpppa malloc"); + return (PCAP_ERROR); + } + ctl.maxlen = dlp->dl_length; + ctl.len = 0; + ctl.buf = (char *)ppa_data_buf; + /* get the data */ + if (getmsg(fd, &ctl, (struct strbuf *)NULL, &flags) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "get_dlpi_ppa: hpppa getmsg"); + free(ppa_data_buf); + return (PCAP_ERROR); + } + if (ctl.len == -1) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa getmsg: control buffer has no data"); + return (PCAP_ERROR); + } + if ((u_int)ctl.len < dlp->dl_length) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "get_dlpi_ppa: hpppa ack too small (%d < %lu)", + ctl.len, (unsigned long)dlp->dl_length); + free(ppa_data_buf); + return (PCAP_ERROR); + } + + ap = (dl_hp_ppa_ack_t *)buf; + ipstart = (dl_hp_ppa_info_t *)ppa_data_buf; + ip = ipstart; + +#ifdef HAVE_DL_HP_PPA_INFO_T_DL_MODULE_ID_1 + /* + * The "dl_hp_ppa_info_t" structure has a "dl_module_id_1" + * member that should, in theory, contain the part of the + * name for the device that comes before the unit number, + * and should also have a "dl_module_id_2" member that may + * contain an alternate name (e.g., I think Ethernet devices + * have both "lan", for "lanN", and "snap", for "snapN", with + * the former being for Ethernet packets and the latter being + * for 802.3/802.2 packets). + * + * Search for the device that has the specified name and + * instance number. + */ + for (i = 0; i < ap->dl_count; i++) { + if ((strcmp((const char *)ip->dl_module_id_1, device) == 0 || + strcmp((const char *)ip->dl_module_id_2, device) == 0) && + ip->dl_instance_num == unit) + break; + + ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); + } +#else + /* + * We don't have that member, so the search is impossible; make it + * look as if the search failed. + */ + i = ap->dl_count; +#endif + + if (i == ap->dl_count) { + /* + * Well, we didn't, or can't, find the device by name. + * + * HP-UX 10.20, whilst it has "dl_module_id_1" and + * "dl_module_id_2" fields in the "dl_hp_ppa_info_t", + * doesn't seem to fill them in unless the system is + * at a reasonably up-to-date patch level. + * + * Older HP-UX 10.x systems might not have those fields + * at all. + * + * Therefore, we'll search for the entry with the major + * device number of a device with the name "/dev/", + * if such a device exists, as the old code did. + */ + snprintf(dname, sizeof(dname), "/dev/%s%u", device, unit); + if (stat(dname, &statbuf) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "stat: %s", dname); + return (PCAP_ERROR); + } + majdev = major(statbuf.st_rdev); + + ip = ipstart; + + for (i = 0; i < ap->dl_count; i++) { + if (ip->dl_mjr_num == majdev && + ip->dl_instance_num == unit) + break; + + ip = (dl_hp_ppa_info_t *)((u_char *)ipstart + ip->dl_next_offset); + } + } + if (i == ap->dl_count) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "can't find /dev/dlpi PPA for %s%u", device, unit); + return (PCAP_ERROR_NO_SUCH_DEVICE); + } + if (ip->dl_hdw_state == HDW_DEAD) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "%s%d: hardware state: DOWN\n", device, unit); + free(ppa_data_buf); + return (PCAP_ERROR); + } + *ppa = ip->dl_ppa; + free(ppa_data_buf); + return (0); +} +#endif + +#ifdef HAVE_HPUX9 +/* + * Under HP-UX 9, there is no good way to determine the ppa. + * So punt and read it from /dev/kmem. + */ +static struct nlist nl[] = { +#define NL_IFNET 0 + { "ifnet" }, + { "" } +}; + +static char path_vmunix[] = "/hp-ux"; + +/* Determine ppa number that specifies ifname */ +static int +get_dlpi_ppa(register int fd, register const char *ifname, register u_int unit, + u_int *ppa, register char *ebuf) +{ + register const char *cp; + register int kd; + void *addr; + struct ifnet ifnet; + char if_name[sizeof(ifnet.if_name) + 1]; + + cp = strrchr(ifname, '/'); + if (cp != NULL) + ifname = cp + 1; + if (nlist(path_vmunix, &nl) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "nlist %s failed", + path_vmunix); + return (PCAP_ERROR); + } + if (nl[NL_IFNET].n_value == 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "couldn't find %s kernel symbol", + nl[NL_IFNET].n_name); + return (PCAP_ERROR); + } + kd = open("/dev/kmem", O_RDONLY); + if (kd < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "kmem open"); + return (PCAP_ERROR); + } + if (dlpi_kread(kd, nl[NL_IFNET].n_value, + &addr, sizeof(addr), ebuf) < 0) { + close(kd); + return (PCAP_ERROR); + } + for (; addr != NULL; addr = ifnet.if_next) { + if (dlpi_kread(kd, (off_t)addr, + &ifnet, sizeof(ifnet), ebuf) < 0 || + dlpi_kread(kd, (off_t)ifnet.if_name, + if_name, sizeof(ifnet.if_name), ebuf) < 0) { + (void)close(kd); + return (PCAP_ERROR); + } + if_name[sizeof(ifnet.if_name)] = '\0'; + if (strcmp(if_name, ifname) == 0 && ifnet.if_unit == unit) { + *ppa = ifnet.if_index; + return (0); + } + } + + snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't find %s", ifname); + return (PCAP_ERROR_NO_SUCH_DEVICE); +} + +static int +dlpi_kread(register int fd, register off_t addr, + register void *buf, register u_int len, register char *ebuf) +{ + register int cc; + + if (lseek(fd, addr, SEEK_SET) < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "lseek"); + return (-1); + } + cc = read(fd, buf, len); + if (cc < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "read"); + return (-1); + } else if (cc != len) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "short read (%d != %d)", cc, + len); + return (-1); + } + return (cc); +} +#endif + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; +#ifdef DL_HP_RAWDLS + struct pcap_dlpi *pd; +#endif + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi); + if (p == NULL) + return (NULL); + +#ifdef DL_HP_RAWDLS + pd = p->priv; + pd->send_fd = -1; /* it hasn't been opened yet */ +#endif + + p->activate_op = pcap_activate_dlpi; + return (p); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-dos.c b/src/libpcap-1.10.5/pcap-dos.c new file mode 100644 index 0000000000..5093c5f037 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dos.c @@ -0,0 +1,1550 @@ +/* + * This file is part of DOS-libpcap + * Ported to DOS/DOSX by G. Vanem + * + * pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode + * network drivers. + */ + +#include +#include +#include +#include +#include +#include +#include /* for INT_MAX */ +#include + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/pmdrvr.h" + #include "msdos/pm_drvr/pci.h" + #include "msdos/pm_drvr/bios32.h" + #include "msdos/pm_drvr/module.h" + #include "msdos/pm_drvr/3c501.h" + #include "msdos/pm_drvr/3c503.h" + #include "msdos/pm_drvr/3c509.h" + #include "msdos/pm_drvr/3c59x.h" + #include "msdos/pm_drvr/3c515.h" + #include "msdos/pm_drvr/3c90x.h" + #include "msdos/pm_drvr/3c575_cb.h" + #include "msdos/pm_drvr/ne.h" + #include "msdos/pm_drvr/wd.h" + #include "msdos/pm_drvr/accton.h" + #include "msdos/pm_drvr/cs89x0.h" + #include "msdos/pm_drvr/rtl8139.h" + #include "msdos/pm_drvr/ne2k-pci.h" +#endif + +#include "pcap.h" +#include "pcap-dos.h" +#include "pcap-int.h" +#include "msdos/pktdrvr.h" + +#ifdef USE_NDIS2 +#include "msdos/ndis2.h" +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(USE_32BIT_DRIVERS) + #define FLUSHK() do { _printk_safe = 1; _printk_flush(); } while (0) + #define NDIS_NEXT_DEV &rtl8139_dev + + static char *rx_pool = NULL; + static void init_32bit (void); + + static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool); + static int pktq_check (struct rx_ringbuf *q); + static int pktq_inc_out (struct rx_ringbuf *q); + static int pktq_in_index (struct rx_ringbuf *q) LOCKED_FUNC; + static void pktq_clear (struct rx_ringbuf *q) LOCKED_FUNC; + + static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) LOCKED_FUNC; + static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q); + +#else + #define FLUSHK() ((void)0) + #define NDIS_NEXT_DEV NULL +#endif + +/* + * Internal variables/functions in Watt-32 + */ +extern WORD _pktdevclass; +extern BOOL _eth_is_init; +extern int _w32_dynamic_host; +extern int _watt_do_exit; +extern int _watt_is_init; +extern int _w32__bootp_on, _w32__dhcp_on, _w32__rarp_on, _w32__do_mask_req; +extern void (*_w32_usr_post_init) (void); +extern void (*_w32_print_hook)(); + +extern void dbug_write (const char *); /* Watt-32 lib, pcdbug.c */ +extern int pkt_get_mtu (void); + +static int ref_count = 0; + +static u_long mac_count = 0; +static u_long filter_count = 0; + +static volatile BOOL exc_occurred = 0; + +static struct device *handle_to_device [20]; + +static int pcap_activate_dos (pcap_t *p); +static int pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, + u_char *data); +static void pcap_cleanup_dos (pcap_t *p); +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps); +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len); +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp); + +static int ndis_probe (struct device *dev); +static int pkt_probe (struct device *dev); + +static void close_driver (void); +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf); +static int first_init (const char *name, char *ebuf, int promisc); + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf); + +/* + * These are the device we always support + */ +static struct device ndis_dev = { + "ndis", + "NDIS2 LanManager", + 0, + 0,0,0,0,0,0, + NDIS_NEXT_DEV, /* NULL or a 32-bit device */ + ndis_probe + }; + +static struct device pkt_dev = { + "pkt", + "Packet-Driver", + 0, + 0,0,0,0,0,0, + &ndis_dev, + pkt_probe + }; + +static struct device *get_device (int fd) +{ + if (fd <= 0 || fd >= sizeof(handle_to_device)/sizeof(handle_to_device[0])) + return (NULL); + return handle_to_device [fd-1]; +} + +/* + * Private data for capturing on MS-DOS. + */ +struct pcap_dos { + void (*wait_proc)(void); /* call proc while waiting */ + struct pcap_stat stat; +}; + +pcap_t *pcap_create_interface (const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dos); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_dos; + return (p); +} + +/* + * Open MAC-driver with name 'device_name' for live capture of + * network packets. + */ +static int pcap_activate_dos (pcap_t *pcap) +{ + if (pcap->opt.rfmon) { + /* + * No monitor mode on DOS. + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (pcap->snapshot <= 0 || pcap->snapshot > MAXIMUM_SNAPLEN) + pcap->snapshot = MAXIMUM_SNAPLEN; + + if (pcap->snapshot < ETH_MIN+8) + pcap->snapshot = ETH_MIN+8; + + if (pcap->snapshot > ETH_MAX) /* silently accept and truncate large MTUs */ + pcap->snapshot = ETH_MAX; + + pcap->linktype = DLT_EN10MB; /* !! */ + pcap->cleanup_op = pcap_cleanup_dos; + pcap->read_op = pcap_read_dos; + pcap->stats_op = pcap_stats_dos; + pcap->inject_op = pcap_sendpacket_dos; + pcap->setfilter_op = pcap_setfilter_dos; + pcap->setdirection_op = NULL; /* Not implemented.*/ + pcap->fd = ++ref_count; + + pcap->bufsize = ETH_MAX+100; /* add some margin */ + pcap->buffer = calloc (pcap->bufsize, 1); + + if (pcap->fd == 1) /* first time we're called */ + { + if (!init_watt32(pcap, pcap->opt.device, pcap->errbuf) || + !first_init(pcap->opt.device, pcap->errbuf, pcap->opt.promisc)) + { + /* XXX - free pcap->buffer? */ + return (PCAP_ERROR); + } + atexit (close_driver); + } + else if (stricmp(active_dev->name,pcap->opt.device)) + { + snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE, + "Cannot use different devices simultaneously " + "(`%s' vs. `%s')", active_dev->name, pcap->opt.device); + /* XXX - free pcap->buffer? */ + return (PCAP_ERROR); + } + handle_to_device [pcap->fd-1] = active_dev; + return (0); +} + +/* + * Poll the receiver queue and call the pcap callback-handler + * with the packet. + */ +static int +pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data) +{ + struct pcap_dos *pd = p->priv; + struct pcap_pkthdr pcap; + struct timeval now, expiry = { 0,0 }; + int rx_len = 0; + + if (p->opt.timeout > 0) + { + gettimeofday2 (&now, NULL); + expiry.tv_usec = now.tv_usec + 1000UL * p->opt.timeout; + expiry.tv_sec = now.tv_sec; + while (expiry.tv_usec >= 1000000L) + { + expiry.tv_usec -= 1000000L; + expiry.tv_sec++; + } + } + + while (!exc_occurred) + { + volatile struct device *dev; /* might be reset by sig_handler */ + + dev = get_device (p->fd); + if (!dev) + break; + + PCAP_ASSERT (dev->copy_rx_buf || dev->peek_rx_buf); + FLUSHK(); + + /* If driver has a zero-copy receive facility, peek at the queue, + * filter it, do the callback and release the buffer. + */ + if (dev->peek_rx_buf) + { + PCAP_ASSERT (dev->release_rx_buf); + rx_len = (*dev->peek_rx_buf) (&p->buffer); + } + else + { + rx_len = (*dev->copy_rx_buf) (p->buffer, p->snapshot); + } + + if (rx_len > 0) /* got a packet */ + { + mac_count++; + + FLUSHK(); + + pcap.caplen = min (rx_len, p->snapshot); + pcap.len = rx_len; + + if (callback && + (!p->fcode.bf_insns || pcap_filter(p->fcode.bf_insns, p->buffer, pcap.len, pcap.caplen))) + { + filter_count++; + + /* Fix-me!! Should be time of arrival. Not time of + * capture. + */ + gettimeofday2 (&pcap.ts, NULL); + (*callback) (data, &pcap, p->buffer); + } + + if (dev->release_rx_buf) + (*dev->release_rx_buf) (p->buffer); + + if (pcap_pkt_debug > 0) + { + if (callback == watt32_recv_hook) + dbug_write ("pcap_recv_hook\n"); + else dbug_write ("pcap_read_op\n"); + } + FLUSHK(); + return (1); + } + + /* Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + + /* If not to wait for a packet or pcap_cleanup_dos() called from + * e.g. SIGINT handler, exit loop now. + */ + if (p->opt.timeout <= 0 || (volatile int)p->fd <= 0) + break; + + gettimeofday2 (&now, NULL); + + if (timercmp(&now, &expiry, >)) + break; + +#ifndef DJGPP + kbhit(); /* a real CPU hog */ +#endif + + if (pd->wait_proc) + (*pd->wait_proc)(); /* call yield func */ + } + + if (rx_len < 0) /* receive error */ + { + pd->stat.ps_drop++; +#ifdef USE_32BIT_DRIVERS + if (pcap_pkt_debug > 1) + printk ("pkt-err %s\n", pktInfo.error); +#endif + return (-1); + } + return (0); +} + +static int +pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback, u_char *data) +{ + int rc, num = 0; + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(cnt)) + cnt = INT_MAX; + + while (num <= cnt) + { + if (p->fd <= 0) + return (-1); + rc = pcap_read_one (p, callback, data); + if (rc > 0) + num++; + if (rc < 0) + break; + _w32_os_yield(); /* allow SIGINT generation, yield to Win95/NT */ + } + return (num); +} + +/* + * Return network statistics + */ +static int pcap_stats_dos (pcap_t *p, struct pcap_stat *ps) +{ + struct net_device_stats *stats; + struct pcap_dos *pd; + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev) + { + strcpy (p->errbuf, "illegal pcap handle"); + return (-1); + } + + if (!dev->get_stats || (stats = (*dev->get_stats)(dev)) == NULL) + { + strcpy (p->errbuf, "device statistics not available"); + return (-1); + } + + FLUSHK(); + + pd = p->priv; + pd->stat.ps_recv = stats->rx_packets; + pd->stat.ps_drop += stats->rx_missed_errors; + pd->stat.ps_ifdrop = stats->rx_dropped + /* queue full */ + stats->rx_errors; /* HW errors */ + if (ps) + *ps = pd->stat; + + return (0); +} + +/* + * Return detailed network/device statistics. + * May be called after 'dev->close' is called. + */ +int pcap_stats_ex (pcap_t *p, struct pcap_stat_ex *se) +{ + struct device *dev = p ? get_device (p->fd) : NULL; + + if (!dev || !dev->get_stats) + { + pcap_strlcpy (p->errbuf, "detailed device statistics not available", + PCAP_ERRBUF_SIZE); + return (-1); + } + + if (!strnicmp(dev->name,"pkt",3)) + { + pcap_strlcpy (p->errbuf, "pktdrvr doesn't have detailed statistics", + PCAP_ERRBUF_SIZE); + return (-1); + } + memcpy (se, (*dev->get_stats)(dev), sizeof(*se)); + return (0); +} + +/* + * Simply store the filter-code for the pcap_read_dos() callback + * Some day the filter-code could be handed down to the active + * device (pkt_rx1.s or 32-bit device interrupt handler). + */ +static int pcap_setfilter_dos (pcap_t *p, struct bpf_program *fp) +{ + if (!p) + return (-1); + p->fcode = *fp; + return (0); +} + +/* + * Return # of packets received in pcap_read_dos() + */ +u_long pcap_mac_packets (void) +{ + return (mac_count); +} + +/* + * Return # of packets passed through filter in pcap_read_dos() + */ +u_long pcap_filter_packets (void) +{ + return (filter_count); +} + +/* + * Close pcap device. Not called for offline captures. + */ +static void pcap_cleanup_dos (pcap_t *p) +{ + struct pcap_dos *pd; + + if (!exc_occurred) + { + pd = p->priv; + if (pcap_stats(p,NULL) < 0) + pd->stat.ps_drop = 0; + if (!get_device(p->fd)) + return; + + handle_to_device [p->fd-1] = NULL; + p->fd = 0; + if (ref_count > 0) + ref_count--; + if (ref_count > 0) + return; + } + close_driver(); + /* XXX - call pcap_cleanup_live_common? */ +} + +/* + * Return the name of the 1st network interface, + * or NULL if none can be found. + */ +char *pcap_lookupdev (char *ebuf) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if ((*dev->probe)(dev)) + { + FLUSHK(); + probed_dev = (struct device*) dev; /* remember last probed device */ + return (char*) dev->name; + } + } + + if (ebuf) + strcpy (ebuf, "No driver found"); + return (NULL); +} + +/* + * Gets localnet & netmask from Watt-32. + */ +int pcap_lookupnet (const char *device, bpf_u_int32 *localnet, + bpf_u_int32 *netmask, char *errbuf) +{ + DWORD mask, net; + + if (!_watt_is_init) + { + strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be " + "called first"); + return (-1); + } + + mask = _w32_sin_mask; + net = my_ip_addr & mask; + if (net == 0) + { + if (IN_CLASSA(*netmask)) + net = IN_CLASSA_NET; + else if (IN_CLASSB(*netmask)) + net = IN_CLASSB_NET; + else if (IN_CLASSC(*netmask)) + net = IN_CLASSC_NET; + else + { + snprintf (errbuf, PCAP_ERRBUF_SIZE, "inet class for 0x%lx unknown", mask); + return (-1); + } + } + *localnet = htonl (net); + *netmask = htonl (mask); + + ARGSUSED (device); + return (0); +} + +/* + * Get a list of all interfaces that are present and that we probe okay. + * Returns -1 on error, 0 otherwise. + * The list may be NULL empty if no interfaces were up and could be opened. + */ +int pcap_platform_finddevs (pcap_if_list_t *devlistp, char *errbuf) +{ + struct device *dev; + pcap_if_t *curdev; +#if 0 /* Pkt drivers should have no addresses */ + struct sockaddr_in sa_ll_1, sa_ll_2; + struct sockaddr *addr, *netmask, *broadaddr, *dstaddr; +#endif + int ret = 0; + int found = 0; + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) + continue; + + PCAP_ASSERT (dev->close); /* set by probe routine */ + FLUSHK(); + (*dev->close) (dev); + + /* + * XXX - find out whether it's up or running? Does that apply here? + * Can we find out if anything's plugged into the adapter, if it's + * a wired device, and set PCAP_IF_CONNECTION_STATUS_CONNECTED + * or PCAP_IF_CONNECTION_STATUS_DISCONNECTED? + */ + if ((curdev = pcap_add_dev(devlistp, dev->name, 0, + dev->long_name, errbuf)) == NULL) + { + ret = -1; + break; + } + found = 1; +#if 0 /* Pkt drivers should have no addresses */ + memset (&sa_ll_1, 0, sizeof(sa_ll_1)); + memset (&sa_ll_2, 0, sizeof(sa_ll_2)); + sa_ll_1.sin_family = AF_INET; + sa_ll_2.sin_family = AF_INET; + + addr = (struct sockaddr*) &sa_ll_1; + netmask = (struct sockaddr*) &sa_ll_1; + dstaddr = (struct sockaddr*) &sa_ll_1; + broadaddr = (struct sockaddr*) &sa_ll_2; + memset (&sa_ll_2.sin_addr, 0xFF, sizeof(sa_ll_2.sin_addr)); + + if (pcap_add_addr_to_dev(curdev, addr, sizeof(*addr), + netmask, sizeof(*netmask), + broadaddr, sizeof(*broadaddr), + dstaddr, sizeof(*dstaddr), errbuf) < 0) + { + ret = -1; + break; + } +#endif + } + + if (ret == 0 && !found) + strcpy (errbuf, "No drivers found"); + + return (ret); +} + +/* + * pcap_assert() is mainly used for debugging + */ +void pcap_assert (const char *what, const char *file, unsigned line) +{ + FLUSHK(); + fprintf (stderr, "%s (%u): Assertion \"%s\" failed\n", + file, line, what); + close_driver(); + _exit (-1); +} + +/* + * For pcap_offline_read(): wait and yield between printing packets + * to simulate the pace packets where actually recorded. + */ +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait) +{ + if (p) + { + struct pcap_dos *pd = p->priv; + + pd->wait_proc = yield; + p->opt.timeout = wait; + } +} + +/* + * Initialize a named network device. + */ +static struct device * +open_driver (const char *dev_name, char *ebuf, int promisc) +{ + struct device *dev; + + for (dev = (struct device*)dev_base; dev; dev = dev->next) + { + PCAP_ASSERT (dev->name); + + if (strcmp (dev_name,dev->name)) + continue; + + if (!probed_dev) /* user didn't call pcap_lookupdev() first */ + { + PCAP_ASSERT (dev->probe); + + if (!(*dev->probe)(dev)) /* call the xx_probe() function */ + { + snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to detect device `%s'", dev_name); + return (NULL); + } + probed_dev = dev; /* device is probed okay and may be used */ + } + else if (dev != probed_dev) + { + goto not_probed; + } + + FLUSHK(); + + /* Select what traffic to receive + */ + if (promisc) + dev->flags |= (IFF_ALLMULTI | IFF_PROMISC); + else dev->flags &= ~(IFF_ALLMULTI | IFF_PROMISC); + + PCAP_ASSERT (dev->open); + + if (!(*dev->open)(dev)) + { + snprintf (ebuf, PCAP_ERRBUF_SIZE, "failed to activate device `%s'", dev_name); + if (pktInfo.error && !strncmp(dev->name,"pkt",3)) + { + strcat (ebuf, ": "); + strcat (ebuf, pktInfo.error); + } + return (NULL); + } + + /* Some devices need this to operate in promiscuous mode + */ + if (promisc && dev->set_multicast_list) + (*dev->set_multicast_list) (dev); + + active_dev = dev; /* remember our active device */ + break; + } + + /* 'dev_name' not matched in 'dev_base' list. + */ + if (!dev) + { + snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not supported", dev_name); + return (NULL); + } + +not_probed: + if (!probed_dev) + { + snprintf (ebuf, PCAP_ERRBUF_SIZE, "device `%s' not probed", dev_name); + return (NULL); + } + return (dev); +} + +/* + * Deinitialize MAC driver. + * Set receive mode back to default mode. + */ +static void close_driver (void) +{ + /* !!todo: loop over all 'handle_to_device[]' ? */ + struct device *dev = active_dev; + + if (dev && dev->close) + { + (*dev->close) (dev); + FLUSHK(); + } + + active_dev = NULL; + +#ifdef USE_32BIT_DRIVERS + if (rx_pool) + { + k_free (rx_pool); + rx_pool = NULL; + } + if (dev) + pcibios_exit(); +#endif +} + + +#ifdef __DJGPP__ +static void setup_signals (void (*handler)(int)) +{ + signal (SIGSEGV,handler); + signal (SIGILL, handler); + signal (SIGFPE, handler); +} + +static void exc_handler (int sig) +{ +#ifdef USE_32BIT_DRIVERS + if (active_dev->irq > 0) /* excludes IRQ 0 */ + { + disable_irq (active_dev->irq); + irq_eoi_cmd (active_dev->irq); + _printk_safe = 1; + } +#endif + + switch (sig) + { + case SIGSEGV: + fputs ("Catching SIGSEGV.\n", stderr); + break; + case SIGILL: + fputs ("Catching SIGILL.\n", stderr); + break; + case SIGFPE: + _fpreset(); + fputs ("Catching SIGFPE.\n", stderr); + break; + default: + fprintf (stderr, "Catching signal %d.\n", sig); + } + exc_occurred = 1; + close_driver(); +} +#endif /* __DJGPP__ */ + + +/* + * Open the pcap device for the first client calling pcap_activate() + */ +static int first_init (const char *name, char *ebuf, int promisc) +{ + struct device *dev; + +#ifdef USE_32BIT_DRIVERS + rx_pool = k_calloc (RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE); + if (!rx_pool) + { + strcpy (ebuf, "Not enough memory (Rx pool)"); + return (0); + } +#endif + +#ifdef __DJGPP__ + setup_signals (exc_handler); +#endif + +#ifdef USE_32BIT_DRIVERS + init_32bit(); +#endif + + dev = open_driver (name, ebuf, promisc); + if (!dev) + { +#ifdef USE_32BIT_DRIVERS + k_free (rx_pool); + rx_pool = NULL; +#endif + +#ifdef __DJGPP__ + setup_signals (SIG_DFL); +#endif + return (0); + } + +#ifdef USE_32BIT_DRIVERS + /* + * If driver is NOT a 16-bit "pkt/ndis" driver (having a 'copy_rx_buf' + * set in it's probe handler), initialize near-memory ring-buffer for + * the 32-bit device. + */ + if (dev->copy_rx_buf == NULL) + { + dev->get_rx_buf = get_rxbuf; + dev->peek_rx_buf = peek_rxbuf; + dev->release_rx_buf = release_rxbuf; + pktq_init (&dev->queue, RECEIVE_BUF_SIZE, RECEIVE_QUEUE_SIZE, rx_pool); + } +#endif + return (1); +} + +#ifdef USE_32BIT_DRIVERS +static void init_32bit (void) +{ + static int init_pci = 0; + + if (!_printk_file) + _printk_init (64*1024, NULL); /* calls atexit(printk_exit) */ + + if (!init_pci) + (void)pci_init(); /* init BIOS32+PCI interface */ + init_pci = 1; +} +#endif + + +/* + * Hook functions for using Watt-32 together with pcap + */ +static char rxbuf [ETH_MAX+100]; /* rx-buffer with some margin */ +static WORD etype; +static pcap_t pcap_save; + +static void watt32_recv_hook (u_char *dummy, const struct pcap_pkthdr *pcap, + const u_char *buf) +{ + /* Fix me: assumes Ethernet II only */ + struct ether_header *ep = (struct ether_header*) buf; + + memcpy (rxbuf, buf, pcap->caplen); + etype = ep->ether_type; + ARGSUSED (dummy); +} + +#if (WATTCP_VER >= 0x0224) +/* + * This function is used by Watt-32 to poll for a packet. + * i.e. it's set to bypass _eth_arrived() + */ +static void *pcap_recv_hook (WORD *type) +{ + int len = pcap_read_dos (&pcap_save, 1, watt32_recv_hook, NULL); + + if (len < 0) + return (NULL); + + *type = etype; + return (void*) &rxbuf; +} + +/* + * This function is called by Watt-32 (via _eth_xmit_hook). + * If dbug_init() was called, we should trace packets sent. + */ +static int pcap_xmit_hook (const void *buf, unsigned len) +{ + int rc = 0; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit_hook: "); + + if (active_dev && active_dev->xmit) + if ((*active_dev->xmit) (active_dev, buf, len) > 0) + rc = len; + + if (pcap_pkt_debug > 0) + dbug_write (rc ? "ok\n" : "fail\n"); + return (rc); +} +#endif + +static int pcap_sendpacket_dos (pcap_t *p, const void *buf, size_t len) +{ + struct device *dev = p ? get_device(p->fd) : NULL; + + if (!dev || !dev->xmit) + return (-1); + return (*dev->xmit) (dev, buf, len); +} + +/* + * This function is called by Watt-32 in tcp_post_init(). + * We should prevent Watt-32 from using BOOTP/DHCP/RARP etc. + */ +static void (*prev_post_hook) (void); + +static void pcap_init_hook (void) +{ + _w32__bootp_on = _w32__dhcp_on = _w32__rarp_on = 0; + _w32__do_mask_req = 0; + _w32_dynamic_host = 0; + if (prev_post_hook) + (*prev_post_hook)(); +} + +/* + * Suppress PRINT message from Watt-32's sock_init() + */ +static void null_print (void) {} + +/* + * To use features of Watt-32 (netdb functions and socket etc.) + * we must call sock_init(). But we set various hooks to prevent + * using normal PKTDRVR functions in pcpkt.c. This should hopefully + * make Watt-32 and pcap co-operate. + */ +static int init_watt32 (struct pcap *pcap, const char *dev_name, char *err_buf) +{ + char *env; + int rc, MTU, has_ip_addr; + int using_pktdrv = 1; + + /* If user called sock_init() first, we need to reinit in + * order to open debug/trace-file properly + */ + if (_watt_is_init) + sock_exit(); + + env = getenv ("PCAP_TRACE"); + if (env && atoi(env) > 0 && + pcap_pkt_debug < 0) /* if not already set */ + { + dbug_init(); + pcap_pkt_debug = atoi (env); + } + + _watt_do_exit = 0; /* prevent sock_init() calling exit() */ + prev_post_hook = _w32_usr_post_init; + _w32_usr_post_init = pcap_init_hook; + _w32_print_hook = null_print; + + if (dev_name && strncmp(dev_name,"pkt",3)) + using_pktdrv = FALSE; + + rc = sock_init(); + has_ip_addr = (rc != 8); /* IP-address assignment failed */ + + /* if pcap is using a 32-bit driver w/o a pktdrvr loaded, we + * just pretend Watt-32 is initialized okay. + * + * !! fix-me: The Watt-32 config isn't done if no pktdrvr + * was found. In that case my_ip_addr + sin_mask + * have default values. Should be taken from another + * ini-file/environment in any case (ref. tcpdump.ini) + */ + _watt_is_init = 1; + + if (!using_pktdrv || !has_ip_addr) /* for now .... */ + { + static const char myip[] = "192.168.0.1"; + static const char mask[] = "255.255.255.0"; + + printf ("Just guessing, using IP %s and netmask %s\n", myip, mask); + my_ip_addr = aton (myip); + _w32_sin_mask = aton (mask); + } + else if (rc && using_pktdrv) + { + snprintf (err_buf, PCAP_ERRBUF_SIZE, "sock_init() failed, code %d", rc); + return (0); + } + + /* Set recv-hook for peeking in _eth_arrived(). + */ +#if (WATTCP_VER >= 0x0224) + _eth_recv_hook = pcap_recv_hook; + _eth_xmit_hook = pcap_xmit_hook; +#endif + + /* Free the pkt-drvr handle allocated in pkt_init(). + * The above hooks should thus use the handle reopened in open_driver() + */ + if (using_pktdrv) + { + _eth_release(); +/* _eth_is_init = 1; */ /* hack to get Rx/Tx-hooks in Watt-32 working */ + } + + memcpy (&pcap_save, pcap, sizeof(pcap_save)); + MTU = pkt_get_mtu(); + pcap_save.fcode.bf_insns = NULL; + pcap_save.linktype = _eth_get_hwtype (NULL, NULL); + pcap_save.snapshot = MTU > 0 ? MTU : ETH_MAX; /* assume 1514 */ + + /* prevent use of resolve() and resolve_ip() + */ + last_nameserver = 0; + return (1); +} + +int EISA_bus = 0; /* Where is natural place for this? */ + +/* + * Application config hooks to set various driver parameters. + */ + +static const struct config_table debug_tab[] = { + { "PKT.DEBUG", ARG_ATOI, &pcap_pkt_debug }, + { "PKT.VECTOR", ARG_ATOX_W, NULL }, + { "NDIS.DEBUG", ARG_ATOI, NULL }, +#ifdef USE_32BIT_DRIVERS + { "3C503.DEBUG", ARG_ATOI, &ei_debug }, + { "3C503.IO_BASE", ARG_ATOX_W, &el2_dev.base_addr }, + { "3C503.MEMORY", ARG_ATOX_W, &el2_dev.mem_start }, + { "3C503.IRQ", ARG_ATOI, &el2_dev.irq }, + { "3C505.DEBUG", ARG_ATOI, NULL }, + { "3C505.BASE", ARG_ATOX_W, NULL }, + { "3C507.DEBUG", ARG_ATOI, NULL }, + { "3C509.DEBUG", ARG_ATOI, &el3_debug }, + { "3C509.ILOOP", ARG_ATOI, &el3_max_loop }, + { "3C529.DEBUG", ARG_ATOI, NULL }, + { "3C575.DEBUG", ARG_ATOI, &debug_3c575 }, + { "3C59X.DEBUG", ARG_ATOI, &vortex_debug }, + { "3C59X.IFACE0", ARG_ATOI, &vortex_options[0] }, + { "3C59X.IFACE1", ARG_ATOI, &vortex_options[1] }, + { "3C59X.IFACE2", ARG_ATOI, &vortex_options[2] }, + { "3C59X.IFACE3", ARG_ATOI, &vortex_options[3] }, + { "3C90X.DEBUG", ARG_ATOX_W, &tc90xbc_debug }, + { "ACCT.DEBUG", ARG_ATOI, ðpk_debug }, + { "CS89.DEBUG", ARG_ATOI, &cs89_debug }, + { "RTL8139.DEBUG", ARG_ATOI, &rtl8139_debug }, + /* { "RTL8139.FDUPLEX", ARG_ATOI, &rtl8139_options }, */ + { "SMC.DEBUG", ARG_ATOI, &ei_debug }, + /* { "E100.DEBUG", ARG_ATOI, &e100_debug }, */ + { "PCI.DEBUG", ARG_ATOI, &pci_debug }, + { "BIOS32.DEBUG", ARG_ATOI, &bios32_debug }, + { "IRQ.DEBUG", ARG_ATOI, &irq_debug }, + { "TIMER.IRQ", ARG_ATOI, &timer_irq }, +#endif + { NULL } + }; + +/* + * pcap_config_hook() is an extension to application's config + * handling. Uses Watt-32's config-table function. + */ +int pcap_config_hook (const char *keyword, const char *value) +{ + return parse_config_table (debug_tab, NULL, keyword, value); +} + +/* + * Linked list of supported devices + */ +struct device *active_dev = NULL; /* the device we have opened */ +struct device *probed_dev = NULL; /* the device we have probed */ +const struct device *dev_base = &pkt_dev; /* list of network devices */ + +/* + * PKTDRVR device functions + */ +int pcap_pkt_debug = -1; + +static void pkt_close (struct device *dev) +{ + BOOL okay = PktExitDriver(); + + if (pcap_pkt_debug > 1) + fprintf (stderr, "pkt_close(): %d\n", okay); + + if (dev->priv) + free (dev->priv); + dev->priv = NULL; +} + +static int pkt_open (struct device *dev) +{ + PKT_RX_MODE mode; + + if (dev->flags & IFF_PROMISC) + mode = PDRX_ALL_PACKETS; + else mode = PDRX_BROADCAST; + + if (!PktInitDriver(mode)) + return (0); + + PktResetStatistics (pktInfo.handle); + PktQueueBusy (FALSE); + return (1); +} + +static int pkt_xmit (struct device *dev, const void *buf, int len) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (pcap_pkt_debug > 0) + dbug_write ("pcap_xmit\n"); + + if (!PktTransmit(buf,len)) + { + stats->tx_errors++; + return (0); + } + return (len); +} + +static void *pkt_stats (struct device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + if (!stats || !PktSessStatistics(pktInfo.handle)) + return (NULL); + + stats->rx_packets = pktStat.inPackets; + stats->rx_errors = pktStat.lost; + stats->rx_missed_errors = PktRxDropped(); + return (stats); +} + +static int pkt_probe (struct device *dev) +{ + if (!PktSearchDriver()) + return (0); + + dev->open = pkt_open; + dev->xmit = pkt_xmit; + dev->close = pkt_close; + dev->get_stats = pkt_stats; + dev->copy_rx_buf = PktReceive; /* farmem peek and copy routine */ + dev->get_rx_buf = NULL; + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + dev->priv = calloc (sizeof(struct net_device_stats), 1); + if (!dev->priv) + return (0); + return (1); +} + +/* + * NDIS device functions + */ +static void ndis_close (struct device *dev) +{ +#ifdef USE_NDIS2 + NdisShutdown(); +#endif + ARGSUSED (dev); +} + +static int ndis_open (struct device *dev) +{ + int promisc = (dev->flags & IFF_PROMISC); + +#ifdef USE_NDIS2 + if (!NdisInit(promisc)) + return (0); + return (1); +#else + ARGSUSED (promisc); + return (0); +#endif +} + +static void *ndis_stats (struct device *dev) +{ + static struct net_device_stats stats; + + /* to-do */ + ARGSUSED (dev); + return (&stats); +} + +static int ndis_probe (struct device *dev) +{ +#ifdef USE_NDIS2 + if (!NdisOpen()) + return (0); +#endif + + dev->open = ndis_open; + dev->xmit = NULL; + dev->close = ndis_close; + dev->get_stats = ndis_stats; + dev->copy_rx_buf = NULL; /* to-do */ + dev->get_rx_buf = NULL; /* upcall is from rmode driver */ + dev->peek_rx_buf = NULL; + dev->release_rx_buf = NULL; + return (0); +} + +/* + * Search & probe for supported 32-bit (pmode) pcap devices + */ +#if defined(USE_32BIT_DRIVERS) + +struct device el2_dev LOCKED_VAR = { + "3c503", + "EtherLink II", + 0, + 0,0,0,0,0,0, + NULL, + el2_probe + }; + +struct device el3_dev LOCKED_VAR = { + "3c509", + "EtherLink III", + 0, + 0,0,0,0,0,0, + &el2_dev, + el3_probe + }; + +struct device tc515_dev LOCKED_VAR = { + "3c515", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &el3_dev, + tc515_probe + }; + +struct device tc59_dev LOCKED_VAR = { + "3c59x", + "EtherLink PCI", + 0, + 0,0,0,0,0,0, + &tc515_dev, + tc59x_probe + }; + +struct device tc90xbc_dev LOCKED_VAR = { + "3c90x", + "EtherLink 90X", + 0, + 0,0,0,0,0,0, + &tc59_dev, + tc90xbc_probe + }; + +struct device wd_dev LOCKED_VAR = { + "wd", + "Western Digital", + 0, + 0,0,0,0,0,0, + &tc90xbc_dev, + wd_probe + }; + +struct device ne_dev LOCKED_VAR = { + "ne", + "NEx000", + 0, + 0,0,0,0,0,0, + &wd_dev, + ne_probe + }; + +struct device acct_dev LOCKED_VAR = { + "acct", + "Accton EtherPocket", + 0, + 0,0,0,0,0,0, + &ne_dev, + ethpk_probe + }; + +struct device cs89_dev LOCKED_VAR = { + "cs89", + "Crystal Semiconductor", + 0, + 0,0,0,0,0,0, + &acct_dev, + cs89x0_probe + }; + +struct device rtl8139_dev LOCKED_VAR = { + "rtl8139", + "RealTek PCI", + 0, + 0,0,0,0,0,0, + &cs89_dev, + rtl8139_probe /* dev->probe routine */ + }; + +/* + * Dequeue routine is called by polling. + * NOTE: the queue-element is not copied, only a pointer is + * returned at '*buf' + */ +int peek_rxbuf (BYTE **buf) +{ + struct rx_elem *tail, *head; + + PCAP_ASSERT (pktq_check (&active_dev->queue)); + + DISABLE(); + tail = pktq_out_elem (&active_dev->queue); + head = pktq_in_elem (&active_dev->queue); + ENABLE(); + + if (head != tail) + { + PCAP_ASSERT (tail->size < active_dev->queue.elem_size-4-2); + + *buf = &tail->data[0]; + return (tail->size); + } + *buf = NULL; + return (0); +} + +/* + * Release buffer we peeked at above. + */ +int release_rxbuf (BYTE *buf) +{ +#ifndef NDEBUG + struct rx_elem *tail = pktq_out_elem (&active_dev->queue); + + PCAP_ASSERT (&tail->data[0] == buf); +#else + ARGSUSED (buf); +#endif + pktq_inc_out (&active_dev->queue); + return (1); +} + +/* + * get_rxbuf() routine (in locked code) is called from IRQ handler + * to request a buffer. Interrupts are disabled and we have a 32kB stack. + */ +BYTE *get_rxbuf (int len) +{ + int idx; + + if (len < ETH_MIN || len > ETH_MAX) + return (NULL); + + idx = pktq_in_index (&active_dev->queue); + +#ifdef DEBUG + { + static int fan_idx LOCKED_VAR = 0; + writew ("-\\|/"[fan_idx++] | (15 << 8), /* white on black colour */ + 0xB8000 + 2*79); /* upper-right corner, 80-col colour screen */ + fan_idx &= 3; + } +/* writew (idx + '0' + 0x0F00, 0xB8000 + 2*78); */ +#endif + + if (idx != active_dev->queue.out_index) + { + struct rx_elem *head = pktq_in_elem (&active_dev->queue); + + head->size = len; + active_dev->queue.in_index = idx; + return (&head->data[0]); + } + + /* !!to-do: drop 25% of the oldest element + */ + pktq_clear (&active_dev->queue); + return (NULL); +} + +/* + * Simple ring-buffer queue handler for reception of packets + * from network driver. + */ +#define PKTQ_MARKER 0xDEADBEEF + +static int pktq_check (struct rx_ringbuf *q) +{ +#ifndef NDEBUG + int i; + char *buf; +#endif + + if (!q || !q->num_elem || !q->buf_start) + return (0); + +#ifndef NDEBUG + buf = q->buf_start; + + for (i = 0; i < q->num_elem; i++) + { + buf += q->elem_size; + if (*(DWORD*)(buf - sizeof(DWORD)) != PKTQ_MARKER) + return (0); + } +#endif + return (1); +} + +static int pktq_init (struct rx_ringbuf *q, int size, int num, char *pool) +{ + int i; + + q->elem_size = size; + q->num_elem = num; + q->buf_start = pool; + q->in_index = 0; + q->out_index = 0; + + PCAP_ASSERT (size >= sizeof(struct rx_elem) + sizeof(DWORD)); + PCAP_ASSERT (num); + PCAP_ASSERT (pool); + + for (i = 0; i < num; i++) + { +#if 0 + struct rx_elem *elem = (struct rx_elem*) pool; + + /* assert dword aligned elements + */ + PCAP_ASSERT (((unsigned)(&elem->data[0]) & 3) == 0); +#endif + pool += size; + *(DWORD*) (pool - sizeof(DWORD)) = PKTQ_MARKER; + } + return (1); +} + +/* + * Increment the queue 'out_index' (tail). + * Check for wraps. + */ +static int pktq_inc_out (struct rx_ringbuf *q) +{ + q->out_index++; + if (q->out_index >= q->num_elem) + q->out_index = 0; + return (q->out_index); +} + +/* + * Return the queue's next 'in_index' (head). + * Check for wraps. + */ +static int pktq_in_index (struct rx_ringbuf *q) +{ + volatile int index = q->in_index + 1; + + if (index >= q->num_elem) + index = 0; + return (index); +} + +/* + * Return the queue's head-buffer. + */ +static struct rx_elem *pktq_in_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->in_index)); +} + +/* + * Return the queue's tail-buffer. + */ +static struct rx_elem *pktq_out_elem (struct rx_ringbuf *q) +{ + return (struct rx_elem*) (q->buf_start + (q->elem_size * q->out_index)); +} + +/* + * Clear the queue ring-buffer by setting head=tail. + */ +static void pktq_clear (struct rx_ringbuf *q) +{ + q->in_index = q->out_index; +} + +/* + * Symbols that must be linkable for "gcc -O0" + */ +#undef __IOPORT_H +#undef __DMA_H + +#define extern +#define __inline__ + +#include "msdos/pm_drvr/ioport.h" +#include "msdos/pm_drvr/dma.h" + +#endif /* USE_32BIT_DRIVERS */ + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return ("DOS-" PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-dos.h b/src/libpcap-1.10.5/pcap-dos.h new file mode 100644 index 0000000000..bf47fb511e --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dos.h @@ -0,0 +1,225 @@ +/* + * Internal details for libpcap on DOS. + * 32-bit targets: djgpp, Pharlap or DOS4GW. + */ + +#ifndef __PCAP_DOS_H +#define __PCAP_DOS_H + +#ifdef __DJGPP__ +#include /* simple non-conio kbhit */ +#else +#include +#endif + +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef BYTE ETHER[6]; + +#define ETH_ALEN sizeof(ETHER) /* Ether address length */ +#define ETH_HLEN (2*ETH_ALEN+2) /* Ether header length */ +#define ETH_MTU 1500 +#define ETH_MIN 60 +#define ETH_MAX (ETH_MTU+ETH_HLEN) + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define PHARLAP 1 +#define DJGPP 2 +#define DOS4GW 4 + +#ifdef __DJGPP__ + #undef DOSX + #define DOSX DJGPP +#endif + +#ifdef __WATCOMC__ + #undef DOSX + #define DOSX DOS4GW +#endif + +#ifdef __HIGHC__ + #include + #undef DOSX + #define DOSX PHARLAP + #define inline +#else + typedef unsigned int UINT; +#endif + + +#if defined(__GNUC__) || defined(__HIGHC__) + typedef unsigned long long uint64; + typedef unsigned long long QWORD; +#endif + +#if defined(__WATCOMC__) + typedef unsigned __int64 uint64; + typedef unsigned __int64 QWORD; +#endif + +#define ARGSUSED(x) (void) x + +#if defined (__SMALL__) || defined(__LARGE__) + #define DOSX 0 + +#elif !defined(DOSX) + #error DOSX not defined; 1 = PharLap, 2 = djgpp, 4 = DOS4GW +#endif + +#ifdef __HIGHC__ +#define min(a,b) _min(a,b) +#define max(a,b) _max(a,b) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) < (b) ? (b) : (a)) +#endif + +#if !defined(_U_) && defined(__GNUC__) +#define _U_ __attribute__((unused)) +#endif + +#ifndef _U_ +#define _U_ +#endif + +#if defined(USE_32BIT_DRIVERS) + #include "msdos/pm_drvr/lock.h" + + #ifndef RECEIVE_QUEUE_SIZE + #define RECEIVE_QUEUE_SIZE 60 + #endif + + #ifndef RECEIVE_BUF_SIZE + #define RECEIVE_BUF_SIZE (ETH_MAX+20) + #endif + + extern struct device el2_dev LOCKED_VAR; /* 3Com EtherLink II */ + extern struct device el3_dev LOCKED_VAR; /* EtherLink III */ + extern struct device tc59_dev LOCKED_VAR; /* 3Com Vortex Card (?) */ + extern struct device tc515_dev LOCKED_VAR; + extern struct device tc90x_dev LOCKED_VAR; + extern struct device tc90bcx_dev LOCKED_VAR; + extern struct device wd_dev LOCKED_VAR; + extern struct device ne_dev LOCKED_VAR; + extern struct device acct_dev LOCKED_VAR; + extern struct device cs89_dev LOCKED_VAR; + extern struct device rtl8139_dev LOCKED_VAR; + + struct rx_ringbuf { + volatile int in_index; /* queue index head */ + int out_index; /* queue index tail */ + int elem_size; /* size of each element */ + int num_elem; /* number of elements */ + char *buf_start; /* start of buffer pool */ + }; + + struct rx_elem { + DWORD size; /* size copied to this element */ + BYTE data[ETH_MAX+10]; /* add some margin. data[0] should be */ + }; /* dword aligned */ + + extern BYTE *get_rxbuf (int len) LOCKED_FUNC; + extern int peek_rxbuf (BYTE **buf); + extern int release_rxbuf (BYTE *buf); + +#else + #define LOCKED_VAR + #define LOCKED_FUNC + + struct device { + const char *name; + const char *long_name; + DWORD base_addr; /* device I/O address */ + int irq; /* device IRQ number */ + int dma; /* DMA channel */ + DWORD mem_start; /* shared mem start */ + DWORD mem_end; /* shared mem end */ + DWORD rmem_start; /* shmem "recv" start */ + DWORD rmem_end; /* shared "recv" end */ + + struct device *next; /* next device in list */ + + /* interface service routines */ + int (*probe)(struct device *dev); + int (*open) (struct device *dev); + void (*close)(struct device *dev); + int (*xmit) (struct device *dev, const void *buf, int len); + void *(*get_stats)(struct device *dev); + void (*set_multicast_list)(struct device *dev); + + /* driver-to-pcap receive buffer routines */ + int (*copy_rx_buf) (BYTE *buf, int max); /* rx-copy (pktdrvr only) */ + BYTE *(*get_rx_buf) (int len); /* rx-buf fetch/enqueue */ + int (*peek_rx_buf) (BYTE **buf); /* rx-non-copy at queue */ + int (*release_rx_buf) (BYTE *buf); /* release after peek */ + + WORD flags; /* Low-level status flags. */ + void *priv; /* private data */ + }; + + /* + * Network device statistics + */ + typedef struct net_device_stats { + DWORD rx_packets; /* total packets received */ + DWORD tx_packets; /* total packets transmitted */ + DWORD rx_bytes; /* total bytes received */ + DWORD tx_bytes; /* total bytes transmitted */ + DWORD rx_errors; /* bad packets received */ + DWORD tx_errors; /* packet transmit problems */ + DWORD rx_dropped; /* no space in Rx buffers */ + DWORD tx_dropped; /* no space available for Tx */ + DWORD multicast; /* multicast packets received */ + + /* detailed rx_errors: */ + DWORD rx_length_errors; + DWORD rx_over_errors; /* recv'r overrun error */ + DWORD rx_osize_errors; /* recv'r over-size error */ + DWORD rx_crc_errors; /* recv'd pkt with crc error */ + DWORD rx_frame_errors; /* recv'd frame alignment error */ + DWORD rx_fifo_errors; /* recv'r fifo overrun */ + DWORD rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + DWORD tx_aborted_errors; + DWORD tx_carrier_errors; + DWORD tx_fifo_errors; + DWORD tx_heartbeat_errors; + DWORD tx_window_errors; + DWORD tx_collisions; + DWORD tx_jabbers; + } NET_STATS; +#endif + +extern struct device *active_dev LOCKED_VAR; +extern const struct device *dev_base LOCKED_VAR; +extern struct device *probed_dev; + +extern int pcap_pkt_debug; + +extern void _w32_os_yield (void); /* Watt-32's misc.c */ + +#ifdef NDEBUG + #define PCAP_ASSERT(x) ((void)0) + +#else + void pcap_assert (const char *what, const char *file, unsigned line); + + #define PCAP_ASSERT(x) do { \ + if (!(x)) \ + pcap_assert (#x, __FILE__, __LINE__); \ + } while (0) +#endif + +#endif /* __PCAP_DOS_H */ diff --git a/src/libpcap-1.10.5/pcap-dpdk.c b/src/libpcap-1.10.5/pcap-dpdk.c new file mode 100644 index 0000000000..794fae3932 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-dpdk.c @@ -0,0 +1,1084 @@ +/* + * Copyright (C) 2018 jingle YANG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* +Date: Dec 16, 2018 + +Description: +1. Pcap-dpdk provides libpcap the ability to use DPDK with the device name as dpdk:{portid}, such as dpdk:0. +2. DPDK is a set of libraries and drivers for fast packet processing. (https://www.dpdk.org/) +3. The testprogs/capturetest provides 6.4Gbps/800,000 pps on Intel 10-Gigabit X540-AT2 with DPDK 18.11. + +Limitations: +1. DPDK support will be on if DPDK is available. Please set DIR for --with-dpdk[=DIR] with ./configure or -DDPDK_DIR[=DIR] with cmake if DPDK is installed manually. +2. Only support link libdpdk.so dynamically, because the libdpdk.a will not work correctly. +3. Only support read operation, and packet injection has not been supported yet. + +Usage: +1. Compile DPDK as shared library and install.(https://github.com/DPDK/dpdk.git) + +You shall modify the file $RTE_SDK/$RTE_TARGET/.config and set: +CONFIG_RTE_BUILD_SHARED_LIB=y +By the following command: +sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/' $RTE_SDK/$RTE_TARGET/.config + +2. Launch l2fwd that is one of DPDK examples correctly, and get device information. + +You shall learn how to bind nic with DPDK-compatible driver by $RTE_SDK/usertools/dpdk-devbind.py, such as igb_uio. +And enable hugepages by dpdk-setup.sh + +Then launch the l2fwd with dynamic driver support. For example: +$RTE_SDK/examples/l2fwd/$RTE_TARGET/l2fwd -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so -- -p 0x1 + +3. Compile libpcap with dpdk options. + +If DPDK has not been found automatically, you shall export DPDK environment variable which are used for compiling DPDK. And then pass $RTE_SDK/$RTE_TARGET to --with-dpdk or -DDPDK_DIR + +export RTE_SDK={your DPDK base directory} +export RTE_TARGET={your target name} + +3.1 With configure + +./configure --with-dpdk=$RTE_SDK/$RTE_TARGET && make -s all && make -s testprogs && make install + +3.2 With cmake + +mkdir -p build && cd build && cmake -DDPDK_DIR=$RTE_SDK/$RTE_TARGET ../ && make -s all && make -s testprogs && make install + +4. Link your own program with libpcap, and use DPDK with the device name as dpdk:{portid}, such as dpdk:0. +And you shall set DPDK configure options by environment variable DPDK_CFG +For example, the testprogs/capturetest could be launched by: + +env DPDK_CFG="--log-level=debug -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" ./capturetest -i dpdk:0 +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include /* for INT_MAX */ +#include + +#include + +//header for calling dpdk +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap-dpdk.h" + +/* + * Deal with API changes that break source compatibility. + */ + +#ifdef HAVE_STRUCT_RTE_ETHER_ADDR +#define ETHER_ADDR_TYPE struct rte_ether_addr +#else +#define ETHER_ADDR_TYPE struct ether_addr +#endif + +#define DPDK_DEF_LOG_LEV RTE_LOG_ERR +// +// This is set to 0 if we haven't initialized DPDK yet, 1 if we've +// successfully initialized it, a negative value, which is the negative +// of the rte_errno from rte_eal_init(), if we tried to initialize it +// and got an error. +// +static int is_dpdk_pre_inited=0; +#define DPDK_LIB_NAME "libpcap_dpdk" +#define DPDK_DESC "Data Plane Development Kit (DPDK) Interface" +#define DPDK_ERR_PERM_MSG "permission denied, DPDK needs root permission" +#define DPDK_ARGC_MAX 64 +#define DPDK_CFG_MAX_LEN 1024 +#define DPDK_DEV_NAME_MAX 32 +#define DPDK_DEV_DESC_MAX 512 +#define DPDK_CFG_ENV_NAME "DPDK_CFG" +#define DPDK_DEF_MIN_SLEEP_MS 1 +static char dpdk_cfg_buf[DPDK_CFG_MAX_LEN]; +#define DPDK_MAC_ADDR_SIZE 32 +#define DPDK_DEF_MAC_ADDR "00:00:00:00:00:00" +#define DPDK_PCI_ADDR_SIZE 16 +#define DPDK_DEF_CFG "--log-level=error -l0 -dlibrte_pmd_e1000.so -dlibrte_pmd_ixgbe.so -dlibrte_mempool_ring.so" +#define DPDK_PREFIX "dpdk:" +#define DPDK_PORTID_MAX 65535U +#define MBUF_POOL_NAME "mbuf_pool" +#define DPDK_TX_BUF_NAME "tx_buffer" +//The number of elements in the mbuf pool. +#define DPDK_NB_MBUFS 8192U +#define MEMPOOL_CACHE_SIZE 256 +#define MAX_PKT_BURST 32 +// Configurable number of RX/TX ring descriptors +#define RTE_TEST_RX_DESC_DEFAULT 1024 +#define RTE_TEST_TX_DESC_DEFAULT 1024 + +static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; +static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; + +#ifdef RTE_ETHER_MAX_JUMBO_FRAME_LEN +#define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN +#else +#define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN +#endif + +static struct rte_eth_dev_tx_buffer *tx_buffer; + +struct dpdk_ts_helper{ + struct timeval start_time; + uint64_t start_cycles; + uint64_t hz; +}; +struct pcap_dpdk{ + pcap_t * orig; + uint16_t portid; // portid of DPDK + int must_clear_promisc; + uint64_t bpf_drop; + int nonblock; + struct timeval required_select_timeout; + struct timeval prev_ts; + struct rte_eth_stats prev_stats; + struct timeval curr_ts; + struct rte_eth_stats curr_stats; + uint64_t pps; + uint64_t bps; + struct rte_mempool * pktmbuf_pool; + struct dpdk_ts_helper ts_helper; + ETHER_ADDR_TYPE eth_addr; + char mac_addr[DPDK_MAC_ADDR_SIZE]; + char pci_addr[DPDK_PCI_ADDR_SIZE]; + unsigned char pcap_tmp_buf[RTE_ETH_PCAP_SNAPLEN]; +}; + +static struct rte_eth_conf port_conf = { + .rxmode = { + .split_hdr_size = 0, + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, +}; + +static void dpdk_fmt_errmsg_for_rte_errno(char *, size_t, int, + PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(4, 5); + +/* + * Generate an error message based on a format, arguments, and an + * rte_errno, with a message for the rte_errno after the formatted output. + */ +static void dpdk_fmt_errmsg_for_rte_errno(char *errbuf, size_t errbuflen, + int errnum, const char *fmt, ...) +{ + va_list ap; + size_t msglen; + char *p; + size_t errbuflen_remaining; + + va_start(ap, fmt); + vsnprintf(errbuf, errbuflen, fmt, ap); + va_end(ap); + msglen = strlen(errbuf); + + /* + * Do we have enough space to append ": "? + * Including the terminating '\0', that's 3 bytes. + */ + if (msglen + 3 > errbuflen) { + /* No - just give them what we've produced. */ + return; + } + p = errbuf + msglen; + errbuflen_remaining = errbuflen - msglen; + *p++ = ':'; + *p++ = ' '; + *p = '\0'; + msglen += 2; + errbuflen_remaining -= 2; + + /* + * Now append the string for the error code. + * rte_strerror() is thread-safe, at least as of dpdk 18.11, + * unlike strerror() - it uses strerror_r() rather than strerror() + * for UN*X errno values, and prints to what I assume is a per-thread + * buffer (based on the "PER_LCORE" in "RTE_DEFINE_PER_LCORE" used + * to declare the buffers statically) for DPDK errors. + */ + snprintf(p, errbuflen_remaining, "%s", rte_strerror(errnum)); +} + +static int dpdk_init_timer(struct pcap_dpdk *pd){ + gettimeofday(&(pd->ts_helper.start_time),NULL); + pd->ts_helper.start_cycles = rte_get_timer_cycles(); + pd->ts_helper.hz = rte_get_timer_hz(); + if (pd->ts_helper.hz == 0){ + return -1; + } + return 0; +} +static inline void calculate_timestamp(struct dpdk_ts_helper *helper,struct timeval *ts) +{ + uint64_t cycles; + // delta + struct timeval cur_time; + cycles = rte_get_timer_cycles() - helper->start_cycles; + cur_time.tv_sec = (time_t)(cycles/helper->hz); + cur_time.tv_usec = (suseconds_t)((cycles%helper->hz)*1e6/helper->hz); + timeradd(&(helper->start_time), &cur_time, ts); +} + +static uint32_t dpdk_gather_data(unsigned char *data, uint32_t len, struct rte_mbuf *mbuf) +{ + uint32_t total_len = 0; + while (mbuf && (total_len+mbuf->data_len) < len ){ + rte_memcpy(data+total_len, rte_pktmbuf_mtod(mbuf,void *),mbuf->data_len); + total_len+=mbuf->data_len; + mbuf=mbuf->next; + } + return total_len; +} + + +static int dpdk_read_with_timeout(pcap_t *p, struct rte_mbuf **pkts_burst, const uint16_t burst_cnt){ + struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv); + int nb_rx = 0; + int timeout_ms = p->opt.timeout; + int sleep_ms = 0; + if (pd->nonblock){ + // In non-blocking mode, just read once, no matter how many packets are captured. + nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt); + }else{ + // In blocking mode, read many times until packets are captured or timeout or break_loop is set. + // if timeout_ms == 0, it may be blocked forever. + while (timeout_ms == 0 || sleep_ms < timeout_ms){ + nb_rx = (int)rte_eth_rx_burst(pd->portid, 0, pkts_burst, burst_cnt); + if (nb_rx){ // got packets within timeout_ms + break; + }else{ // no packet arrives at this round. + if (p->break_loop){ + break; + } + // sleep for a very short while. + // block sleep is the only choice, since usleep() will impact performance dramatically. + rte_delay_us_block(DPDK_DEF_MIN_SLEEP_MS*1000); + sleep_ms += DPDK_DEF_MIN_SLEEP_MS; + } + } + } + return nb_rx; +} + +static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *cb_arg) +{ + struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv); + int burst_cnt = 0; + int nb_rx = 0; + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_mbuf *m; + struct pcap_pkthdr pcap_header; + // In DPDK, pkt_len is sum of lengths for all segments. And data_len is for one segment + uint32_t pkt_len = 0; + uint32_t caplen = 0; + u_char *bp = NULL; + int i=0; + unsigned int gather_len =0; + int pkt_cnt = 0; + u_char *large_buffer=NULL; + int timeout_ms = p->opt.timeout; + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(max_cnt)) + max_cnt = INT_MAX; + + if (max_cnt < MAX_PKT_BURST){ + burst_cnt = max_cnt; + }else{ + burst_cnt = MAX_PKT_BURST; + } + + while( pkt_cnt < max_cnt){ + if (p->break_loop){ + p->break_loop = 0; + return PCAP_ERROR_BREAK; + } + // read once in non-blocking mode, or try many times waiting for timeout_ms. + // if timeout_ms == 0, it will be blocked until one packet arrives or break_loop is set. + nb_rx = dpdk_read_with_timeout(p, pkts_burst, burst_cnt); + if (nb_rx == 0){ + if (pd->nonblock){ + RTE_LOG(DEBUG, USER1, "dpdk: no packets available in non-blocking mode.\n"); + }else{ + if (p->break_loop){ + RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n"); + p->break_loop = 0; + return PCAP_ERROR_BREAK; + + } + RTE_LOG(DEBUG, USER1, "dpdk: no packets available for timeout %d ms in blocking mode.\n", timeout_ms); + } + // break if dpdk reads 0 packet, no matter in blocking(timeout) or non-blocking mode. + break; + } + pkt_cnt += nb_rx; + for ( i = 0; i < nb_rx; i++) { + m = pkts_burst[i]; + calculate_timestamp(&(pd->ts_helper),&(pcap_header.ts)); + pkt_len = rte_pktmbuf_pkt_len(m); + // caplen = min(pkt_len, p->snapshot); + // caplen will not be changed, no matter how long the rte_pktmbuf + caplen = pkt_len < (uint32_t)p->snapshot ? pkt_len: (uint32_t)p->snapshot; + pcap_header.caplen = caplen; + pcap_header.len = pkt_len; + // volatile prefetch + rte_prefetch0(rte_pktmbuf_mtod(m, void *)); + bp = NULL; + if (m->nb_segs == 1) + { + bp = rte_pktmbuf_mtod(m, u_char *); + }else{ + // use fast buffer pcap_tmp_buf if pkt_len is small, no need to call malloc and free + if ( pkt_len <= RTE_ETH_PCAP_SNAPLEN) + { + gather_len = dpdk_gather_data(pd->pcap_tmp_buf, RTE_ETH_PCAP_SNAPLEN, m); + bp = pd->pcap_tmp_buf; + }else{ + // need call free later + large_buffer = (u_char *)malloc(caplen*sizeof(u_char)); + gather_len = dpdk_gather_data(large_buffer, caplen, m); + bp = large_buffer; + } + + } + if (bp){ + if (p->fcode.bf_insns==NULL || pcapint_filter(p->fcode.bf_insns, bp, pcap_header.len, pcap_header.caplen)){ + cb(cb_arg, &pcap_header, bp); + }else{ + pd->bpf_drop++; + } + } + //free all pktmbuf + rte_pktmbuf_free(m); + if (large_buffer){ + free(large_buffer); + large_buffer=NULL; + } + } + } + return pkt_cnt; +} + +static int pcap_dpdk_inject(pcap_t *p, const void *buf _U_, int size _U_) +{ + //not implemented yet + pcapint_strlcpy(p->errbuf, + "dpdk error: Inject function has not been implemented yet", + PCAP_ERRBUF_SIZE); + return PCAP_ERROR; +} + +static void pcap_dpdk_close(pcap_t *p) +{ + struct pcap_dpdk *pd = p->priv; + if (pd==NULL) + { + return; + } + if (pd->must_clear_promisc) + { + rte_eth_promiscuous_disable(pd->portid); + } + rte_eth_dev_stop(pd->portid); + rte_eth_dev_close(pd->portid); + pcapint_cleanup_live_common(p); +} + +static void nic_stats_display(struct pcap_dpdk *pd) +{ + uint16_t portid = pd->portid; + struct rte_eth_stats stats; + rte_eth_stats_get(portid, &stats); + RTE_LOG(INFO,USER1, "portid:%d, RX-packets: %-10"PRIu64" RX-errors: %-10"PRIu64 + " RX-bytes: %-10"PRIu64" RX-Imissed: %-10"PRIu64"\n", portid, stats.ipackets, stats.ierrors, + stats.ibytes,stats.imissed); + RTE_LOG(INFO,USER1, "portid:%d, RX-PPS: %-10"PRIu64" RX-Mbps: %.2lf\n", portid, pd->pps, pd->bps/1e6f ); +} + +static int pcap_dpdk_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_dpdk *pd = p->priv; + calculate_timestamp(&(pd->ts_helper), &(pd->curr_ts)); + rte_eth_stats_get(pd->portid,&(pd->curr_stats)); + if (ps){ + ps->ps_recv = pd->curr_stats.ipackets; + ps->ps_drop = pd->curr_stats.ierrors; + ps->ps_drop += pd->bpf_drop; + ps->ps_ifdrop = pd->curr_stats.imissed; + } + uint64_t delta_pkt = pd->curr_stats.ipackets - pd->prev_stats.ipackets; + struct timeval delta_tm; + timersub(&(pd->curr_ts),&(pd->prev_ts), &delta_tm); + uint64_t delta_usec = delta_tm.tv_sec*1e6+delta_tm.tv_usec; + uint64_t delta_bit = (pd->curr_stats.ibytes-pd->prev_stats.ibytes)*8; + RTE_LOG(DEBUG, USER1, "delta_usec: %-10"PRIu64" delta_pkt: %-10"PRIu64" delta_bit: %-10"PRIu64"\n", delta_usec, delta_pkt, delta_bit); + pd->pps = (uint64_t)(delta_pkt*1e6f/delta_usec); + pd->bps = (uint64_t)(delta_bit*1e6f/delta_usec); + nic_stats_display(pd); + pd->prev_stats = pd->curr_stats; + pd->prev_ts = pd->curr_ts; + return 0; +} + +static int pcap_dpdk_setnonblock(pcap_t *p, int nonblock){ + struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv); + pd->nonblock = nonblock; + return 0; +} + +static int pcap_dpdk_getnonblock(pcap_t *p){ + struct pcap_dpdk *pd = (struct pcap_dpdk*)(p->priv); + return pd->nonblock; +} +static int check_link_status(uint16_t portid, struct rte_eth_link *plink) +{ + // wait up to 9 seconds to get link status + rte_eth_link_get(portid, plink); + return plink->link_status == ETH_LINK_UP; +} +static void eth_addr_str(ETHER_ADDR_TYPE *addrp, char* mac_str, int len) +{ + int offset=0; + if (addrp == NULL){ + snprintf(mac_str, len-1, DPDK_DEF_MAC_ADDR); + return; + } + for (int i=0; i<6; i++) + { + if (offset >= len) + { // buffer overflow + return; + } + if (i==0) + { + snprintf(mac_str+offset, len-1-offset, "%02X",addrp->addr_bytes[i]); + offset+=2; // FF + }else{ + snprintf(mac_str+offset, len-1-offset, ":%02X", addrp->addr_bytes[i]); + offset+=3; // :FF + } + } + return; +} +// return portid by device name, otherwise return -1 +static uint16_t portid_by_device(char * device) +{ + uint16_t ret = DPDK_PORTID_MAX; + size_t len = strlen(device); + size_t prefix_len = strlen(DPDK_PREFIX); + unsigned long ret_ul = 0L; + char *pEnd; + if (len<=prefix_len || strncmp(device, DPDK_PREFIX, prefix_len)) // check prefix dpdk: + { + return ret; + } + //check all chars are digital + for (int i=prefix_len; device[i]; i++){ + if (device[i]<'0' || device[i]>'9'){ + return ret; + } + } + ret_ul = strtoul(&(device[prefix_len]), &pEnd, 10); + if (pEnd == &(device[prefix_len]) || *pEnd != '\0'){ + return ret; + } + // too large for portid + if (ret_ul >= DPDK_PORTID_MAX){ + return ret; + } + ret = (uint16_t)ret_ul; + return ret; +} + +static int parse_dpdk_cfg(char* dpdk_cfg,char** dargv) +{ + int cnt=0; + memset(dargv,0,sizeof(dargv[0])*DPDK_ARGC_MAX); + //current process name + int skip_space = 1; + int i=0; + RTE_LOG(INFO, USER1,"dpdk cfg: %s\n",dpdk_cfg); + // find first non space char + // The last opt is NULL + for (i=0;dpdk_cfg[i] && cntpriv; + pd->orig = p; + int ret = PCAP_ERROR; + uint16_t nb_ports=0; + uint16_t portid= DPDK_PORTID_MAX; + unsigned nb_mbufs = DPDK_NB_MBUFS; + struct rte_eth_rxconf rxq_conf; + struct rte_eth_txconf txq_conf; + struct rte_eth_conf local_port_conf = port_conf; + struct rte_eth_dev_info dev_info; + int is_port_up = 0; + struct rte_eth_link link; + do{ + //init EAL; fail if we have insufficient permission + char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE]; + ret = dpdk_pre_init(dpdk_pre_init_errbuf, 0); + if (ret < 0) + { + // This returns a negative value on an error. + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Can't open device %s: %s", + p->opt.device, dpdk_pre_init_errbuf); + // ret is set to the correct error + break; + } + if (ret == 0) + { + // This means DPDK isn't available on this machine. + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Can't open device %s: DPDK is not available on this machine", + p->opt.device); + return PCAP_ERROR_NO_SUCH_DEVICE; + } + + ret = dpdk_init_timer(pd); + if (ret<0) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "dpdk error: Init timer is zero with device %s", + p->opt.device); + ret = PCAP_ERROR; + break; + } + + nb_ports = rte_eth_dev_count_avail(); + if (nb_ports == 0) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "dpdk error: No Ethernet ports"); + ret = PCAP_ERROR; + break; + } + + portid = portid_by_device(p->opt.device); + if (portid == DPDK_PORTID_MAX){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "dpdk error: portid is invalid. device %s", + p->opt.device); + ret = PCAP_ERROR_NO_SUCH_DEVICE; + break; + } + + pd->portid = portid; + + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + { + p->snapshot = MAXIMUM_SNAPLEN; + } + // create the mbuf pool + pd->pktmbuf_pool = rte_pktmbuf_pool_create(MBUF_POOL_NAME, nb_mbufs, + MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (pd->pktmbuf_pool == NULL) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, rte_errno, + "dpdk error: Cannot init mbuf pool"); + ret = PCAP_ERROR; + break; + } + // config dev + rte_eth_dev_info_get(portid, &dev_info); + if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + { + local_port_conf.txmode.offloads |=DEV_TX_OFFLOAD_MBUF_FAST_FREE; + } + // only support 1 queue + ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); + if (ret < 0) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, -ret, + "dpdk error: Cannot configure device: port=%u", + portid); + ret = PCAP_ERROR; + break; + } + // adjust rx tx + ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd); + if (ret < 0) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, -ret, + "dpdk error: Cannot adjust number of descriptors: port=%u", + portid); + ret = PCAP_ERROR; + break; + } + // get MAC addr + rte_eth_macaddr_get(portid, &(pd->eth_addr)); + eth_addr_str(&(pd->eth_addr), pd->mac_addr, DPDK_MAC_ADDR_SIZE-1); + + // init one RX queue + rxq_conf = dev_info.default_rxconf; + rxq_conf.offloads = local_port_conf.rxmode.offloads; + ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, + rte_eth_dev_socket_id(portid), + &rxq_conf, + pd->pktmbuf_pool); + if (ret < 0) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, -ret, + "dpdk error: rte_eth_rx_queue_setup:port=%u", + portid); + ret = PCAP_ERROR; + break; + } + + // init one TX queue + txq_conf = dev_info.default_txconf; + txq_conf.offloads = local_port_conf.txmode.offloads; + ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, + rte_eth_dev_socket_id(portid), + &txq_conf); + if (ret < 0) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, -ret, + "dpdk error: rte_eth_tx_queue_setup:port=%u", + portid); + ret = PCAP_ERROR; + break; + } + // Initialize TX buffers + tx_buffer = rte_zmalloc_socket(DPDK_TX_BUF_NAME, + RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, + rte_eth_dev_socket_id(portid)); + if (tx_buffer == NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "dpdk error: Cannot allocate buffer for tx on port %u", portid); + ret = PCAP_ERROR; + break; + } + rte_eth_tx_buffer_init(tx_buffer, MAX_PKT_BURST); + // Start device + ret = rte_eth_dev_start(portid); + if (ret < 0) + { + dpdk_fmt_errmsg_for_rte_errno(p->errbuf, + PCAP_ERRBUF_SIZE, -ret, + "dpdk error: rte_eth_dev_start:port=%u", + portid); + ret = PCAP_ERROR; + break; + } + // set promiscuous mode + if (p->opt.promisc){ + pd->must_clear_promisc=1; + rte_eth_promiscuous_enable(portid); + } + // check link status + is_port_up = check_link_status(portid, &link); + if (!is_port_up){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "dpdk error: link is down, port=%u",portid); + ret = PCAP_ERROR_IFACE_NOT_UP; + break; + } + // reset statistics + rte_eth_stats_reset(pd->portid); + calculate_timestamp(&(pd->ts_helper), &(pd->prev_ts)); + rte_eth_stats_get(pd->portid,&(pd->prev_stats)); + // format pcap_t + pd->portid = portid; + p->fd = pd->portid; + if (p->snapshot <=0 || p->snapshot> MAXIMUM_SNAPLEN) + { + p->snapshot = MAXIMUM_SNAPLEN; + } + p->linktype = DLT_EN10MB; // Ethernet, the 10MB is historical. + p->selectable_fd = p->fd; + p->read_op = pcap_dpdk_dispatch; + p->inject_op = pcap_dpdk_inject; + // using pcapint_filter currently, though DPDK provides their own BPF function. Because DPDK BPF needs load a ELF file as a filter. + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = NULL; + p->set_datalink_op = NULL; + p->getnonblock_op = pcap_dpdk_getnonblock; + p->setnonblock_op = pcap_dpdk_setnonblock; + p->stats_op = pcap_dpdk_stats; + p->cleanup_op = pcap_dpdk_close; + p->breakloop_op = pcapint_breakloop_common; + // set default timeout + pd->required_select_timeout.tv_sec = 0; + pd->required_select_timeout.tv_usec = DPDK_DEF_MIN_SLEEP_MS*1000; + p->required_select_timeout = &pd->required_select_timeout; + ret = 0; // OK + }while(0); + + if (ret <= PCAP_ERROR) // all kinds of error code + { + pcapint_cleanup_live_common(p); + }else{ + rte_eth_dev_get_name_by_port(portid,pd->pci_addr); + RTE_LOG(INFO, USER1,"Port %d device: %s, MAC:%s, PCI:%s\n", portid, p->opt.device, pd->mac_addr, pd->pci_addr); + RTE_LOG(INFO, USER1,"Port %d Link Up. Speed %u Mbps - %s\n", + portid, link.link_speed, + (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? + ("full-duplex") : ("half-duplex\n")); + } + return ret; +} + +// device name for dpdk should be in the form as dpdk:number, such as dpdk:0 +pcap_t * pcap_dpdk_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p=NULL; + *is_ours = 0; + + *is_ours = !strncmp(device, "dpdk:", 5); + if (! *is_ours) + return NULL; + //memset will happen + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dpdk); + + if (p == NULL) + return NULL; + p->activate_op = pcap_dpdk_activate; + return p; +} + +int pcap_dpdk_findalldevs(pcap_if_list_t *devlistp, char *ebuf) +{ + int ret=0; + unsigned int nb_ports = 0; + char dpdk_name[DPDK_DEV_NAME_MAX]; + char dpdk_desc[DPDK_DEV_DESC_MAX]; + ETHER_ADDR_TYPE eth_addr; + char mac_addr[DPDK_MAC_ADDR_SIZE]; + char pci_addr[DPDK_PCI_ADDR_SIZE]; + do{ + // init EAL; return "DPDK not available" if we + // have insufficient permission + char dpdk_pre_init_errbuf[PCAP_ERRBUF_SIZE]; + ret = dpdk_pre_init(dpdk_pre_init_errbuf, 1); + if (ret < 0) + { + // This returns a negative value on an error. + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "Can't look for DPDK devices: %s", + dpdk_pre_init_errbuf); + ret = PCAP_ERROR; + break; + } + if (ret == 0) + { + // This means DPDK isn't available on this machine. + // That just means "don't return any devices". + break; + } + nb_ports = rte_eth_dev_count_avail(); + if (nb_ports == 0) + { + // That just means "don't return any devices". + ret = 0; + break; + } + for (unsigned int i=0; i + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "interface.h" + +struct packet_header { +#ifdef IBMRTPC + struct LengthWords length; + struct tap_header tap; +#endif /* IBMRTPC */ + u_char packet[8] +}; + +extern int errno; + +#define BUFSPACE (4*1024) + +/* Forwards */ +static void efReadError(int, char *); + +void +readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) +{ +#ifdef IBMRTPC + register struct packet_header *ph; + register u_char *bp; + register int inc; +#else /* !IBMRTPC */ + static struct timeval tv = { 0 }; +#endif /* IBMRTPC */ + register int cc, caplen; + register struct bpf_insn *fcode = fp->bf_insns; + union { + struct packet_header hdr; + u_char p[BUFSPACE]; + u_short s; + } buf; + + while (1) { + if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) + efReadError(if_fd, "reader"); + +#ifdef IBMRTPC + /* + * Loop through each packet. + */ + bp = buf.p; + while (cc > 0) { + ph = (struct packet_header *)bp; + caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap +.th_wirelen ; + if (pcapint_filter(fcode, (char *)ph->packet, + ph->tap.th_wirelen, caplen)) { + if (cnt >= 0 && --cnt < 0) + goto out; + (*printit)((char *)ph->packet, + (struct timeval *)ph->tap.th_timestamp, + ph->tap.th_wirelen, caplen); + } + inc = ph->length.PacketOffset; + cc -= inc; + bp += inc; + } +#else /* !IBMRTPC */ + caplen = cc > snaplen ? snaplen : cc ; + if (pcapint_filter(fcode, buf.hdr.packet, cc, caplen)) { + if (cnt >= 0 && --cnt < 0) + goto out; + (*printit)(buf.hdr.packet, &tv, cc, caplen); + } +#endif /* IBMRTPC */ + } + out: + wrapup(if_fd); +} + +/* Call ONLY if read() has returned an error on packet filter */ +static void +efReadError(int fid, char *msg) +{ + if (errno == EINVAL) { /* read MAXINT bytes already! */ + if (lseek(fid, 0, 0) < 0) { + perror("tcpdump: efReadError/lseek"); + exit(-1); + } + else + return; + } + else { + (void) fprintf(stderr, "tcpdump: "); + perror(msg); + exit(-1); + } +} + +void +wrapup(int fd) +{ +#ifdef IBMRTPC + struct enstats es; + + if (ioctl(fd, EIOSTATS, &es) == -1) { + perror("tcpdump: enet ioctl EIOSTATS error"); + exit(-1); + } + + fprintf(stderr, "%d packets queued", es.enStat_Rcnt); + if (es.enStat_Rdrops > 0) + fprintf(stderr, ", %d dropped", es.enStat_Rdrops); + if (es.enStat_Reads > 0) + fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, + es.enStat_Reads > 1 ? "reads" : "read"); + if (es.enStat_MaxRead > 1) + fprintf(stderr, ", %d packets in largest read", + es.enStat_MaxRead); + putc('\n', stderr); +#endif /* IBMRTPC */ + close(fd); +} + +int +initdevice(char *device, int pflag, int *linktype) +{ + struct eniocb ctl; + struct enfilter filter; + u_int maxwaiting; + int if_fd; + +#ifdef IBMRTPC + GETENETDEVICE(0, O_RDONLY, &if_fd); +#else /* !IBMRTPC */ + if_fd = open("/dev/enet", O_RDONLY, 0); +#endif /* IBMRTPC */ + + if (if_fd == -1) { + perror("tcpdump: enet open error"); + error( +"your system may not be properly configured; see \"man enet(4)\""); + exit(-1); + } + + /* Get operating parameters. */ + + if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { + perror("tcpdump: enet ioctl EIOCGETP error"); + exit(-1); + } + + /* Set operating parameters. */ + +#ifdef IBMRTPC + ctl.en_rtout = 1 * ctl.en_hz; + ctl.en_tr_etherhead = 1; + ctl.en_tap_network = 1; + ctl.en_multi_packet = 1; + ctl.en_maxlen = BUFSPACE; +#else /* !IBMRTPC */ + ctl.en_rtout = 64; /* randomly picked value for HZ */ +#endif /* IBMRTPC */ + if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { + perror("tcpdump: enet ioctl EIOCSETP error"); + exit(-1); + } + + /* Flush the receive queue, since we've changed + the operating parameters and we otherwise might + receive data without headers. */ + + if (ioctl(if_fd, EIOCFLUSH) == -1) { + perror("tcpdump: enet ioctl EIOCFLUSH error"); + exit(-1); + } + + /* Set the receive queue depth to its maximum. */ + + maxwaiting = ctl.en_maxwaiting; + if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { + perror("tcpdump: enet ioctl EIOCSETW error"); + exit(-1); + } + +#ifdef IBMRTPC + /* Clear statistics. */ + + if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { + perror("tcpdump: enet ioctl EIOCLRSTAT error"); + exit(-1); + } +#endif /* IBMRTPC */ + + /* Set the filter (accept all packets). */ + + filter.enf_Priority = 3; + filter.enf_FilterLen = 0; + if (ioctl(if_fd, EIOCSETF, &filter) == -1) { + perror("tcpdump: enet ioctl EIOCSETF error"); + exit(-1); + } + /* + * "enetfilter" supports only ethernets. + */ + *linktype = DLT_EN10MB; + + return(if_fd); +} diff --git a/src/libpcap-1.10.5/pcap-filter.manmisc.in b/src/libpcap-1.10.5/pcap-filter.manmisc.in new file mode 100644 index 0000000000..bfb692ff5c --- /dev/null +++ b/src/libpcap-1.10.5/pcap-filter.manmisc.in @@ -0,0 +1,1206 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-FILTER @MAN_MISC_INFO@ "13 June 2023" +.SH NAME +pcap-filter \- packet filter syntax +.br +.ad +.SH DESCRIPTION +.LP +.BR pcap_compile (3PCAP) +is used to compile a string into a filter program. +The resulting filter program can then be applied to +some stream of packets to determine which packets will be supplied to +.BR pcap_loop (3PCAP), +.BR pcap_dispatch (3PCAP), +.BR pcap_next (3PCAP), +or +.BR pcap_next_ex (3PCAP). +.LP +The \fIfilter expression\fP consists of one or more +.IR primitives . +Primitives usually consist of an +.I id +(name or number) preceded by one or more qualifiers. +There are three +different kinds of qualifier: +.IP \fItype\fP +.I type +qualifiers say what kind of thing the id name or number refers to. +Possible types are +.BR host , +.BR net , +.B port +and +.BR portrange . +E.g., `\fBhost\fP foo', `\fBnet\fP 128.3', `\fBport\fP 20', `\fBportrange\fP 6000-6008'. +If there is no type +qualifier, +.B host +is assumed. +.IP \fIdir\fP +.I dir +qualifiers specify a particular transfer direction to and/or from +.IR id . +Possible directions are +.BR src , +.BR dst , +.BR "src or dst" , +.BR "src and dst" , +.BR ra , +.BR ta , +.BR addr1 , +.BR addr2 , +.BR addr3 , +and +.BR addr4 . +E.g., `\fBsrc\fP foo', `\fBdst net\fP 128.3', `\fBsrc or dst port\fP ftp-data'. +If +there is no dir qualifier, `\fBsrc or dst\fP' is assumed. +The +.BR ra , +.BR ta , +.BR addr1 , +.BR addr2 , +.BR addr3 , +and +.B addr4 +qualifiers are only valid for IEEE 802.11 Wireless LAN link layers. +.IP \fIproto\fP +.I proto +qualifiers restrict the match to a particular protocol. +Possible +protocols are: +.BR ether , +.BR fddi , +.BR tr , +.BR wlan , +.BR ip , +.BR ip6 , +.BR arp , +.BR rarp , +.BR decnet , +.BR sctp , +.B tcp +and +.BR udp . +E.g., `\fBether src\fP foo', `\fBarp net\fP 128.3', `\fBtcp port\fP 21', +`\fBudp portrange\fP 7000-7009', `\fBwlan addr2\fP 0:2:3:4:5:6'. +If there is no +.I proto +qualifier, all protocols consistent with the type are assumed. +E.g., `\fBsrc\fP foo' means `\fB(ip6 or ip or arp or rarp) src\fP foo', +`\fBnet\fP bar' means `\fB(ip or arp or rarp) net\fP bar' and +`\fBport\fP 53' means `\fB(tcp or udp or sctp) port\fP 53' +(note that these examples use invalid syntax to illustrate the principle). +.LP +[\fBfddi\fP is actually an alias for \fBether\fP; the parser treats them +identically as meaning ``the data link level used on the specified +network interface''. FDDI headers contain Ethernet-like source +and destination addresses, and often contain Ethernet-like packet +types, so you can filter on these FDDI fields just as with the +analogous Ethernet fields. +FDDI headers also contain other fields, +but you cannot name them explicitly in a filter expression. +.LP +Similarly, \fBtr\fP and \fBwlan\fP are aliases for \fBether\fP; the previous +paragraph's statements about FDDI headers also apply to Token Ring +and 802.11 wireless LAN headers. For 802.11 headers, the destination +address is the DA field and the source address is the SA field; the +BSSID, RA, and TA fields aren't tested.] +.LP +In addition to the above, there are some special `primitive' keywords +that don't follow the pattern: +.BR gateway , +.BR broadcast , +.BR less , +.B greater +and arithmetic expressions. +All of these are described below. +.LP +More complex filter expressions are built up by using the words +.BR and , +.B or +and +.B not +(or equivalently: `\fB&&\fP', `\fB||\fP' and `\fB!\fP' respectively) +to combine primitives. +E.g., `\fBhost\fP foo \fBand not port\fP ftp \fBand not port\fP ftp-data'. +To save typing, identical qualifier lists can be omitted. +E.g., +`\fBtcp dst port\fP ftp \fBor\fP ftp-data \fBor\fP domain' is exactly the same as +`\fBtcp dst port\fP ftp \fBor tcp dst port\fP ftp-data \fBor tcp dst port\fP domain'. +.LP +Allowable primitives are: +.IP "\fBdst host \fIhostnameaddr\fR" +True if the IPv4/v6 destination field of the packet is \fIhostnameaddr\fP, +which may be either an address or a name. +.IP "\fBsrc host \fIhostnameaddr\fR" +True if the IPv4/v6 source field of the packet is \fIhostnameaddr\fP. +.IP "\fBhost \fIhostnameaddr\fP" +True if either the IPv4/v6 source or destination of the packet is \fIhostnameaddr\fP. +.IP +Any of the above host expressions can be prepended with the keywords, +\fBip\fP, \fBarp\fP, \fBrarp\fP, or \fBip6\fP as in: +.in +.5i +.nf +\fBip host \fIhostnameaddr\fR +.fi +.in -.5i +which is equivalent to: +.in +.5i +.nf +\fBether proto \\\fRip \fBand host \fIhostnameaddr\fR +.fi +.in -.5i +If \fIhostnameaddr\fR is a name with multiple IPv4/v6 addresses, each address will +be checked for a match. +.IP "\fBether dst \fIethernameaddr\fP" +True if the Ethernet destination address is \fIethernameaddr\fP. +\fIethernameaddr\fP +may be either a name from /etc/ethers or a numerical MAC address of the +form "xx:xx:xx:xx:xx:xx", "xx.xx.xx.xx.xx.xx", "xx-xx-xx-xx-xx-xx", +"xxxx.xxxx.xxxx", "xxxxxxxxxxxx", or various mixes of ':', '.', and '-', +where each "x" is a hex digit (0-9, a-f, or A-F). +.IP "\fBether src \fIethernameaddr\fP" +True if the Ethernet source address is \fIethernameaddr\fP. +.IP "\fBether host \fIethernameaddr\fP" +True if either the Ethernet source or destination address is \fIethernameaddr\fP. +.IP "\fBgateway\fP \fIhost\fP" +True if the packet used \fIhost\fP as a gateway. +I.e., the Ethernet +source or destination address was \fIhost\fP but neither the IP source +nor the IP destination was \fIhost\fP. +\fIHost\fP must be a name and +must be found both by the machine's host-name-to-IP-address resolution +mechanisms (host name file, DNS, NIS, etc.) and by the machine's +host-name-to-Ethernet-address resolution mechanism (/etc/ethers, etc.). +(An equivalent expression is +.in +.5i +.nf +\fBether host \fIethernameaddr \fBand not host \fIhostnameaddr\fR +.fi +.in -.5i +which can be used with either names or numbers for \fIhostnameaddr / ethernameaddr\fP.) +This syntax does not work in IPv6-enabled configuration at this moment. +.IP "\fBdst net \fInetnameaddr\fR" +True if the IPv4/v6 destination address of the packet has a network +number of \fInetnameaddr\fP. +\fINet\fP may be either a name from the networks database +(/etc/networks, etc.) or a network number. +An IPv4 network number can be written as a dotted quad (e.g., 192.168.1.0), +dotted triple (e.g., 192.168.1), dotted pair (e.g, 172.16), or single +number (e.g., 10); the netmask is 255.255.255.255 for a dotted quad +(which means that it's really a host match), 255.255.255.0 for a dotted +triple, 255.255.0.0 for a dotted pair, or 255.0.0.0 for a single number. +An IPv6 network number must be written out fully; the netmask is +ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, so IPv6 "network" matches are really always +host matches, and a network match requires a netmask length. +.IP "\fBsrc net \fInetnameaddr\fR" +True if the IPv4/v6 source address of the packet has a network +number of \fInetnameaddr\fP. +.IP "\fBnet \fInetnameaddr\fR" +True if either the IPv4/v6 source or destination address of the packet has a network +number of \fInetnameaddr\fP. +.IP "\fBnet \fInetaddr\fR \fBmask \fInetmask\fR" +True if the IPv4 address matches \fInetaddr\fR with the specific \fInetmask\fR. +May be qualified with \fBsrc\fR or \fBdst\fR. +Note that this syntax is not valid for IPv6 \fInetaddr\fR. +.IP "\fBnet \fInetaddr\fR/\fIlen\fR" +True if the IPv4/v6 address matches \fInetaddr\fR with a netmask \fIlen\fR +bits wide. +May be qualified with \fBsrc\fR or \fBdst\fR. +.IP "\fBdst port \fIportnamenum\fR" +True if the packet is IPv4/v6 TCP, UDP or SCTP and has a +destination port value of \fIportnamenum\fP. +The \fIportnamenum\fP can be a number or a name used in /etc/services (see +.BR tcp (4P) +and +.BR udp (4P)). +If a name is used, both the port +number and protocol are checked. +If a number or ambiguous name is used, +only the port number is checked (e.g., `\fBdst port\fR 513' will print both +tcp/login traffic and udp/who traffic, and `\fBport\fR domain' will print +both tcp/domain and udp/domain traffic). +.IP "\fBsrc port \fIportnamenum\fR" +True if the packet has a source port value of \fIportnamenum\fP. +.IP "\fBport \fIportnamenum\fR" +True if either the source or destination port of the packet is \fIportnamenum\fP. +.IP "\fBdst portrange \fIportnamenum1-portnamenum2\fR" +True if the packet is IPv4/v6 TCP, UDP or SCTP and has a +destination port value between \fIportnamenum1\fP and \fIportnamenum2\fP (both inclusive). +.I portnamenum1 +and +.I portnamenum2 +are interpreted in the same fashion as the +.I portnamenum +parameter for +.BR port . +.IP "\fBsrc portrange \fIportnamenum1-portnamenum2\fR" +True if the packet has a source port value between \fIportnamenum1\fP and +\fIportnamenum2\fP (both inclusive). +.IP "\fBportrange \fIportnamenum1-portnamenum2\fR" +True if either the source or destination port of the packet is between +\fIportnamenum1\fP and \fIportnamenum2\fP (both inclusive). +.IP +Any of the above port or port range expressions can be prepended with +the keywords, \fBtcp\fP, \fBudp\fP or \fBsctp\fP, as in: +.in +.5i +.nf +\fBtcp src port \fIportnamenum\fR +.fi +.in -.5i +which matches only TCP packets whose source port is \fIportnamenum\fP. +.IP "\fBless \fIlength\fR" +True if the packet has a length less than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen <= \fIlength\fP +.fi +.in -.5i +.IP "\fBgreater \fIlength\fR" +True if the packet has a length greater than or equal to \fIlength\fP. +This is equivalent to: +.in +.5i +.nf +\fBlen >= \fIlength\fP +.fi +.in -.5i +.IP "\fBip proto \fIprotocol\fR" +True if the packet is an IPv4 packet (see +.BR ip (4P)) +of protocol type \fIprotocol\fP. +\fIProtocol\fP can be a number or one of the names recognized by +.BR getprotobyname (3) +(as in e.g. `\fBgetent\fR(1) protocols'), typically from an entry in +.IR \%/etc/protocols , +for example: +.BR ah , +.BR esp , +.B eigrp +(only in Linux, FreeBSD, NetBSD, DragonFly BSD, and macOS), +.BR icmp , +.BR igmp , +.B igrp +(only in OpenBSD), +.BR pim , +.BR sctp , +.BR tcp , +.B udp +or +.BR vrrp . +Note that most of these example identifiers +are also keywords and must be escaped via backslash (\\). +Note that this primitive does not chase the protocol header chain. +.IP "\fBicmp\fR" +Abbreviation for: +.in +.5i +.nf +\fBip proto\fR 1 +.fi +.in -.5i +.IP "\fBip6 proto \fIprotocol\fR" +True if the packet is an IPv6 packet of protocol type \fIprotocol\fP. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fR.) +Note that the IPv6 variant of ICMP uses a different protocol number, named +.B \%ipv6-icmp +in AIX, FreeBSD, illumos, Linux, macOS, NetBSD, OpenBSD, Solaris and Windows. +Note that this primitive does not chase the protocol header chain. +.IP "\fBicmp6\fR" +Abbreviation for: +.in +.5i +.nf +\fBip6 proto\fR 58 +.fi +.in -.5i +.IP "\fBproto \fIprotocol\fR" +True if the packet is an IPv4 or IPv6 packet of protocol type +\fIprotocol\fP. (See `\fBip proto\fP' above for the meaning of +\fIprotocol\fP.) Note that this primitive does not chase the protocol +header chain. +.IP "\fBah\fR, \fBesp\fR, \fBpim\fR, \fBsctp\fR, \fBtcp\fR, \fBudp\fR" +Abbreviations for: +.in +.5i +.nf +\fBproto \\\fIprotocol\fR +.fi +.in -.5i +where \fIprotocol\fR is one of the above protocols. +.IP "\fBip6 protochain \fIprotocol\fR" +True if the packet is IPv6 packet, +and contains protocol header with type \fIprotocol\fR +in its protocol header chain. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fP.) +For example, +.in +.5i +.nf +\fBip6 protochain\fR 6 +.fi +.in -.5i +matches any IPv6 packet with TCP protocol header in the protocol header chain. +The packet may contain, for example, +authentication header, routing header, or hop-by-hop option header, +between IPv6 header and TCP header. +The BPF code emitted by this primitive is complex and +cannot be optimized by the BPF optimizer code, and is not supported by +filter engines in the kernel, so this can be somewhat slow, and may +cause more packets to be dropped. +.IP "\fBip protochain \fIprotocol\fR" +Equivalent to \fBip6 protochain \fIprotocol\fR, but this is for IPv4. +(See `\fBip proto\fP' above for the meaning of \fIprotocol\fP.) +.IP "\fBprotochain \fIprotocol\fR" +True if the packet is an IPv4 or IPv6 packet of protocol type +\fIprotocol\fP. (See `\fBip proto\fP' above for the meaning of +\fIprotocol\fP.) Note that this primitive chases the protocol +header chain. +.IP "\fBether broadcast\fR" +True if the packet is an Ethernet broadcast packet. +The \fBether\fP +keyword is optional. +.IP "\fBip broadcast\fR" +True if the packet is an IPv4 broadcast packet. +It checks for both the all-zeroes and all-ones broadcast conventions, +and looks up the subnet mask on the interface on which the capture is +being done. +.IP +If the subnet mask of the interface on which the capture is being done +is not available, either because the interface on which capture is being +done has no netmask or because the capture is being done on the Linux +"any" interface, which can capture on more than one interface, this +check will not work correctly. +.IP "\fBether multicast\fR" +True if the packet is an Ethernet multicast packet. +The \fBether\fP +keyword is optional. +This is shorthand for `\fBether[\fP0\fB] & \fP1\fB != \fP0'. +.IP "\fBip multicast\fR" +True if the packet is an IPv4 multicast packet. +.IP "\fBip6 multicast\fR" +True if the packet is an IPv6 multicast packet. +.IP "\fBether proto \fIprotocol\fR" +True if the packet is of ether type \fIprotocol\fR. +\fIProtocol\fP can be a number or one of the names +\fBaarp\fP, \fBarp\fP, \fBatalk\fP, \fBdecnet\fP, \fBip\fP, \fBip6\fP, +\fBipx\fP, \fBiso\fP, \fBlat\fP, \fBloopback\fP, \fBmopdl\fP, \fBmoprc\fP, \fBnetbeui\fP, +\fBrarp\fP, \fBsca\fP or \fBstp\fP. +Note these identifiers (except \fBloopback\fP) are also keywords +and must be escaped via backslash (\\). +.IP +[In the case of FDDI (e.g., `\fBfddi proto \\arp\fR'), Token Ring +(e.g., `\fBtr proto \\arp\fR'), and IEEE 802.11 wireless LANs (e.g., +`\fBwlan proto \\arp\fR'), for most of those protocols, the +protocol identification comes from the 802.2 Logical Link Control (LLC) +header, which is usually layered on top of the FDDI, Token Ring, or +802.11 header. +.IP +When filtering for most protocol identifiers on FDDI, Token Ring, or +802.11, the filter checks only the protocol ID field of an LLC header +in so-called SNAP format with an Organizational Unit Identifier (OUI) of +0x000000, for encapsulated Ethernet; it doesn't check whether the packet +is in SNAP format with an OUI of 0x000000. +The exceptions are: +.RS +.TP +\fBiso\fP +the filter checks the DSAP (Destination Service Access Point) and +SSAP (Source Service Access Point) fields of the LLC header; +.TP +\fBstp\fP and \fBnetbeui\fP +the filter checks the DSAP of the LLC header; +.TP +\fBatalk\fP +the filter checks for a SNAP-format packet with an OUI of 0x080007 +and the AppleTalk etype. +.RE +.IP +In the case of Ethernet, the filter checks the Ethernet type field +for most of those protocols. The exceptions are: +.RS +.TP +\fBiso\fP, \fBstp\fP, and \fBnetbeui\fP +the filter checks for an 802.3 frame and then checks the LLC header as +it does for FDDI, Token Ring, and 802.11; +.TP +\fBatalk\fP +the filter checks both for the AppleTalk etype in an Ethernet frame and +for a SNAP-format packet as it does for FDDI, Token Ring, and 802.11; +.TP +\fBaarp\fP +the filter checks for the AppleTalk ARP etype in either an Ethernet +frame or an 802.2 SNAP frame with an OUI of 0x000000; +.TP +\fBipx\fP +the filter checks for the IPX etype in an Ethernet frame, the IPX +DSAP in the LLC header, the 802.3-with-no-LLC-header encapsulation of +IPX, and the IPX etype in a SNAP frame. +.RE +.IP "\fBip\fR, \fBip6\fR, \fBarp\fR, \fBrarp\fR, \fBatalk\fR, \fBaarp\fR, \fBdecnet\fR, \fBiso\fR, \fBstp\fR, \fBipx\fR, \fBnetbeui\fP" +Abbreviations for: +.in +.5i +.nf +\fBether proto \\\fIprotocol\fR +.fi +.in -.5i +where \fIprotocol\fR is one of the above protocols. +.IP "\fBlat\fR, \fBmoprc\fR, \fBmopdl\fR" +Abbreviations for: +.in +.5i +.nf +\fBether proto \\\fIprotocol\fR +.fi +.in -.5i +where \fIprotocol\fR is one of the above protocols. +Note that not all applications using +.BR pcap (3PCAP) +currently know how to parse these protocols. +.IP "\fBdecnet src \fIdecnetaddr\fR" +True if the DECnet source address is +.IR decnetaddr , +which may be an address of the form ``10.123'', or a DECnet host +name. +[DECnet host name support is only available on ULTRIX systems +that are configured to run DECnet.] +.IP "\fBdecnet dst \fIdecnetaddr\fR" +True if the DECnet destination address is +.IR decnetaddr . +.IP "\fBdecnet host \fIdecnetaddr\fR" +True if either the DECnet source or destination address is +.IR decnetaddr . +.IP \fBllc\fP +True if the packet has an 802.2 LLC header. This includes: +.IP +Ethernet packets with a length field rather than a type field that +aren't raw NetWare-over-802.3 packets; +.IP +IEEE 802.11 data packets; +.IP +Token Ring packets (no check is done for LLC frames); +.IP +FDDI packets (no check is done for LLC frames); +.IP +LLC-encapsulated ATM packets, for SunATM on Solaris. +.IP "\fBllc\fP \fItype\fR" +True if the packet has an 802.2 LLC header and has the specified +.IR type . +.I type +can be one of: +.RS +.TP +\fBi\fR +Information (I) PDUs +.TP +\fBs\fR +Supervisory (S) PDUs +.TP +\fBu\fR +Unnumbered (U) PDUs +.TP +\fBrr\fR +Receiver Ready (RR) S PDUs +.TP +\fBrnr\fR +Receiver Not Ready (RNR) S PDUs +.TP +\fBrej\fR +Reject (REJ) S PDUs +.TP +\fBui\fR +Unnumbered Information (UI) U PDUs +.TP +\fBua\fR +Unnumbered Acknowledgment (UA) U PDUs +.TP +\fBdisc\fR +Disconnect (DISC) U PDUs +.TP +\fBsabme\fR +Set Asynchronous Balanced Mode Extended (SABME) U PDUs +.TP +\fBtest\fR +Test (TEST) U PDUs +.TP +\fBxid\fR +Exchange Identification (XID) U PDUs +.TP +\fBfrmr\fR +Frame Reject (FRMR) U PDUs +.RE +.IP \fBinbound\fP +Packet was received by the host performing the capture rather than being +sent by that host. This is only supported for certain link-layer types, +such as SLIP and the ``cooked'' Linux capture mode +used for the ``any'' device and for some other device types. +.IP \fBoutbound\fP +Packet was sent by the host performing the capture rather than being +received by that host. This is only supported for certain link-layer types, +such as SLIP and the ``cooked'' Linux capture mode +used for the ``any'' device and for some other device types. +.IP "\fBifindex \fIinterface_index\fR" +True if the packet was logged via the specified interface (applies only to +packets logged by the Linux "any" cooked v2 interface). +.IP "\fBifname \fIinterface\fR" +True if the packet was logged as coming from the specified interface (applies +only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBon \fIinterface\fR" +Synonymous with the +.B ifname +modifier. +.IP "\fBrnr \fInum\fR" +True if the packet was logged as matching the specified PF rule number +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBrulenum \fInum\fR" +Synonymous with the +.B rnr +modifier. +.IP "\fBreason \fIcode\fR" +True if the packet was logged with the specified PF reason code. The known +codes are: +.BR \%match , +.BR \%bad-offset , +.BR \%fragment , +.BR \%short , +.BR \%normalize , +and +.B memory +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBrset \fIname\fR" +True if the packet was logged as matching the specified PF ruleset +name of an anchored ruleset (applies only to packets logged by OpenBSD's +or FreeBSD's +.BR pf (4)). +.IP "\fBruleset \fIname\fR" +Synonymous with the +.B rset +modifier. +.IP "\fBsrnr \fInum\fR" +True if the packet was logged as matching the specified PF rule number +of an anchored ruleset (applies only to packets logged by OpenBSD's or +FreeBSD's +.BR pf (4)). +.IP "\fBsubrulenum \fInum\fR" +Synonymous with the +.B srnr +modifier. +.IP "\fBaction \fIact\fR" +True if PF took the specified action when the packet was logged. Known actions +are: +.B pass +and +.B block +and, with later versions of +.BR pf (4), +.BR nat , +.BR rdr , +.B binat +and +.B scrub +(applies only to packets logged by OpenBSD's or FreeBSD's +.BR pf (4)). +.IP "\fBwlan ra \fIehost\fR" +True if the IEEE 802.11 RA is +.IR ehost . +The RA field is used in all frames except for management frames. +.IP "\fBwlan ta \fIehost\fR" +True if the IEEE 802.11 TA is +.IR ehost . +The TA field is used in all frames except for management frames and +CTS (Clear To Send) and ACK (Acknowledgment) control frames. +.IP "\fBwlan addr1 \fIehost\fR" +True if the first IEEE 802.11 address is +.IR ehost . +.IP "\fBwlan addr2 \fIehost\fR" +True if the second IEEE 802.11 address, if present, is +.IR ehost . +The second address field is used in all frames except for CTS (Clear To +Send) and ACK (Acknowledgment) control frames. +.IP "\fBwlan addr3 \fIehost\fR" +True if the third IEEE 802.11 address, if present, is +.IR ehost . +The third address field is used in management and data frames, but not +in control frames. +.IP "\fBwlan addr4 \fIehost\fR" +True if the fourth IEEE 802.11 address, if present, is +.IR ehost . +The fourth address field is only used for +WDS (Wireless Distribution System) frames. +.IP "\fBtype \fIwlan_type\fR" +True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR. +Valid \fIwlan_type\fRs are: +\fBmgt\fP, +\fBctl\fP +and \fBdata\fP. +.IP "\fBtype \fIwlan_type \fBsubtype \fIwlan_subtype\fR" +True if the IEEE 802.11 frame type matches the specified \fIwlan_type\fR +and frame subtype matches the specified \fIwlan_subtype\fR. +.IP +If the specified \fIwlan_type\fR is \fBmgt\fP, +then valid \fIwlan_subtype\fRs are: +\fBassoc-req\fP, +\fBassoc-resp\fP, +\fBreassoc-req\fP, +\fBreassoc-resp\fP, +\fBprobe-req\fP, +\fBprobe-resp\fP, +\fBbeacon\fP, +\fBatim\fP, +\fBdisassoc\fP, +\fBauth\fP and +\fBdeauth\fP. +.IP +If the specified \fIwlan_type\fR is \fBctl\fP, +then valid \fIwlan_subtype\fRs are: +\fBps-poll\fP, +\fBrts\fP, +\fBcts\fP, +\fBack\fP, +\fBcf-end\fP and +\fBcf-end-ack\fP. +.IP +If the specified \fIwlan_type\fR is \fBdata\fP, +then valid \fIwlan_subtype\fRs are: +.BR \%data , +.BR \%data-cf-ack , +.BR \%data-cf-poll , +.BR \%data-cf-ack-poll , +.BR \%null , +.BR \%cf-ack , +.BR \%cf-poll , +.BR \%cf-ack-poll , +.BR \%qos-data , +.BR \%qos-data-cf-ack , +.BR \%qos-data-cf-poll , +.BR \%qos-data-cf-ack-poll , +.BR \%qos , +.B \%qos-cf-poll +and +.BR \%qos-cf-ack-poll . +.IP "\fBsubtype \fIwlan_subtype\fR" +True if the IEEE 802.11 frame subtype matches the specified \fIwlan_subtype\fR +and frame has the type to which the specified \fIwlan_subtype\fR belongs. +.IP "\fBdir \fIdirection\fR" +True if the IEEE 802.11 frame direction matches the specified +.IR direction . +Valid directions are: +.BR nods , +.BR tods , +.BR fromds , +.BR dstods , +or a numeric value. +.IP "\fBvlan \fI[vlan_id]\fR" +True if the packet is an IEEE 802.1Q VLAN packet. +If the optional \fIvlan_id\fR is specified, only true if the packet has the specified +\fIvlan_id\fR. +Note that the first \fBvlan\fR keyword encountered in an expression +changes the decoding offsets for the remainder of the expression on +the assumption that the packet is a VLAN packet. The `\fBvlan +\fI[vlan_id]\fR` keyword may be used more than once, to filter on VLAN +hierarchies. Each use of that keyword increments the filter offsets +by 4. +.IP +For example: +.in +.5i +.nf +\fBvlan\fP 100 \fB&& vlan\fR 200 +.fi +.in -.5i +filters on VLAN 200 encapsulated within VLAN 100, and +.in +.5i +.nf +\fBvlan && vlan \fP300 \fB&& ip\fR +.fi +.in -.5i +filters IPv4 protocol encapsulated in VLAN 300 encapsulated within any +higher order VLAN. +.IP "\fBmpls \fI[label_num]\fR" +True if the packet is an MPLS packet. +If the optional \fIlabel_num\fR is specified, only true if the packet has the specified +\fIlabel_num\fR. +Note that the first \fBmpls\fR keyword encountered in an expression +changes the decoding offsets for the remainder of the expression on +the assumption that the packet is a MPLS-encapsulated IP packet. The +`\fBmpls \fI[label_num]\fR` keyword may be used more than once, to +filter on MPLS hierarchies. Each use of that keyword increments the +filter offsets by 4. +.IP +For example: +.in +.5i +.nf +\fBmpls\fP 100000 \fB&& mpls\fR 1024 +.fi +.in -.5i +filters packets with an outer label of 100000 and an inner label of +1024, and +.in +.5i +.nf +\fBmpls && mpls\fP 1024 \fB&& host\fR 192.9.200.1 +.fi +.in -.5i +filters packets to or from 192.9.200.1 with an inner label of 1024 and +any outer label. +.IP \fBpppoed\fP +True if the packet is a PPP-over-Ethernet Discovery packet (Ethernet +type 0x8863). +.IP "\fBpppoes \fI[session_id]\fR" +True if the packet is a PPP-over-Ethernet Session packet (Ethernet +type 0x8864). +If the optional \fIsession_id\fR is specified, only true if the packet has the specified +\fIsession_id\fR. +Note that the first \fBpppoes\fR keyword encountered in an expression +changes the decoding offsets for the remainder of the expression on +the assumption that the packet is a PPPoE session packet. +.IP +For example: +.in +.5i +.nf +\fBpppoes\fP 0x27 \fB&& ip\fR +.fi +.in -.5i +filters IPv4 protocol encapsulated in PPPoE session id 0x27. +.IP "\fBgeneve \fI[vni]\fR" +True if the packet is a Geneve packet (UDP port 6081). If the optional \fIvni\fR +is specified, only true if the packet has the specified \fIvni\fR. +Note that when the \fBgeneve\fR keyword is encountered in +an expression, it changes the decoding offsets for the remainder of +the expression on the assumption that the packet is a Geneve packet. +.IP +For example: +.in +.5i +.nf +\fBgeneve\fP 0xb \fB&& ip\fR +.fi +.in -.5i +filters IPv4 protocol encapsulated in Geneve with VNI 0xb. This will +match both IPv4 directly encapsulated in Geneve as well as IPv4 contained +inside an Ethernet frame. +.IP "\fBiso proto \fIprotocol\fR" +True if the packet is an OSI packet of protocol type \fIprotocol\fP. +\fIProtocol\fP can be a number or one of the names +\fBclnp\fP, \fBesis\fP, or \fBisis\fP. +.IP "\fBclnp\fR, \fBesis\fR, \fBisis\fR" +Abbreviations for: +.in +.5i +.nf +\fBiso proto \\\fIprotocol\fR +.fi +.in -.5i +where \fIprotocol\fR is one of the above protocols. +.IP "\fBl1\fR, \fBl2\fR, \fBiih\fR, \fBlsp\fR, \fBsnp\fR, \fBcsnp\fR, \fBpsnp\fR" +Abbreviations for IS-IS PDU types. +.IP "\fBvpi\fP \fIn\fR" +True if the packet is an ATM packet, for SunATM on Solaris, with a +virtual path identifier of +.IR n . +.IP "\fBvci\fP \fIn\fR" +True if the packet is an ATM packet, for SunATM on Solaris, with a +virtual channel identifier of +.IR n . +.IP \fBlane\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +an ATM LANE packet. +Note that the first \fBlane\fR keyword encountered in an expression +changes the tests done in the remainder of the expression +on the assumption that the packet is either a LANE emulated Ethernet +packet or a LANE LE Control packet. If \fBlane\fR isn't specified, the +tests are done under the assumption that the packet is an +LLC-encapsulated packet. +.IP \fBoamf4s\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment OAM F4 flow cell (VPI=0 & VCI=3). +.IP \fBoamf4e\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +an end-to-end OAM F4 flow cell (VPI=0 & VCI=4). +.IP \fBoamf4\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). +.IP \fBoam\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +a segment or end-to-end OAM F4 flow cell (VPI=0 & (VCI=3 | VCI=4)). +.IP \fBmetac\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a meta signaling circuit (VPI=0 & VCI=1). +.IP \fBbcc\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a broadcast signaling circuit (VPI=0 & VCI=2). +.IP \fBsc\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a signaling circuit (VPI=0 & VCI=5). +.IP \fBilmic\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on an ILMI circuit (VPI=0 & VCI=16). +.IP \fBconnectmsg\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, +Connect Ack, Release, or Release Done message. +.IP \fBmetaconnect\fP +True if the packet is an ATM packet, for SunATM on Solaris, and is +on a meta signaling circuit and is a Q.2931 Setup, Call Proceeding, Connect, +Release, or Release Done message. +.IP "\fIexpr1 relop expr2\fR" +True if the relation holds. \fIRelop\fR is one of +.RB { > , +.BR < , +.BR >= , +.BR <= , +.BR = , +.BR == , +.BR != } +(where +.B = +means the same as +.BR == ). +Each of \fIexpr1\fR and \fIexpr2\fR is an arithmetic expression composed of +integer constants (expressed in standard C syntax), the normal binary operators +.RB { + , +.BR - , +.BR * , +.BR / , +.BR % , +.BR & , +.BR | , +.BR ^ , +.BR << , +.BR >> }, +a length operator, and special packet data +accessors. Note that all comparisons are unsigned, so that, for example, +0x80000000 and 0xffffffff are > 0. +.IP +The +.B % +and +.B ^ +operators are currently only supported for filtering in the kernel on +particular operating systems (for example: FreeBSD, Linux with 3.7 and later +kernels, NetBSD); on all other systems (for example: AIX, illumos, Solaris, +OpenBSD), if +those operators are used, filtering will be done in user mode, which +will increase the overhead of capturing packets and may cause more +packets to be dropped. +.IP +The length operator, indicated by the keyword \fBlen\fP, gives the +length of the packet. +.IP +To access data inside the packet, use the following syntax: +.in +.5i +.nf +\fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR +.fi +.in -.5i +.I Proto +is one of +.BR arp , +.BR atalk , +.BR carp , +.BR decnet , +.BR ether , +.BR fddi , +.BR icmp , +.BR icmp6 , +.BR igmp , +.BR igrp , +.BR ip , +.BR ip6 , +.BR lat , +.BR link , +.BR mopdl , +.BR moprc , +.BR pim , +.BR ppp , +.BR radio , +.BR rarp , +.BR sca , +.BR sctp , +.BR slip , +.BR tcp , +.BR tr , +.BR udp , +.B vrrp +or +.BR wlan , +and +indicates the protocol layer for the index operation. +.RB ( ether , +.BR fddi , +.BR link , +.BR ppp , +.BR slip , +.B tr +and +.BR wlan +all refer to the +link layer. \fBradio\fR refers to the "radio header" added to some +802.11 captures.) +Note that \fBtcp\fR, \fBudp\fR and other upper-layer protocol types only +apply to IPv4, not IPv6 (this will be fixed in the future). +The byte offset, relative to the indicated protocol layer, is +given by \fIexpr\fR. +\fISize\fR is optional and indicates the number of bytes in the +field of interest; it can be either one, two, or four, and defaults to one. + +For example, `\fBether[\fP0\fB] &\fP 1 \fB!=\fP 0' catches all multicast traffic. +The expression `\fBip[\fP0\fB] &\fP 0xf \fB!=\fP 5' +catches all IPv4 packets with options. +The expression +`\fBip[\fP6:2\fB] &\fP 0x1fff \fB=\fP 0' +catches only unfragmented IPv4 datagrams and frag zero of fragmented +IPv4 datagrams. +This check is implicitly applied to the \fBtcp\fP and \fBudp\fP +index operations. +For instance, \fBtcp[\fP0\fB]\fP always means the first +byte of the TCP \fIheader\fP, and never means the first byte of an +intervening fragment. +.IP +Some offsets and field values may be expressed as names rather than +as numeric values. +The following protocol header field offsets are +available: \fBicmptype\fP (ICMP type field), \fBicmp6type\fP (ICMPv6 type field), +\fBicmpcode\fP (ICMP code field), \fBicmp6code\fP (ICMPv6 code field) and +\fBtcpflags\fP (TCP flags field). +.IP +The following ICMP type field values are available: +.BR \%icmp-echoreply , +.BR \%icmp-unreach , +.BR \%icmp-sourcequench , +.BR \%icmp-redirect , +.BR \%icmp-echo , +.BR \%icmp-routeradvert , +.BR \%icmp-routersolicit , +.BR \%icmp-timxceed , +.BR \%icmp-paramprob , +.BR \%icmp-tstamp , +.BR \%icmp-tstampreply , +.BR \%icmp-ireq , +.BR \%icmp-ireqreply , +.BR \%icmp-maskreq , +.BR \%icmp-maskreply . +.IP +The following ICMPv6 type field values are available: +.BR \%icmp6-destinationunreach , +.BR \%icmp6-packettoobig , +.BR \%icmp6-timeexceeded , +.BR \%icmp6-parameterproblem , +.BR \%icmp6-echo , +.BR \%icmp6-echoreply , +.BR \%icmp6-multicastlistenerquery , +.BR \%icmp6-multicastlistenerreportv1 , +.BR \%icmp6-multicastlistenerdone , +.BR \%icmp6-routersolicit , +.BR \%icmp6-routeradvert , +.BR \%icmp6-neighborsolicit , +.BR \%icmp6-neighboradvert , +.BR \%icmp6-redirect , +.BR \%icmp6-routerrenum , +.BR \%icmp6-nodeinformationquery , +.BR \%icmp6-nodeinformationresponse , +.BR \%icmp6-ineighbordiscoverysolicit , +.BR \%icmp6-ineighbordiscoveryadvert , +.BR \%icmp6-multicastlistenerreportv2 , +.BR \%icmp6-homeagentdiscoveryrequest , +.BR \%icmp6-homeagentdiscoveryreply , +.BR \%icmp6-mobileprefixsolicit , +.BR \%icmp6-mobileprefixadvert , +.BR \%icmp6-certpathsolicit , +.BR \%icmp6-certpathadvert , +.BR \%icmp6-multicastrouteradvert , +.BR \%icmp6-multicastroutersolicit , +.BR \%icmp6-multicastrouterterm . +.IP +The following TCP flags field values are available: \fBtcp-fin\fP, +\fBtcp-syn\fP, \fBtcp-rst\fP, \fBtcp-push\fP, +\fBtcp-ack\fP, \fBtcp-urg\fP, \fBtcp-ece\fP, +\fBtcp-cwr\fP. +.LP +Primitives may be combined using: +.IP +A parenthesized group of primitives and operators. +.IP +Negation (`\fB!\fP' or `\fBnot\fP'). +.IP +Concatenation (`\fB&&\fP' or `\fBand\fP'). +.IP +Alternation (`\fB||\fP' or `\fBor\fP'). +.LP +Negation has the highest precedence. +Alternation and concatenation have equal precedence and associate +left to right. +.LP +If an identifier is given without a keyword, the most recent keyword +is assumed. +For example, +.in +.5i +.nf +\fBnot host\fP vs \fBand\fR ace +.fi +.in -.5i +is short for +.in +.5i +.nf +\fBnot host\fP vs \fBand host\fR ace +.fi +.in -.5i +which should not be confused with +.in +.5i +.nf +\fBnot (host \fPvs\fB or \fPace\fB)\fR +.fi +.in -.5i +.SH EXAMPLES +.LP +To select all packets arriving at or departing from `sundown': +.RS +.nf +\fBhost\fP sundown +.fi +.RE +.LP +To select traffic between `helios' and either `hot' or `ace': +.RS +.nf +\fBhost\fP helios \fBand (\fPhot \fBor\fP ace\fB)\fP +.fi +.RE +.LP +To select all IPv4 packets between `ace' and any host except `helios': +.RS +.nf +\fBip host\fP ace \fBand not\fP helios +.fi +.RE +.LP +To select all traffic between local hosts and hosts at Berkeley: +.RS +.nf +\fBnet\fP ucb-ether +.fi +.RE +.LP +To select all FTP traffic through Internet gateway `snup': +.RS +.nf +\fBgateway\fP snup \fBand (port\fP ftp \fBor\fP ftp-data\fB)\fP +.fi +.RE +.LP +To select IPv4 traffic neither sourced from nor destined for local hosts +(if you gateway to one other net, this stuff should never make it +onto your local net). +.RS +.nf +\fBip and not net \fPlocalnet +.fi +.RE +.LP +To select the start and end packets (the SYN and FIN packets) of each +TCP conversation that involves a non-local host. +.RS +.nf +\fBtcp[tcpflags] & (tcp-syn|tcp-fin) !=\fP 0 \fBand not src and dst net\fP localnet +.fi +.RE +.LP +To select the TCP packets with flags RST and ACK both set. +(i.e. select only the RST and ACK flags in the flags field, and if the result +is "RST and ACK both set", match) +.RS +.nf +.B +tcp[tcpflags] & (tcp-rst|tcp-ack) == (tcp-rst|tcp-ack) +.fi +.RE +.LP +To select all IPv4 HTTP packets to and from port 80, i.e. print only +packets that contain data, not, for example, SYN and FIN packets and +ACK-only packets. (IPv6 is left as an exercise for the reader.) +.RS +.nf +\fBtcp port\fP 80 \fBand (((ip[\fP2:2\fB] - ((ip[\fP0\fB]&\fP0xf\fB)<<\fP2\fB)) - ((tcp[\fP12\fB]&\fP0xf0\fB)>>\fP2\fB)) != \fP0\fB) +.fi +.RE +.LP +To select IPv4 packets longer than 576 bytes sent through gateway `snup': +.RS +.nf +\fBgateway\fP snup \fBand ip[\fP2:2\fB] >\fP 576 +.fi +.RE +.LP +To select IPv4 broadcast or multicast packets that were +.I not +sent via Ethernet broadcast or multicast: +.RS +.nf +\fBether[\fP0\fB] &\fP 1 \fB=\fP 0 \fBand ip[\fP16\fB] >=\fP 224 +.fi +.RE +.LP +To select all ICMP packets that are not echo requests/replies (i.e., not +ping packets): +.RS +.nf +.B +icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply +.B +icmp6[icmp6type] != icmp6-echo and icmp6[icmp6type] != icmp6-echoreply +.fi +.RE +.SH BACKWARD COMPATIBILITY +The ICMPv6 type code names, as well as the +.B tcp-ece +and +.B tcp-cwr +TCP flag names became available in libpcap 1.9.0. +.PP +The +.B geneve +keyword became available in libpcap 1.8.0. +.PP +The +.B ifindex +keyword became available in libpcap 1.10.0. +.SH SEE ALSO +.BR pcap (3PCAP) +.SH BUGS +To report a security issue please send an e-mail to \%security@tcpdump.org. +.LP +To report bugs and other problems, contribute patches, request a +feature, provide generic feedback etc please see the file +.I CONTRIBUTING.md +in the libpcap source tree root. +.LP +Filter expressions on fields other than those in Token Ring headers will +not correctly handle source-routed Token Ring packets. +.LP +Filter expressions on fields other than those in 802.11 headers will not +correctly handle 802.11 data packets with both To DS and From DS set. +.LP +`\fBip6 proto\fP' +should chase header chain, but at this moment it does not. +`\fBip6 protochain\fP' +is supplied for this behavior. For example, to match IPv6 fragments: +`\fBip6 protochain\fP 44' +.LP +Arithmetic expression against transport layer headers, like \fBtcp[0]\fP, +does not work against IPv6 packets. +It only looks at IPv4 packets. diff --git a/src/libpcap-1.10.5/pcap-haiku.c b/src/libpcap-1.10.5/pcap-haiku.c new file mode 100644 index 0000000000..6cb0e71a1f --- /dev/null +++ b/src/libpcap-1.10.5/pcap-haiku.c @@ -0,0 +1,504 @@ +/* + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * James Woodcock + */ + + +#include +#include "pcap-int.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +// IFT_TUN was renamed to IFT_TUNNEL in the master branch after R1/beta4 (the +// integer value didn't change). Even though IFT_TUN is a no-op in versions +// that define it, for the time being it is desirable to support compiling +// libpcap on versions with the old macro and using it on later versions that +// support tunnel interfaces. +#ifndef IFT_TUNNEL +#define IFT_TUNNEL IFT_TUN +#endif + +/* + * Private data for capturing on Haiku sockets. + */ +struct pcap_haiku { + struct pcap_stat stat; + int aux_socket; + struct ifreq ifreq; + // The original state of the promiscuous mode at the activation time, + // if the capture should be run in promiscuous mode. + int orig_promisc; +}; + + +static int +pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback, + u_char* userdata) +{ + // Receive a single packet + + u_char* buffer = (u_char*)handle->buffer; + ssize_t bytesReceived; + do { + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC, + NULL, NULL); + } while (bytesReceived < 0 && errno == B_INTERRUPTED); + + // The kernel does not implement timestamping of network packets, so + // doing it ASAP in userland is the best that can be done. + bigtime_t ts = real_time_clock_usecs(); + + if (bytesReceived < 0) { + if (errno == B_WOULD_BLOCK) { + // there is no packet for us + return 0; + } + + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "recvfrom"); + return PCAP_ERROR; + } + + struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; + // BPF is 32-bit, which is more than sufficient for any realistic + // packet size. + if (bytesReceived > UINT32_MAX) + goto drop; + // At this point, if the recvfrom() call populated its struct sockaddr + // and socklen_t arguments, it would be the right time to drop packets + // that have .sa_family not valid for the current DLT. But in the + // current master branch (hrev57588) this would erroneously drop some + // valid packets: recvfrom(), at least for tap mode tunnels, sets the + // address length to 0 for all incoming packets and sets .sa_len and + // .sa_family to 0 for packets that are broadcast or multicast. So it + // cannot be done yet, if there is a good reason to do it in the first + // place. + handlep->stat.ps_recv++; + + bpf_u_int32 wireLength = (bpf_u_int32)bytesReceived; + // As long as the buffer is large enough, the captured length is equal + // to the wire length, but let's get the lengths right anyway in case + // packets grow bigger or the buffer grows smaller in future and the + // MSG_TRUNC effect kicks in. + bpf_u_int32 captureLength = + wireLength <= handle->bufsize ? wireLength : handle->bufsize; + + // run the packet filter + if (handle->fcode.bf_insns) { + // NB: pcapint_filter() takes the wire length and the captured + // length, not the snapshot length of the pcap_t handle. + if (pcapint_filter(handle->fcode.bf_insns, buffer, wireLength, + captureLength) == 0) + goto drop; + } + + // fill in pcap_header + struct pcap_pkthdr header; + header.caplen = captureLength <= (bpf_u_int32)handle->snapshot ? + captureLength : + (bpf_u_int32)handle->snapshot; + header.len = wireLength; + header.ts.tv_usec = ts % 1000000; + header.ts.tv_sec = ts / 1000000; + + /* Call the user supplied callback function */ + callback(userdata, &header, buffer); + return 1; +drop: + handlep->stat.ps_drop++; + return 0; +} + + +static int +dgram_socket(const int af, char *errbuf) +{ + int ret = socket(af, SOCK_DGRAM, 0); + if (ret < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "socket"); + return PCAP_ERROR; + } + return ret; +} + + +static int +ioctl_ifreq(const int fd, const unsigned long op, const char *name, + struct ifreq *ifreq, char *errbuf) +{ + if (ioctl(fd, op, ifreq, sizeof(struct ifreq)) < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "%s", name); + return PCAP_ERROR; + } + return 0; +} + + +static int +get_promisc(pcap_t *handle) +{ + struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv; + // SIOCGIFFLAGS would work fine for AF_LINK too. + if (ioctl_ifreq(handlep->aux_socket, SIOCGIFFLAGS, "SIOCGIFFLAGS", + &handlep->ifreq, handle->errbuf) < 0) + return PCAP_ERROR; + return (handlep->ifreq.ifr_flags & IFF_PROMISC) != 0; +} + + +static int +set_promisc(pcap_t *handle, const int enable) +{ + struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv; + if (enable) + handlep->ifreq.ifr_flags |= IFF_PROMISC; + else + handlep->ifreq.ifr_flags &= ~IFF_PROMISC; + // SIOCSIFFLAGS works for AF_INET, but not for AF_LINK. + return ioctl_ifreq(handlep->aux_socket, SIOCSIFFLAGS, "SIOCSIFFLAGS", + &handlep->ifreq, handle->errbuf); +} + + +static void +pcap_cleanup_haiku(pcap_t *handle) +{ + struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv; + if (handlep->aux_socket >= 0) { + // Closing the sockets has no effect on IFF_PROMISC, hence the + // need to restore the original state on one hand and the + // possibility of clash with other processes managing the same + // interface flag. Unset promiscuous mode iff the activation + // function had set it and it is still set now. + if (handle->opt.promisc && ! handlep->orig_promisc && + get_promisc(handle)) + (void)set_promisc(handle, 0); + close(handlep->aux_socket); + handlep->aux_socket = -1; + } + pcapint_cleanup_live_common(handle); +} + + +static int +pcap_inject_haiku(pcap_t *handle, const void *buffer _U_, int size _U_) +{ + // Haiku currently (hrev57588) does not support sending raw packets. + // https://dev.haiku-os.org/ticket/18810 + strlcpy(handle->errbuf, "Sending packets isn't supported yet", + PCAP_ERRBUF_SIZE); + return PCAP_ERROR; +} + + +static int +pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; + *stats = handlep->stat; + // Now ps_recv and ps_drop are accurate, but ps_ifdrop still equals to + // the snapshot value from the activation time. + if (ioctl_ifreq(handlep->aux_socket, SIOCGIFSTATS, "SIOCGIFSTATS", + &handlep->ifreq, handle->errbuf) < 0) + return PCAP_ERROR; + // The result is subject to wrapping around the 32-bit integer space, + // but that cannot be significantly improved as long as it has to fit + // into a 32-bit member of pcap_stats. + stats->ps_ifdrop = handlep->ifreq.ifr_stats.receive.dropped - stats->ps_ifdrop; + return 0; +} + + +static int +pcap_activate_haiku(pcap_t *handle) +{ + struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv; + int ret = PCAP_ERROR; + + // we need a socket to talk to the networking stack + if ((handlep->aux_socket = dgram_socket(AF_INET, handle->errbuf)) < 0) + goto error; + + // pcap_stats_haiku() will need a baseline for ps_ifdrop. + // At the time of this writing SIOCGIFSTATS returns EINVAL for AF_LINK + // sockets. + if (ioctl_ifreq(handlep->aux_socket, SIOCGIFSTATS, "SIOCGIFSTATS", + &handlep->ifreq, handle->errbuf) < 0) { + // Detect a non-existent network interface at least at the + // first ioctl() use. + if (errno == EINVAL) + ret = PCAP_ERROR_NO_SUCH_DEVICE; + goto error; + } + handlep->stat.ps_ifdrop = handlep->ifreq.ifr_stats.receive.dropped; + + // get link level interface for this interface + if ((handle->fd = dgram_socket(AF_LINK, handle->errbuf)) < 0) + goto error; + + // Derive a DLT from the interface type. + // At the time of this writing SIOCGIFTYPE cannot be used for this + // purpose: it returns EINVAL for AF_LINK sockets and sets ifr_type to + // 0 for AF_INET sockets. Use the same method as Haiku ifconfig does + // (SIOCGIFADDR and AF_LINK). + if (ioctl_ifreq(handle->fd, SIOCGIFADDR, "SIOCGIFADDR", + &handlep->ifreq, handle->errbuf) < 0) + goto error; + struct sockaddr_dl *sdl = (struct sockaddr_dl *)&handlep->ifreq.ifr_addr; + if (sdl->sdl_family != AF_LINK) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Got AF %d instead of AF_LINK for interface \"%s\".", + sdl->sdl_family, handle->opt.device); + goto error; + } + switch (sdl->sdl_type) { + case IFT_ETHER: + // Ethernet on all versions, also tap (L2) mode tunnels on + // versions after R1/beta4. + handle->linktype = DLT_EN10MB; + break; + case IFT_TUNNEL: + // Unused on R1/beta4 and earlier versions, tun (L3) mode + // tunnels on later versions. + case IFT_LOOP: + // The loopback interface on all versions. + // Both IFT_TUNNEL and IFT_LOOP prepended a dummy Ethernet + // header until hrev57585: https://dev.haiku-os.org/ticket/18801 + handle->linktype = DLT_RAW; + break; + default: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Unknown interface type 0x%0x for interface \"%s\".", + sdl->sdl_type, handle->opt.device); + goto error; + } + + // start monitoring + if (ioctl_ifreq(handle->fd, SIOCSPACKETCAP, "SIOCSPACKETCAP", + &handlep->ifreq, handle->errbuf) < 0) + goto error; + + handle->selectable_fd = handle->fd; + handle->read_op = pcap_read_haiku; + handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + handle->inject_op = pcap_inject_haiku; + handle->stats_op = pcap_stats_haiku; + handle->cleanup_op = pcap_cleanup_haiku; + + // use default hooks where possible + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + // Although it would be trivial to size the buffer at the kernel end of + // the capture socket using setsockopt() and SO_RCVBUF, there seems to + // be no point in doing so: setting the size low silently drops some + // packets in the kernel, setting it high does not result in a visible + // improvement. Let's leave this buffer as it is until it is clear why + // it would need resizing. Meanwhile pcap_set_buffer_size() will have + // no effect on Haiku. + + // It would be wrong to size the buffer at the libpcap end of the + // capture socket to the interface MTU, which limits only outgoing + // packets and only at layer 3. For example, an Ethernet interface + // with ifconfig/ioctl() MTU set to 1500 ordinarily sends layer 2 + // packets as large as 1514 bytes and receives layer 2 packets as large + // as the NIC and the driver happen to accept (e.g. 9018 bytes for + // ipro1000). This way, valid packets larger than the MTU can occur in + // a capture and will arrive truncated to pcap_read_haiku() if the + // buffer is not large enough. So let's keep it large enough for most + // if not all practical use cases, then pcap_read_haiku() can handle + // the unlikely truncation as and if necessary. + handle->bufsize = 65536; + + // allocate buffer for monitoring the device + handle->buffer = (u_char*)malloc(handle->bufsize); + if (handle->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "buffer malloc"); + goto error; + } + + if (handle->opt.promisc) { + // Set promiscuous mode iff required, in any case remember the + // original state. + if ((handlep->orig_promisc = get_promisc(handle)) < 0) + goto error; + if (! handlep->orig_promisc && set_promisc(handle, 1) < 0) + return PCAP_WARNING_PROMISC_NOTSUP; + } + return 0; +error: + pcap_cleanup_haiku(handle); + return ret; +} + + +static int +validate_ifname(const char *device, char *errbuf) +{ + if (strlen(device) >= IF_NAMESIZE) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface name \"%s\" is too long.", device); + return PCAP_ERROR; + } + return 0; +} + + +// #pragma mark - pcap API + + +static int +can_be_bound(const char *name) +{ + if (strcmp(name, "loop") != 0) + return 1; + + // In Haiku versions before hrev57010 the loopback interface allows to + // start a capture, but the capture never receives any packets. + // + // Since compiling libpcap on one Haiku version and using the binary on + // another seems to be commonplace, comparing B_HAIKU_VERSION at the + // compile time would not always work as intended. Let's at least + // remove unsuitable well-known 64-bit versions (with or without + // updates) from the problem space at run time. + const char *badversions[] = { + "hrev56578", // R1/beta4 + "hrev55182", // R1/beta3 + "hrev54154", // R1/beta2 + "hrev52295", // R1/beta1 + "hrev44702", // R1/alpha4 + NULL + }; + struct utsname uts; + (void)uname(&uts); + for (const char **s = badversions; *s; s++) + if (! strncmp(uts.version, *s, strlen(*s))) + return 0; + return 1; +} + + +pcap_t * +pcapint_create_interface(const char *device, char *errorBuffer) +{ + if (validate_ifname(device, errorBuffer) < 0) + return NULL; + if (! can_be_bound(device)) { + snprintf(errorBuffer, PCAP_ERRBUF_SIZE, + "Interface \"%s\" does not support capturing traffic.", device); + return NULL; + } + + pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku); + if (handle == NULL) + return NULL; + handle->activate_op = pcap_activate_haiku; + + struct pcap_haiku *handlep = (struct pcap_haiku *)handle->priv; + handlep->aux_socket = -1; + strcpy(handlep->ifreq.ifr_name, device); + + return handle; +} + + +static int +get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) +{ + if (validate_ifname(name, errbuf) < 0) + return PCAP_ERROR; + + if (*flags & PCAP_IF_LOOPBACK || + ! strncmp(name, "tun", strlen("tun")) || + ! strncmp(name, "tap", strlen("tap"))) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + * + * Neither does it to tunnel interfaces. A tun mode tunnel + * can be identified by the IFT_TUNNEL value, but tap mode + * tunnels and Ethernet interfaces both use IFT_ETHER, so let's + * use the interface name prefix until there is a better + * solution. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + + int fd = dgram_socket(AF_LINK, errbuf); + if (fd < 0) + return PCAP_ERROR; + struct ifreq ifreq; + strcpy(ifreq.ifr_name, name); + if (ioctl_ifreq(fd, SIOCGIFFLAGS, "SIOCGIFFLAGS", &ifreq, errbuf) < 0) { + close(fd); + return PCAP_ERROR; + } + *flags |= (ifreq.ifr_flags & IFF_LINK) ? + PCAP_IF_CONNECTION_STATUS_CONNECTED : + PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + if (ioctl_ifreq(fd, SIOCGIFMEDIA, "SIOCGIFMEDIA", &ifreq, errbuf) < 0) { + close(fd); + return PCAP_ERROR; + } + if (IFM_TYPE(ifreq.ifr_media) == IFM_IEEE80211) + *flags |= PCAP_IF_WIRELESS; + close(fd); + + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer) +{ + return pcapint_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound, + get_if_flags); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-int.h b/src/libpcap-1.10.5/pcap-int.h new file mode 100644 index 0000000000..ed0c682968 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-int.h @@ -0,0 +1,601 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef pcap_int_h +#define pcap_int_h + +#include + +#include + +#include + +#ifdef MSDOS + #include + #include +#endif + +#include "varattrs.h" +#include "fmtutils.h" + +#include + +#include "portability.h" + +#define PCAP_DEBUG {printf(" [%s:%d %s] ", __FILE__, __LINE__, __func__); fflush(stdout);} + +/* + * If we're compiling with Visual Studio, make sure we have at least + * VS 2015 or later, so we have sufficient C99 support. + * + * XXX - verify that we have at least C99 support on UN*Xes? + * + * What about MinGW or various DOS toolchains? We're currently assuming + * sufficient C99 support there. + */ +#if defined(_MSC_VER) + /* + * Compiler is MSVC. Make sure we have VS 2015 or later. + */ + #if _MSC_VER < 1900 + #error "Building libpcap requires VS 2015 or later" + #endif +#endif + +/* + * Version string. + * Uses PACKAGE_VERSION from config.h. + */ +#define PCAP_VERSION_STRING "libpcap version " PACKAGE_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * If pcapint_new_api is set, we disable pcap_lookupdev(), because: + * + * it's not thread-safe, and is marked as deprecated, on all + * platforms; + * + * on Windows, it may return UTF-16LE strings, which the program + * might then pass to pcap_create() (or to pcap_open_live(), which + * then passes them to pcap_create()), requiring pcap_create() to + * check for UTF-16LE strings using a hack, and that hack 1) + * *cannot* be 100% reliable and 2) runs the risk of going past the + * end of the string. + * + * We keep it around in legacy mode for compatibility. + * + * We also disable the aforementioned hack in pcap_create(). + */ +extern int pcapint_new_api; + +/* + * If pcapint_utf_8_mode is set, on Windows we treat strings as UTF-8. + * + * On UN*Xes, we assume all strings are and should be in UTF-8, regardless + * of the setting of this flag. + */ +extern int pcapint_utf_8_mode; + +/* + * Swap byte ordering of unsigned long long timestamp on a big endian + * machine. + */ +#define SWAPLL(ull) ((ull & 0xff00000000000000ULL) >> 56) | \ + ((ull & 0x00ff000000000000ULL) >> 40) | \ + ((ull & 0x0000ff0000000000ULL) >> 24) | \ + ((ull & 0x000000ff00000000ULL) >> 8) | \ + ((ull & 0x00000000ff000000ULL) << 8) | \ + ((ull & 0x0000000000ff0000ULL) << 24) | \ + ((ull & 0x000000000000ff00ULL) << 40) | \ + ((ull & 0x00000000000000ffULL) << 56) + +/* + * Maximum snapshot length. + * + * Somewhat arbitrary, but chosen to be: + * + * 1) big enough for maximum-size Linux loopback packets (65549) + * and some USB packets captured with USBPcap: + * + * https://desowin.org/usbpcap/ + * + * (> 131072, < 262144) + * + * and + * + * 2) small enough not to cause attempts to allocate huge amounts of + * memory; some applications might use the snapshot length in a + * savefile header to control the size of the buffer they allocate, + * so a size of, say, 2^31-1 might not work well. (libpcap uses it + * as a hint, but doesn't start out allocating a buffer bigger than + * 2 KiB, and grows the buffer as necessary, but not beyond the + * per-linktype maximum snapshot length. Other code might naively + * use it; we want to avoid writing a too-large snapshot length, + * in order not to cause that code problems.) + * + * We don't enforce this in pcap_set_snaplen(), but we use it internally. + */ +#define MAXIMUM_SNAPLEN 262144 + +/* + * Locale-independent macros for testing character types. + * These can be passed any integral value, without worrying about, for + * example, sign-extending char values, unlike the C macros. + */ +#define PCAP_ISDIGIT(c) \ + ((c) >= '0' && (c) <= '9') +#define PCAP_ISXDIGIT(c) \ + (((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'F') || \ + ((c) >= 'a' && (c) <= 'f')) + +struct pcap_opt { + char *device; + int timeout; /* timeout for buffering */ + u_int buffer_size; + int promisc; + int rfmon; /* monitor mode */ + int immediate; /* immediate mode - deliver packets as soon as they arrive */ + int nonblock; /* non-blocking mode - don't wait for packets to be delivered, return "no packets available" */ + int tstamp_type; + int tstamp_precision; + + /* + * Platform-dependent options. + */ +#ifdef __linux__ + int protocol; /* protocol to use when creating PF_PACKET socket */ +#endif +#ifdef _WIN32 + int nocapture_local;/* disable NPF loopback */ +#endif +}; + +typedef int (*activate_op_t)(pcap_t *); +typedef int (*can_set_rfmon_op_t)(pcap_t *); +typedef int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *); +typedef int (*next_packet_op_t)(pcap_t *, struct pcap_pkthdr *, u_char **); +typedef int (*inject_op_t)(pcap_t *, const void *, int); +typedef void (*save_current_filter_op_t)(pcap_t *, const char *); +typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *); +typedef int (*setdirection_op_t)(pcap_t *, pcap_direction_t); +typedef int (*set_datalink_op_t)(pcap_t *, int); +typedef int (*getnonblock_op_t)(pcap_t *); +typedef int (*setnonblock_op_t)(pcap_t *, int); +typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); +typedef void (*breakloop_op_t)(pcap_t *); +#ifdef _WIN32 +typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *); +typedef int (*setbuff_op_t)(pcap_t *, int); +typedef int (*setmode_op_t)(pcap_t *, int); +typedef int (*setmintocopy_op_t)(pcap_t *, int); +typedef HANDLE (*getevent_op_t)(pcap_t *); +typedef int (*oid_get_request_op_t)(pcap_t *, bpf_u_int32, void *, size_t *); +typedef int (*oid_set_request_op_t)(pcap_t *, bpf_u_int32, const void *, size_t *); +typedef u_int (*sendqueue_transmit_op_t)(pcap_t *, pcap_send_queue *, int); +typedef int (*setuserbuffer_op_t)(pcap_t *, int); +typedef int (*live_dump_op_t)(pcap_t *, char *, int, int); +typedef int (*live_dump_ended_op_t)(pcap_t *, int); +typedef PAirpcapHandle (*get_airpcap_handle_op_t)(pcap_t *); +#endif +typedef void (*cleanup_op_t)(pcap_t *); + +/* + * We put all the stuff used in the read code path at the beginning, + * to try to keep it together in the same cache line or lines. + */ +struct pcap { + /* + * Method to call to read packets on a live capture. + */ + read_op_t read_op; + + /* + * Method to call to read the next packet from a savefile. + */ + next_packet_op_t next_packet_op; + +#ifdef _WIN32 + HANDLE handle; +#else + int fd; +#endif /* _WIN32 */ + + /* + * Read buffer. + */ + u_int bufsize; + void *buffer; + u_char *bp; + int cc; + + sig_atomic_t break_loop; /* flag set to force break from packet-reading loop */ + + void *priv; /* private data for methods */ + +#ifdef ENABLE_REMOTE + struct pcap_samp rmt_samp; /* parameters related to the sampling process. */ +#endif + + int swapped; + FILE *rfile; /* null if live capture, non-null if savefile */ + u_int fddipad; + struct pcap *next; /* list of open pcaps that need stuff cleared on close */ + + /* + * File version number; meaningful only for a savefile, but we + * keep it here so that apps that (mistakenly) ask for the + * version numbers will get the same zero values that they + * always did. + */ + int version_major; + int version_minor; + + int snapshot; + int linktype; /* Network linktype */ + int linktype_ext; /* Extended information stored in the linktype field of a file */ + int offset; /* offset for proper alignment */ + int activated; /* true if the capture is really started */ + int oldstyle; /* if we're opening with pcap_open_live() */ + + struct pcap_opt opt; + + /* + * Place holder for pcap_next(). + */ + u_char *pkt; + +#ifdef _WIN32 + struct pcap_stat stat; /* used for pcap_stats_ex() */ +#endif + + /* We're accepting only packets in this direction/these directions. */ + pcap_direction_t direction; + + /* + * Flags to affect BPF code generation. + */ + int bpf_codegen_flags; + +#if !defined(_WIN32) && !defined(MSDOS) + int selectable_fd; /* FD on which select()/poll()/epoll_wait()/kevent()/etc. can be done */ + + /* + * In case there either is no selectable FD, or there is but + * it doesn't necessarily work (e.g., if it doesn't get notified + * if the packet capture timeout expires before the buffer + * fills up), this points to a timeout that should be used + * in select()/poll()/epoll_wait()/kevent() call. The pcap_t should + * be put into non-blocking mode, and, if the timeout expires on + * the call, an attempt should be made to read packets from all + * pcap_t's with a required timeout, and the code must be + * prepared not to see any packets from the attempt. + */ + const struct timeval *required_select_timeout; +#endif + + /* + * Placeholder for filter code if bpf not in kernel. + */ + struct bpf_program fcode; + + char errbuf[PCAP_ERRBUF_SIZE + 1]; +#ifdef _WIN32 + char acp_errbuf[PCAP_ERRBUF_SIZE + 1]; /* buffer for local code page error strings */ +#endif + int dlt_count; + u_int *dlt_list; + int tstamp_type_count; + u_int *tstamp_type_list; + int tstamp_precision_count; + u_int *tstamp_precision_list; + + struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */ + + /* + * More methods. + */ + activate_op_t activate_op; + can_set_rfmon_op_t can_set_rfmon_op; + inject_op_t inject_op; + save_current_filter_op_t save_current_filter_op; + setfilter_op_t setfilter_op; + setdirection_op_t setdirection_op; + set_datalink_op_t set_datalink_op; + getnonblock_op_t getnonblock_op; + setnonblock_op_t setnonblock_op; + stats_op_t stats_op; + breakloop_op_t breakloop_op; + + /* + * Routine to use as callback for pcap_next()/pcap_next_ex(). + */ + pcap_handler oneshot_callback; + +#ifdef _WIN32 + /* + * These are, at least currently, specific to the Win32 NPF + * driver. + */ + stats_ex_op_t stats_ex_op; + setbuff_op_t setbuff_op; + setmode_op_t setmode_op; + setmintocopy_op_t setmintocopy_op; + getevent_op_t getevent_op; + oid_get_request_op_t oid_get_request_op; + oid_set_request_op_t oid_set_request_op; + sendqueue_transmit_op_t sendqueue_transmit_op; + setuserbuffer_op_t setuserbuffer_op; + live_dump_op_t live_dump_op; + live_dump_ended_op_t live_dump_ended_op; + get_airpcap_handle_op_t get_airpcap_handle_op; +#endif + cleanup_op_t cleanup_op; +}; + +/* + * BPF code generation flags. + */ +#define BPF_SPECIAL_VLAN_HANDLING 0x00000001 /* special VLAN handling for Linux */ + +/* + * User data structure for the one-shot callback used for pcap_next() + * and pcap_next_ex(). + */ +struct oneshot_userdata { + struct pcap_pkthdr *hdr; + const u_char **pkt; + pcap_t *pd; +}; + +#ifndef min +#define min(a, b) ((a) > (b) ? (b) : (a)) +#endif + +int pcapint_offline_read(pcap_t *, int, pcap_handler, u_char *); + +/* + * Does the packet count argument to a module's read routine say + * "supply packets until you run out of packets"? + */ +#define PACKET_COUNT_IS_UNLIMITED(count) ((count) <= 0) + +/* + * Routines that most pcap implementations can use for non-blocking mode. + */ +#if !defined(_WIN32) && !defined(MSDOS) +int pcapint_getnonblock_fd(pcap_t *); +int pcapint_setnonblock_fd(pcap_t *p, int); +#endif + +/* + * Internal interfaces for "pcap_create()". + * + * "pcapint_create_interface()" is the routine to do a pcap_create on + * a regular network interface. There are multiple implementations + * of this, one for each platform type (Linux, BPF, DLPI, etc.), + * with the one used chosen by the configure script. + * + * "pcapint_create_common()" allocates and fills in a pcap_t, for use + * by pcap_create routines. + */ +pcap_t *pcapint_create_interface(const char *, char *); + +/* + * This wrapper takes an error buffer pointer and a type to use for the + * private data, and calls pcapint_create_common(), passing it the error + * buffer pointer, the size for the private data type, in bytes, and the + * offset of the private data from the beginning of the structure, in + * bytes. + */ +#define PCAP_CREATE_COMMON(ebuf, type) \ + pcapint_create_common(ebuf, \ + sizeof (struct { pcap_t __common; type __private; }), \ + offsetof (struct { pcap_t __common; type __private; }, __private)) +pcap_t *pcapint_create_common(char *, size_t, size_t); +int pcapint_do_addexit(pcap_t *); +void pcapint_add_to_pcaps_to_close(pcap_t *); +void pcapint_remove_from_pcaps_to_close(pcap_t *); +void pcapint_cleanup_live_common(pcap_t *); +int pcapint_check_activated(pcap_t *); +void pcapint_breakloop_common(pcap_t *); + +/* + * Internal interfaces for "pcap_findalldevs()". + * + * A pcap_if_list_t * is a reference to a list of devices. + * + * A get_if_flags_func is a platform-dependent function called to get + * additional interface flags. + * + * "pcapint_platform_finddevs()" is the platform-dependent routine to + * find local network interfaces. + * + * "pcapint_findalldevs_interfaces()" is a helper to find those interfaces + * using the "standard" mechanisms (SIOCGIFCONF, "getifaddrs()", etc.). + * + * "pcapint_add_dev()" adds an entry to a pcap_if_list_t. + * + * "pcap_add_any_dev()" adds an entry for the "any" device to a pcap_if_list_t. + * + * "pcapint_find_dev()" tries to find a device, by name, in a pcap_if_list_t. + * + * "pcapint_find_or_add_dev()" checks whether a device is already in a + * pcap_if_list_t and, if not, adds an entry for it. + */ +struct pcap_if_list; +typedef struct pcap_if_list pcap_if_list_t; +typedef int (*get_if_flags_func)(const char *, bpf_u_int32 *, char *); +int pcapint_platform_finddevs(pcap_if_list_t *, char *); +#if !defined(_WIN32) && !defined(MSDOS) +int pcapint_findalldevs_interfaces(pcap_if_list_t *, char *, + int (*)(const char *), get_if_flags_func); +#endif +pcap_if_t *pcapint_find_or_add_dev(pcap_if_list_t *, const char *, bpf_u_int32, + get_if_flags_func, const char *, char *); +pcap_if_t *pcapint_find_dev(pcap_if_list_t *, const char *); +pcap_if_t *pcapint_add_dev(pcap_if_list_t *, const char *, bpf_u_int32, + const char *, char *); +pcap_if_t *pcap_add_any_dev(pcap_if_list_t *, char *); +int pcapint_add_addr_to_dev(pcap_if_t *, struct sockaddr *, size_t, + struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *dstaddr, size_t, char *errbuf); +#ifndef _WIN32 +pcap_if_t *pcapint_find_or_add_if(pcap_if_list_t *, const char *, uint64_t, + get_if_flags_func, char *); +int pcapint_add_addr_to_if(pcap_if_list_t *, const char *, uint64_t, + get_if_flags_func, + struct sockaddr *, size_t, struct sockaddr *, size_t, + struct sockaddr *, size_t, struct sockaddr *, size_t, char *); +#endif + +/* + * Internal interfaces for "pcap_open_offline()" and other savefile + * I/O routines. + * + * "pcapint_open_offline_common()" allocates and fills in a pcap_t, for use + * by pcap_open_offline routines. + * + * "pcapint_adjust_snapshot()" adjusts the snapshot to be non-zero and + * fit within an int. + * + * "pcapint_sf_cleanup()" closes the file handle associated with a pcap_t, if + * appropriate, and frees all data common to all modules for handling + * savefile types. + * + * "pcapint_charset_fopen()", in UTF-8 mode on Windows, does an fopen() that + * treats the pathname as being in UTF-8, rather than the local + * code page, on Windows. + */ + +/* + * This wrapper takes an error buffer pointer and a type to use for the + * private data, and calls pcapint_create_common(), passing it the error + * buffer pointer, the size for the private data type, in bytes, and the + * offset of the private data from the beginning of the structure, in + * bytes. + */ +#define PCAP_OPEN_OFFLINE_COMMON(ebuf, type) \ + pcapint_open_offline_common(ebuf, \ + sizeof (struct { pcap_t __common; type __private; }), \ + offsetof (struct { pcap_t __common; type __private; }, __private)) +pcap_t *pcapint_open_offline_common(char *ebuf, size_t total_size, + size_t private_data); +bpf_u_int32 pcapint_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen); +void pcapint_sf_cleanup(pcap_t *p); +#ifdef _WIN32 +FILE *pcapint_charset_fopen(const char *path, const char *mode); +#else +/* + * On other OSes, just use Boring Old fopen(). + */ +#define pcapint_charset_fopen(path, mode) fopen((path), (mode)) +#endif + +/* + * Internal interfaces for loading code at run time. + */ +#ifdef _WIN32 +#define pcap_code_handle_t HMODULE +#define pcap_funcptr_t FARPROC + +pcap_code_handle_t pcapint_load_code(const char *); +pcap_funcptr_t pcapint_find_function(pcap_code_handle_t, const char *); +#endif + +/* + * Internal interfaces for doing user-mode filtering of packets and + * validating filter programs. + */ +/* + * Auxiliary data, for use when interpreting a filter intended for the + * Linux kernel when the kernel rejects the filter (requiring us to + * run it in userland). It contains VLAN tag information. + */ +struct pcap_bpf_aux_data { + u_short vlan_tag_present; + u_short vlan_tag; +}; + +/* + * Filtering routine that takes the auxiliary data as an additional + * argument. + */ +u_int pcapint_filter_with_aux_data(const struct bpf_insn *, + const u_char *, u_int, u_int, const struct pcap_bpf_aux_data *); + +/* + * Filtering routine that doesn't. + */ +u_int pcapint_filter(const struct bpf_insn *, const u_char *, u_int, u_int); + +/* + * Routine to validate a BPF program. + */ +int pcapint_validate_filter(const struct bpf_insn *, int); + +/* + * Internal interfaces for both "pcap_create()" and routines that + * open savefiles. + * + * "pcapint_oneshot()" is the standard one-shot callback for "pcap_next()" + * and "pcap_next_ex()". + */ +void pcapint_oneshot(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcapint_install_bpf_program(pcap_t *, struct bpf_program *); + +int pcapint_strcasecmp(const char *, const char *); + +/* + * Internal interfaces for pcap_createsrcstr and pcap_parsesrcstr with + * the additional bit of information regarding SSL support (rpcap:// vs. + * rpcaps://). + */ +int pcapint_createsrcstr_ex(char *, int, const char *, const char *, + const char *, unsigned char, char *); +int pcapint_parsesrcstr_ex(const char *, int *, char *, char *, + char *, unsigned char *, char *); + +#ifdef YYDEBUG +extern int pcap_debug; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpcap-1.10.5/pcap-libdlpi.c b/src/libpcap-1.10.5/pcap-libdlpi.c new file mode 100644 index 0000000000..b5ee339fa9 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-libdlpi.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * This code contributed by Sagun Shakya (sagun.shakya@sun.com) + */ +/* + * Packet capture routines for DLPI using libdlpi under SunOS 5.11. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "dlpisubs.h" + +/* Forwards. */ +static int dlpromiscon(pcap_t *, bpf_u_int32); +static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); +static int pcap_inject_libdlpi(pcap_t *, const void *, int); +static void pcap_libdlpi_err(const char *, const char *, int, char *); +static void pcap_cleanup_libdlpi(pcap_t *); + +/* + * list_interfaces() will list all the network links that are + * available on a system. + */ +static boolean_t list_interfaces(const char *, void *); + +typedef struct linknamelist { + char linkname[DLPI_LINKNAME_MAX]; + struct linknamelist *lnl_next; +} linknamelist_t; + +typedef struct linkwalk { + linknamelist_t *lw_list; + int lw_err; +} linkwalk_t; + +/* + * The caller of this function should free the memory allocated + * for each linknamelist_t "entry" allocated. + */ +static boolean_t +list_interfaces(const char *linkname, void *arg) +{ + linkwalk_t *lwp = arg; + linknamelist_t *entry; + + if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { + lwp->lw_err = ENOMEM; + return (B_TRUE); + } + (void) pcapint_strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); + + if (lwp->lw_list == NULL) { + lwp->lw_list = entry; + } else { + entry->lnl_next = lwp->lw_list; + lwp->lw_list = entry; + } + + return (B_FALSE); +} + +static int +pcap_activate_libdlpi(pcap_t *p) +{ + struct pcap_dlpi *pd = p->priv; + int status = 0; + int retv; + dlpi_handle_t dh; + dlpi_info_t dlinfo; + + /* + * Enable Solaris raw and passive DLPI extensions; + * dlpi_open() will not fail if the underlying link does not support + * passive mode. See dlpi(7P) for details. + */ + retv = dlpi_open(p->opt.device, &dh, DLPI_RAW|DLPI_PASSIVE); + if (retv != DLPI_SUCCESS) { + if (retv == DLPI_ELINKNAMEINVAL || retv == DLPI_ENOLINK) { + /* + * There's nothing more to say, so clear the + * error message. + */ + status = PCAP_ERROR_NO_SUCH_DEVICE; + p->errbuf[0] = '\0'; + } else if (retv == DL_SYSERR && + (errno == EPERM || errno == EACCES)) { + status = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open DLPI device failed with %s - root privilege may be required", + (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.device, "dlpi_open", retv, + p->errbuf); + } + return (status); + } + pd->dlpi_hd = dh; + + if (p->opt.rfmon) { + /* + * This device exists, but we don't support monitor mode + * any platforms that support DLPI. + */ + status = PCAP_ERROR_RFMON_NOTSUP; + goto bad; + } + + /* Bind with DLPI_ANY_SAP. */ + if ((retv = dlpi_bind(pd->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.device, "dlpi_bind", retv, p->errbuf); + goto bad; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + /* Enable promiscuous mode. */ + if (p->opt.promisc) { + retv = dlpromiscon(p, DL_PROMISC_PHYS); + if (retv < 0) { + /* + * "You don't have permission to capture on + * this device" and "you don't have permission + * to capture in promiscuous mode on this + * device" are different; let the user know, + * so if they can't get permission to + * capture in promiscuous mode, they can at + * least try to capture in non-promiscuous + * mode. + * + * XXX - you might have to capture in + * promiscuous mode to see outgoing packets. + */ + if (retv == PCAP_ERROR_PERM_DENIED) + status = PCAP_ERROR_PROMISC_PERM_DENIED; + else + status = retv; + goto bad; + } + } else { + /* Try to enable multicast. */ + retv = dlpromiscon(p, DL_PROMISC_MULTI); + if (retv < 0) { + status = retv; + goto bad; + } + } + + /* Try to enable SAP promiscuity. */ + retv = dlpromiscon(p, DL_PROMISC_SAP); + if (retv < 0) { + /* + * Not fatal, since the DL_PROMISC_PHYS mode worked. + * Report it as a warning, however. + */ + if (p->opt.promisc) + status = PCAP_WARNING; + else { + status = retv; + goto bad; + } + } + + /* Determine link type. */ + if ((retv = dlpi_info(pd->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { + status = PCAP_ERROR; + pcap_libdlpi_err(p->opt.device, "dlpi_info", retv, p->errbuf); + goto bad; + } + + if (pcap_process_mactype(p, dlinfo.di_mactype) != 0) { + status = PCAP_ERROR; + goto bad; + } + + p->fd = dlpi_fd(pd->dlpi_hd); + + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, p->snapshot) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * Flush the read side. + */ + if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { + status = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "FLUSHR"); + goto bad; + } + + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p) != 0) { + status = PCAP_ERROR; + goto bad; + } + + /* + * "p->fd" is a FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_libdlpi; + p->inject_op = pcap_inject_libdlpi; + p->setfilter_op = pcapint_install_bpf_program; /* No kernel filtering */ + p->setdirection_op = NULL; /* Not implemented */ + p->set_datalink_op = NULL; /* Can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_dlpi; + p->cleanup_op = pcap_cleanup_libdlpi; + + return (status); +bad: + pcap_cleanup_libdlpi(p); + return (status); +} + +#define STRINGIFY(n) #n + +static int +dlpromiscon(pcap_t *p, bpf_u_int32 level) +{ + struct pcap_dlpi *pd = p->priv; + int retv; + int err; + + retv = dlpi_promiscon(pd->dlpi_hd, level); + if (retv != DLPI_SUCCESS) { + if (retv == DL_SYSERR && + (errno == EPERM || errno == EACCES)) { + if (level == DL_PROMISC_PHYS) { + err = PCAP_ERROR_PROMISC_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to set promiscuous mode failed with %s - root privilege may be required", + (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + err = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to set %s mode failed with %s - root privilege may be required", + (level == DL_PROMISC_MULTI) ? "multicast" : "SAP promiscuous", + (errno == EPERM) ? "EPERM" : "EACCES"); + } + } else { + err = PCAP_ERROR; + pcap_libdlpi_err(p->opt.device, + "dlpi_promiscon" STRINGIFY(level), + retv, p->errbuf); + } + return (err); + } + return (0); +} + +/* + * Presumably everything returned by dlpi_walk() is a DLPI device, + * so there's no work to be done here to check whether name refers + * to a DLPI device. + */ +static int +is_dlpi_interface(const char *name _U_) +{ + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do other than mark loopback devices as "the + * connected/disconnected status doesn't apply". + * + * XXX - on Solaris, can we do what the dladm command does, + * i.e. get a connected/disconnected indication from a kstat? + * (Note that you can also get the link speed, and possibly + * other information, from a kstat as well.) + */ + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + return (0); +} + +/* + * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find + * network links that are plumbed and are up. dlpi_walk(3DLPI) will find + * additional network links present in the system. + */ +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + int retv = 0; + + linknamelist_t *entry, *next; + linkwalk_t lw = {NULL, 0}; + int save_errno; + + /* + * Get the list of regular interfaces first. + */ + if (pcapint_findalldevs_interfaces(devlistp, errbuf, + is_dlpi_interface, get_if_flags) == -1) + return (-1); /* failure */ + + /* dlpi_walk() for loopback will be added here. */ + + /* + * Find all DLPI devices in the current zone. + * + * XXX - will pcapint_findalldevs_interfaces() find any devices + * outside the current zone? If not, the only reason to call + * it would be to get the interface addresses. + */ + dlpi_walk(list_interfaces, &lw, 0); + + if (lw.lw_err != 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + lw.lw_err, "dlpi_walk"); + retv = -1; + goto done; + } + + /* Add linkname if it does not exist on the list. */ + for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { + /* + * If it isn't already in the list of devices, try to + * add it. + */ + if (pcapint_find_or_add_dev(devlistp, entry->linkname, 0, get_if_flags, + NULL, errbuf) == NULL) + retv = -1; + } +done: + save_errno = errno; + for (entry = lw.lw_list; entry != NULL; entry = next) { + next = entry->lnl_next; + free(entry); + } + errno = save_errno; + + return (retv); +} + +/* + * Read data received on DLPI handle. Returns -2 if told to terminate, else + * returns the number of packets read. + */ +static int +pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) +{ + struct pcap_dlpi *pd = p->priv; + int len; + u_char *bufp; + size_t msglen; + int retv; + + len = p->cc; + if (len != 0) { + bufp = p->bp; + goto process_pkts; + } + do { + /* Has "pcap_breakloop()" been called? */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it has, + * and return -2 to indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + + msglen = p->bufsize; + bufp = (u_char *)p->buffer + p->offset; + + retv = dlpi_recv(pd->dlpi_hd, NULL, NULL, bufp, + &msglen, -1, NULL); + if (retv != DLPI_SUCCESS) { + /* + * This is most likely a call to terminate out of the + * loop. So, do not return an error message, instead + * check if "pcap_breakloop()" has been called above. + */ + if (retv == DL_SYSERR && errno == EINTR) { + len = 0; + continue; + } + pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), + "dlpi_recv", retv, p->errbuf); + return (-1); + } + len = msglen; + } while (len == 0); + +process_pkts: + return (pcap_process_pkts(p, callback, user, count, bufp, len)); +} + +static int +pcap_inject_libdlpi(pcap_t *p, const void *buf, int size) +{ + struct pcap_dlpi *pd = p->priv; + int retv; + + retv = dlpi_send(pd->dlpi_hd, NULL, 0, buf, size, NULL); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(dlpi_linkname(pd->dlpi_hd), "dlpi_send", retv, + p->errbuf); + return (-1); + } + /* + * dlpi_send(3DLPI) does not provide a way to return the number of + * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was + * returned we are assuming 'size' bytes were sent. + */ + return (size); +} + +/* + * Close dlpi handle. + */ +static void +pcap_cleanup_libdlpi(pcap_t *p) +{ + struct pcap_dlpi *pd = p->priv; + + if (pd->dlpi_hd != NULL) { + dlpi_close(pd->dlpi_hd); + pd->dlpi_hd = NULL; + p->fd = -1; + } + pcapint_cleanup_live_common(p); +} + +/* + * Write error message to buffer. + */ +static void +pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", + func, linkname, dlpi_strerror(err)); +} + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dlpi); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_libdlpi; + return (p); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-linktype.manmisc.in b/src/libpcap-1.10.5/pcap-linktype.manmisc.in new file mode 100644 index 0000000000..736a91c714 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-linktype.manmisc.in @@ -0,0 +1,48 @@ +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-LINKTYPE @MAN_MISC_INFO@ "6 April 2020" +.SH NAME +pcap-linktype \- link-layer header types supported by libpcap +.SH DESCRIPTION +For a live capture or ``savefile'', libpcap supplies, as the return +value of the +.BR pcap_datalink (3PCAP) +routine, a value that indicates the type of link-layer header at the +beginning of the packets it provides. This is not necessarily the type +of link-layer header that the packets being captured have on the network +from which they're being captured; for example, packets from an IEEE +802.11 network might be provided by libpcap with Ethernet headers that +the network adapter or the network adapter driver generates from the +802.11 headers. The names for those values begin with +.BR DLT_ , +so they are sometimes called "DLT_ values". +.PP +The values stored in the link-layer header type field in the savefile +header are, in most but not all cases, the same as the values returned +by +.BR pcap_datalink (). +The names for those values begin with +.BR LINKTYPE_ . +.PP +The link-layer header types supported by libpcap are described at +https://www.tcpdump.org/linktypes.html . +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap-linux.c b/src/libpcap-1.10.5/pcap-linux.c new file mode 100644 index 0000000000..e0fe1d3e02 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-linux.c @@ -0,0 +1,5735 @@ +/* + * pcap-linux.c: Packet capture interface to the Linux kernel + * + * Copyright (c) 2000 Torsten Landschoff + * Sebastian Krahmer + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Modifications: Added PACKET_MMAP support + * Paolo Abeni + * Added TPACKET_V3 support + * Gabor Tatarka + * + * based on previous works of: + * Simon Patarin + * Phil Wood + * + * Monitor-mode support for mac80211 includes code taken from the iw + * command; the copyright notice for that code is + * + * Copyright (c) 2007, 2008 Johannes Berg + * Copyright (c) 2007 Andy Lutomirski + * Copyright (c) 2007 Mike Kershaw + * Copyright (c) 2008 Gábor Stefanik + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#define _GNU_SOURCE + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap-util.h" +#include "pcap/sll.h" +#include "pcap/vlan.h" +#include "pcap/can_socketcan.h" + +#include "diag-control.h" + +/* + * We require TPACKET_V2 support. + */ +#ifndef TPACKET2_HDRLEN +#error "Libpcap will only work if TPACKET_V2 is supported; you must build for a 2.6.27 or later kernel" +#endif + +/* check for memory mapped access availability. We assume every needed + * struct is defined if the macro TPACKET_HDRLEN is defined, because it + * uses many ring related structs and macros */ +#ifdef TPACKET3_HDRLEN +# define HAVE_TPACKET3 +#endif /* TPACKET3_HDRLEN */ + +/* + * Not all compilers that are used to compile code to run on Linux have + * these builtins. For example, older versions of GCC don't, and at + * least some people are doing cross-builds for MIPS with older versions + * of GCC. + */ +#ifndef HAVE___ATOMIC_LOAD_N +#define __atomic_load_n(ptr, memory_model) (*(ptr)) +#endif +#ifndef HAVE___ATOMIC_STORE_N +#define __atomic_store_n(ptr, val, memory_model) *(ptr) = (val) +#endif + +#define packet_mmap_acquire(pkt) \ + (__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) +#define packet_mmap_release(pkt) \ + (__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) +#define packet_mmap_v3_acquire(pkt) \ + (__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) +#define packet_mmap_v3_release(pkt) \ + (__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) + +#include +#include + +#ifdef HAVE_LINUX_NET_TSTAMP_H +#include +#endif + +/* + * For checking whether a device is a bonding device. + */ +#include + +/* + * Got libnl? + */ +#ifdef HAVE_LIBNL +#include + +#include +#include +#include +#include +#include +#endif /* HAVE_LIBNL */ + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +#define MAX_LINKHEADER_SIZE 256 + +/* + * When capturing on all interfaces we use this as the buffer size. + * Should be bigger then all MTUs that occur in real life. + * 64kB should be enough for now. + */ +#define BIGGER_THAN_ALL_MTUS (64*1024) + +/* + * Private data for capturing on Linux PF_PACKET sockets. + */ +struct pcap_linux { + long long sysfs_dropped; /* packets reported dropped by /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors */ + struct pcap_stat stat; + + char *device; /* device name */ + int filter_in_userland; /* must filter in userland */ + int blocks_to_filter_in_userland; + int must_do_on_close; /* stuff we must do when we close */ + int timeout; /* timeout for buffering */ + int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */ + int ifindex; /* interface index of device we're bound to */ + int lo_ifindex; /* interface index of the loopback device */ + int netdown; /* we got an ENETDOWN and haven't resolved it */ + bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */ + char *mondevice; /* mac80211 monitor device we created */ + u_char *mmapbuf; /* memory-mapped region pointer */ + size_t mmapbuflen; /* size of region */ + int vlan_offset; /* offset at which to insert vlan tags; if -1, don't insert */ + u_int tp_version; /* version of tpacket_hdr for mmaped ring */ + u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */ + u_char *oneshot_buffer; /* buffer for copy of packet */ + int poll_timeout; /* timeout to use in poll() */ +#ifdef HAVE_TPACKET3 + unsigned char *current_packet; /* Current packet within the TPACKET_V3 block. Move to next block if NULL. */ + int packets_left; /* Unhandled packets left within the block from previous call to pcap_read_linux_mmap_v3 in case of TPACKET_V3. */ +#endif + int poll_breakloop_fd; /* fd to an eventfd to break from blocking operations */ +}; + +/* + * Stuff to do when we close. + */ +#define MUST_CLEAR_RFMON 0x00000001 /* clear rfmon (monitor) mode */ +#define MUST_DELETE_MONIF 0x00000002 /* delete monitor-mode interface */ + +/* + * Prototypes for internal functions and methods. + */ +static int get_if_flags(const char *, bpf_u_int32 *, char *); +static int is_wifi(const char *); +static int map_arphrd_to_dlt(pcap_t *, int, const char *, int); +static int pcap_activate_linux(pcap_t *); +static int setup_socket(pcap_t *, int); +static int setup_mmapped(pcap_t *); +static int pcap_can_set_rfmon_linux(pcap_t *); +static int pcap_inject_linux(pcap_t *, const void *, int); +static int pcap_stats_linux(pcap_t *, struct pcap_stat *); +static int pcap_setfilter_linux(pcap_t *, struct bpf_program *); +static int pcap_setdirection_linux(pcap_t *, pcap_direction_t); +static int pcap_set_datalink_linux(pcap_t *, int); +static void pcap_cleanup_linux(pcap_t *); + +union thdr { + struct tpacket2_hdr *h2; +#ifdef HAVE_TPACKET3 + struct tpacket_block_desc *h3; +#endif + u_char *raw; +}; + +#define RING_GET_FRAME_AT(h, offset) (((u_char **)h->buffer)[(offset)]) +#define RING_GET_CURRENT_FRAME(h) RING_GET_FRAME_AT(h, h->offset) + +static void destroy_ring(pcap_t *handle); +static int create_ring(pcap_t *handle); +static int prepare_tpacket_socket(pcap_t *handle); +static int pcap_read_linux_mmap_v2(pcap_t *, int, pcap_handler , u_char *); +#ifdef HAVE_TPACKET3 +static int pcap_read_linux_mmap_v3(pcap_t *, int, pcap_handler , u_char *); +#endif +static int pcap_setnonblock_linux(pcap_t *p, int nonblock); +static int pcap_getnonblock_linux(pcap_t *p); +static void pcapint_oneshot_linux(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes); + +/* + * In pre-3.0 kernels, the tp_vlan_tci field is set to whatever the + * vlan_tci field in the skbuff is. 0 can either mean "not on a VLAN" + * or "on VLAN 0". There is no flag set in the tp_status field to + * distinguish between them. + * + * In 3.0 and later kernels, if there's a VLAN tag present, the tp_vlan_tci + * field is set to the VLAN tag, and the TP_STATUS_VLAN_VALID flag is set + * in the tp_status field, otherwise the tp_vlan_tci field is set to 0 and + * the TP_STATUS_VLAN_VALID flag isn't set in the tp_status field. + * + * With a pre-3.0 kernel, we cannot distinguish between packets with no + * VLAN tag and packets on VLAN 0, so we will mishandle some packets, and + * there's nothing we can do about that. + * + * So, on those systems, which never set the TP_STATUS_VLAN_VALID flag, we + * continue the behavior of earlier libpcaps, wherein we treated packets + * with a VLAN tag of 0 as being packets without a VLAN tag rather than packets + * on VLAN 0. We do this by treating packets with a tp_vlan_tci of 0 and + * with the TP_STATUS_VLAN_VALID flag not set in tp_status as not having + * VLAN tags. This does the right thing on 3.0 and later kernels, and + * continues the old unfixably-imperfect behavior on pre-3.0 kernels. + * + * If TP_STATUS_VLAN_VALID isn't defined, we test it as the 0x10 bit; it + * has that value in 3.0 and later kernels. + */ +#ifdef TP_STATUS_VLAN_VALID + #define VLAN_VALID(hdr, hv) ((hv)->tp_vlan_tci != 0 || ((hdr)->tp_status & TP_STATUS_VLAN_VALID)) +#else + /* + * This is being compiled on a system that lacks TP_STATUS_VLAN_VALID, + * so we test with the value it has in the 3.0 and later kernels, so + * we can test it if we're running on a system that has it. (If we're + * running on a system that doesn't have it, it won't be set in the + * tp_status field, so the tests of it will always fail; that means + * we behave the way we did before we introduced this macro.) + */ + #define VLAN_VALID(hdr, hv) ((hv)->tp_vlan_tci != 0 || ((hdr)->tp_status & 0x10)) +#endif + +#ifdef TP_STATUS_VLAN_TPID_VALID +# define VLAN_TPID(hdr, hv) (((hv)->tp_vlan_tpid || ((hdr)->tp_status & TP_STATUS_VLAN_TPID_VALID)) ? (hv)->tp_vlan_tpid : ETH_P_8021Q) +#else +# define VLAN_TPID(hdr, hv) ETH_P_8021Q +#endif + +/* + * Required select timeout if we're polling for an "interface disappeared" + * indication - 1 millisecond. + */ +static const struct timeval netdown_timeout = { + 0, 1000 /* 1000 microseconds = 1 millisecond */ +}; + +/* + * Wrap some ioctl calls + */ +static int iface_get_id(int fd, const char *device, char *ebuf); +static int iface_get_mtu(int fd, const char *device, char *ebuf); +static int iface_get_arptype(int fd, const char *device, char *ebuf); +static int iface_bind(int fd, int ifindex, char *ebuf, int protocol); +static int enter_rfmon_mode(pcap_t *handle, int sock_fd, + const char *device); +static int iface_get_ts_types(const char *device, pcap_t *handle, + char *ebuf); +static int iface_get_offload(pcap_t *handle); + +static int fix_program(pcap_t *handle, struct sock_fprog *fcode); +static int fix_offset(pcap_t *handle, struct bpf_insn *p); +static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode); +static int reset_kernel_filter(pcap_t *handle); + +static struct sock_filter total_insn + = BPF_STMT(BPF_RET | BPF_K, 0); +static struct sock_fprog total_fcode + = { 1, &total_insn }; + +static int iface_dsa_get_proto_info(const char *device, pcap_t *handle); + +pcap_t * +pcapint_create_interface(const char *device, char *ebuf) +{ + pcap_t *handle; + + handle = PCAP_CREATE_COMMON(ebuf, struct pcap_linux); + if (handle == NULL) + return NULL; + + handle->activate_op = pcap_activate_linux; + handle->can_set_rfmon_op = pcap_can_set_rfmon_linux; + + /* + * See what time stamp types we support. + */ + if (iface_get_ts_types(device, handle, ebuf) == -1) { + pcap_close(handle); + return NULL; + } + + /* + * We claim that we support microsecond and nanosecond time + * stamps. + * + * XXX - with adapter-supplied time stamps, can we choose + * microsecond or nanosecond time stamps on arbitrary + * adapters? + */ + handle->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (handle->tstamp_precision_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + pcap_close(handle); + return NULL; + } + handle->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + handle->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + handle->tstamp_precision_count = 2; + + /* + * Start out with the breakloop handle not open; we don't + * need it until we're activated and ready to capture. + */ + struct pcap_linux *handlep = handle->priv; + handlep->poll_breakloop_fd = -1; + + return handle; +} + +#ifdef HAVE_LIBNL +/* + * If interface {if_name} is a mac80211 driver, the file + * /sys/class/net/{if_name}/phy80211 is a symlink to + * /sys/class/ieee80211/{phydev_name}, for some {phydev_name}. + * + * On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at + * least, has a "wmaster0" device and a "wlan0" device; the + * latter is the one with the IP address. Both show up in + * "tcpdump -D" output. Capturing on the wmaster0 device + * captures with 802.11 headers. + * + * airmon-ng searches through /sys/class/net for devices named + * monN, starting with mon0; as soon as one *doesn't* exist, + * it chooses that as the monitor device name. If the "iw" + * command exists, it does + * + * iw dev {if_name} interface add {monif_name} type monitor + * + * where {monif_name} is the monitor device. It then (sigh) sleeps + * .1 second, and then configures the device up. Otherwise, if + * /sys/class/ieee80211/{phydev_name}/add_iface is a file, it writes + * {mondev_name}, without a newline, to that file, and again (sigh) + * sleeps .1 second, and then iwconfig's that device into monitor + * mode and configures it up. Otherwise, you can't do monitor mode. + * + * All these devices are "glued" together by having the + * /sys/class/net/{if_name}/phy80211 links pointing to the same + * place, so, given a wmaster, wlan, or mon device, you can + * find the other devices by looking for devices with + * the same phy80211 link. + * + * To turn monitor mode off, delete the monitor interface, + * either with + * + * iw dev {monif_name} interface del + * + * or by sending {monif_name}, with no NL, down + * /sys/class/ieee80211/{phydev_name}/remove_iface + * + * Note: if you try to create a monitor device named "monN", and + * there's already a "monN" device, it fails, as least with + * the netlink interface (which is what iw uses), with a return + * value of -ENFILE. (Return values are negative errnos.) We + * could probably use that to find an unused device. + * + * Yes, you can have multiple monitor devices for a given + * physical device. + */ + +/* + * Is this a mac80211 device? If so, fill in the physical device path and + * return 1; if not, return 0. On an error, fill in handle->errbuf and + * return PCAP_ERROR. + */ +static int +get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path, + size_t phydev_max_pathlen) +{ + char *pathstr; + ssize_t bytes_read; + + /* + * Generate the path string for the symlink to the physical device. + */ + if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't generate path name string for /sys/class/net device", + device); + return PCAP_ERROR; + } + bytes_read = readlink(pathstr, phydev_path, phydev_max_pathlen); + if (bytes_read == -1) { + if (errno == ENOENT || errno == EINVAL) { + /* + * Doesn't exist, or not a symlink; assume that + * means it's not a mac80211 device. + */ + free(pathstr); + return 0; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s: Can't readlink %s", device, pathstr); + free(pathstr); + return PCAP_ERROR; + } + free(pathstr); + phydev_path[bytes_read] = '\0'; + return 1; +} + +struct nl80211_state { + struct nl_sock *nl_sock; + struct nl_cache *nl_cache; + struct genl_family *nl80211; +}; + +static int +nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device) +{ + int err; + + state->nl_sock = nl_socket_alloc(); + if (!state->nl_sock) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink handle", device); + return PCAP_ERROR; + } + + if (genl_connect(state->nl_sock)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to connect to generic netlink", device); + goto out_handle_destroy; + } + + err = genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate generic netlink cache: %s", + device, nl_geterror(-err)); + goto out_handle_destroy; + } + + state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211"); + if (!state->nl80211) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl80211 not found", device); + goto out_cache_free; + } + + return 0; + +out_cache_free: + nl_cache_free(state->nl_cache); +out_handle_destroy: + nl_socket_free(state->nl_sock); + return PCAP_ERROR; +} + +static void +nl80211_cleanup(struct nl80211_state *state) +{ + genl_family_put(state->nl80211); + nl_cache_free(state->nl_cache); + nl_socket_free(state->nl_sock); +} + +static int +del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, + const char *device, const char *mondevice); + +static int +add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, + const char *device, const char *mondevice) +{ + struct pcap_linux *handlep = handle->priv; + int ifindex; + struct nl_msg *msg; + int err; + + ifindex = iface_get_id(sock_fd, device, handle->errbuf); + if (ifindex == -1) + return PCAP_ERROR; + + msg = nlmsg_alloc(); + if (!msg) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink msg", device); + return PCAP_ERROR; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, + 0, NL80211_CMD_NEW_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); +DIAG_OFF_NARROWING + NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice); +DIAG_ON_NARROWING + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); + + err = nl_send_auto_complete(state->nl_sock, msg); + if (err < 0) { + if (err == -NLE_FAILURE) { + /* + * Device not available; our caller should just + * keep trying. (libnl 2.x maps ENFILE to + * NLE_FAILURE; it can also map other errors + * to that, but there's not much we can do + * about that.) + */ + nlmsg_free(msg); + return 0; + } else { + /* + * Real failure, not just "that device is not + * available. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_send_auto_complete failed adding %s interface: %s", + device, mondevice, nl_geterror(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + } + err = nl_wait_for_ack(state->nl_sock); + if (err < 0) { + if (err == -NLE_FAILURE) { + /* + * Device not available; our caller should just + * keep trying. (libnl 2.x maps ENFILE to + * NLE_FAILURE; it can also map other errors + * to that, but there's not much we can do + * about that.) + */ + nlmsg_free(msg); + return 0; + } else { + /* + * Real failure, not just "that device is not + * available. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_wait_for_ack failed adding %s interface: %s", + device, mondevice, nl_geterror(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + } + + /* + * Success. + */ + nlmsg_free(msg); + + /* + * Try to remember the monitor device. + */ + handlep->mondevice = strdup(mondevice); + if (handlep->mondevice == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "strdup"); + /* + * Get rid of the monitor device. + */ + del_mon_if(handle, sock_fd, state, device, mondevice); + return PCAP_ERROR; + } + return 1; + +nla_put_failure: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_put failed adding %s interface", + device, mondevice); + nlmsg_free(msg); + return PCAP_ERROR; +} + +static int +del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state, + const char *device, const char *mondevice) +{ + int ifindex; + struct nl_msg *msg; + int err; + + ifindex = iface_get_id(sock_fd, mondevice, handle->errbuf); + if (ifindex == -1) + return PCAP_ERROR; + + msg = nlmsg_alloc(); + if (!msg) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: failed to allocate netlink msg", device); + return PCAP_ERROR; + } + + genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, + 0, NL80211_CMD_DEL_INTERFACE, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + + err = nl_send_auto_complete(state->nl_sock, msg); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_send_auto_complete failed deleting %s interface: %s", + device, mondevice, nl_geterror(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + err = nl_wait_for_ack(state->nl_sock); + if (err < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_wait_for_ack failed adding %s interface: %s", + device, mondevice, nl_geterror(-err)); + nlmsg_free(msg); + return PCAP_ERROR; + } + + /* + * Success. + */ + nlmsg_free(msg); + return 1; + +nla_put_failure: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: nl_put failed deleting %s interface", + device, mondevice); + nlmsg_free(msg); + return PCAP_ERROR; +} +#endif /* HAVE_LIBNL */ + +static int pcap_protocol(pcap_t *handle) +{ + int protocol; + + protocol = handle->opt.protocol; + if (protocol == 0) + protocol = ETH_P_ALL; + + return htons(protocol); +} + +static int +pcap_can_set_rfmon_linux(pcap_t *handle) +{ +#ifdef HAVE_LIBNL + char phydev_path[PATH_MAX+1]; + int ret; +#endif + + if (strcmp(handle->opt.device, "any") == 0) { + /* + * Monitor mode makes no sense on the "any" device. + */ + return 0; + } + +#ifdef HAVE_LIBNL + /* + * Bleah. There doesn't seem to be a way to ask a mac80211 + * device, through libnl, whether it supports monitor mode; + * we'll just check whether the device appears to be a + * mac80211 device and, if so, assume the device supports + * monitor mode. + */ + ret = get_mac80211_phydev(handle, handle->opt.device, phydev_path, + PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 1) + return 1; /* mac80211 device */ +#endif + + return 0; +} + +/* + * Grabs the number of missed packets by the interface from + * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors. + * + * Compared to /proc/net/dev this avoids counting software drops, + * but may be unimplemented and just return 0. + * The author has found no straightforward way to check for support. + */ +static long long int +linux_get_stat(const char * if_name, const char * stat) { + ssize_t bytes_read; + int fd; + char buffer[PATH_MAX]; + + snprintf(buffer, sizeof(buffer), "/sys/class/net/%s/statistics/%s", if_name, stat); + fd = open(buffer, O_RDONLY); + if (fd == -1) + return 0; + + bytes_read = read(fd, buffer, sizeof(buffer) - 1); + close(fd); + if (bytes_read == -1) + return 0; + buffer[bytes_read] = '\0'; + + return strtoll(buffer, NULL, 10); +} + +static long long int +linux_if_drops(const char * if_name) +{ + long long int missed = linux_get_stat(if_name, "rx_missed_errors"); + long long int fifo = linux_get_stat(if_name, "rx_fifo_errors"); + return missed + fifo; +} + + +/* + * Monitor mode is kind of interesting because we have to reset the + * interface before exiting. The problem can't really be solved without + * some daemon taking care of managing usage counts. If we put the + * interface into monitor mode, we set a flag indicating that we must + * take it out of that mode when the interface is closed, and, when + * closing the interface, if that flag is set we take it out of monitor + * mode. + */ + +static void pcap_cleanup_linux( pcap_t *handle ) +{ + struct pcap_linux *handlep = handle->priv; +#ifdef HAVE_LIBNL + struct nl80211_state nlstate; + int ret; +#endif /* HAVE_LIBNL */ + + if (handlep->must_do_on_close != 0) { + /* + * There's something we have to do when closing this + * pcap_t. + */ +#ifdef HAVE_LIBNL + if (handlep->must_do_on_close & MUST_DELETE_MONIF) { + ret = nl80211_init(handle, &nlstate, handlep->device); + if (ret >= 0) { + ret = del_mon_if(handle, handle->fd, &nlstate, + handlep->device, handlep->mondevice); + nl80211_cleanup(&nlstate); + } + if (ret < 0) { + fprintf(stderr, + "Can't delete monitor interface %s (%s).\n" + "Please delete manually.\n", + handlep->mondevice, handle->errbuf); + } + } +#endif /* HAVE_LIBNL */ + + /* + * Take this pcap out of the list of pcaps for which we + * have to take the interface out of some mode. + */ + pcapint_remove_from_pcaps_to_close(handle); + } + + if (handle->fd != -1) { + /* + * Destroy the ring buffer (assuming we've set it up), + * and unmap it if it's mapped. + */ + destroy_ring(handle); + } + + if (handlep->oneshot_buffer != NULL) { + free(handlep->oneshot_buffer); + handlep->oneshot_buffer = NULL; + } + + if (handlep->mondevice != NULL) { + free(handlep->mondevice); + handlep->mondevice = NULL; + } + if (handlep->device != NULL) { + free(handlep->device); + handlep->device = NULL; + } + + if (handlep->poll_breakloop_fd != -1) { + close(handlep->poll_breakloop_fd); + handlep->poll_breakloop_fd = -1; + } + pcapint_cleanup_live_common(handle); +} + +#ifdef HAVE_TPACKET3 +/* + * Some versions of TPACKET_V3 have annoying bugs/misfeatures + * around which we have to work. Determine if we have those + * problems or not. + * 3.19 is the first release with a fixed version of + * TPACKET_V3. We treat anything before that as + * not having a fixed version; that may really mean + * it has *no* version. + */ +static int has_broken_tpacket_v3(void) +{ + struct utsname utsname; + const char *release; + long major, minor; + int matches, verlen; + + /* No version information, assume broken. */ + if (uname(&utsname) == -1) + return 1; + release = utsname.release; + + /* A malformed version, ditto. */ + matches = sscanf(release, "%ld.%ld%n", &major, &minor, &verlen); + if (matches != 2) + return 1; + if (release[verlen] != '.' && release[verlen] != '\0') + return 1; + + /* OK, a fixed version. */ + if (major > 3 || (major == 3 && minor >= 19)) + return 0; + + /* Too old :( */ + return 1; +} +#endif + +/* + * Set the timeout to be used in poll() with memory-mapped packet capture. + */ +static void +set_poll_timeout(struct pcap_linux *handlep) +{ +#ifdef HAVE_TPACKET3 + int broken_tpacket_v3 = has_broken_tpacket_v3(); +#endif + if (handlep->timeout == 0) { +#ifdef HAVE_TPACKET3 + /* + * XXX - due to a set of (mis)features in the TPACKET_V3 + * kernel code prior to the 3.19 kernel, blocking forever + * with a TPACKET_V3 socket can, if few packets are + * arriving and passing the socket filter, cause most + * packets to be dropped. See libpcap issue #335 for the + * full painful story. + * + * The workaround is to have poll() time out very quickly, + * so we grab the frames handed to us, and return them to + * the kernel, ASAP. + */ + if (handlep->tp_version == TPACKET_V3 && broken_tpacket_v3) + handlep->poll_timeout = 1; /* don't block for very long */ + else +#endif + handlep->poll_timeout = -1; /* block forever */ + } else if (handlep->timeout > 0) { +#ifdef HAVE_TPACKET3 + /* + * For TPACKET_V3, the timeout is handled by the kernel, + * so block forever; that way, we don't get extra timeouts. + * Don't do that if we have a broken TPACKET_V3, though. + */ + if (handlep->tp_version == TPACKET_V3 && !broken_tpacket_v3) + handlep->poll_timeout = -1; /* block forever, let TPACKET_V3 wake us up */ + else +#endif + handlep->poll_timeout = handlep->timeout; /* block for that amount of time */ + } else { + /* + * Non-blocking mode; we call poll() to pick up error + * indications, but we don't want it to wait for + * anything. + */ + handlep->poll_timeout = 0; + } +} + +static void pcap_breakloop_linux(pcap_t *handle) +{ + pcapint_breakloop_common(handle); + struct pcap_linux *handlep = handle->priv; + + uint64_t value = 1; + + if (handlep->poll_breakloop_fd != -1) { + /* + * XXX - pcap_breakloop() doesn't have a return value, + * so we can't indicate an error. + */ +DIAG_OFF_WARN_UNUSED_RESULT + (void)write(handlep->poll_breakloop_fd, &value, sizeof(value)); +DIAG_ON_WARN_UNUSED_RESULT + } +} + +/* + * Set the offset at which to insert VLAN tags. + * That should be the offset of the type field. + */ +static void +set_vlan_offset(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + + switch (handle->linktype) { + + case DLT_EN10MB: + /* + * The type field is after the destination and source + * MAC address. + */ + handlep->vlan_offset = 2 * ETH_ALEN; + break; + + case DLT_LINUX_SLL: + /* + * The type field is in the last 2 bytes of the + * DLT_LINUX_SLL header. + */ + handlep->vlan_offset = SLL_HDR_LEN - 2; + break; + + default: + handlep->vlan_offset = -1; /* unknown */ + break; + } +} + +/* + * Get a handle for a live capture from the given device. You can + * pass NULL as device to get all packages (without link level + * information of course). If you pass 1 as promisc the interface + * will be set to promiscuous mode (XXX: I think this usage should + * be deprecated and functions be added to select that later allow + * modification of that values -- Torsten). + */ +static int +pcap_activate_linux(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + const char *device; + int is_any_device; + struct ifreq ifr; + int status; + int ret; + + device = handle->opt.device; + + /* + * Start out assuming no warnings. + */ + status = 0; + + /* + * Make sure the name we were handed will fit into the ioctls we + * might perform on the device; if not, return a "No such device" + * indication, as the Linux kernel shouldn't support creating + * a device whose name won't fit into those ioctls. + * + * "Will fit" means "will fit, complete with a null terminator", + * so if the length, which does *not* include the null terminator, + * is greater than *or equal to* the size of the field into which + * we'll be copying it, that won't fit. + */ + if (strlen(device) >= sizeof(ifr.ifr_name)) { + /* + * There's nothing more to say, so clear the error + * message. + */ + handle->errbuf[0] = '\0'; + status = PCAP_ERROR_NO_SUCH_DEVICE; + goto fail; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + handlep->device = strdup(device); + if (handlep->device == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "strdup"); + status = PCAP_ERROR; + goto fail; + } + + /* + * The "any" device is a special device which causes us not + * to bind to a particular device and thus to look at all + * devices. + */ + is_any_device = (strcmp(device, "any") == 0); + if (is_any_device) { + if (handle->opt.promisc) { + handle->opt.promisc = 0; + /* Just a warning. */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Promiscuous mode not supported on the \"any\" device"); + status = PCAP_WARNING_PROMISC_NOTSUP; + } + } + + /* copy timeout value */ + handlep->timeout = handle->opt.timeout; + + /* + * If we're in promiscuous mode, then we probably want + * to see when the interface drops packets too, so get an + * initial count from + * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors + */ + if (handle->opt.promisc) + handlep->sysfs_dropped = linux_if_drops(handlep->device); + + /* + * If the "any" device is specified, try to open a SOCK_DGRAM. + * Otherwise, open a SOCK_RAW. + */ + ret = setup_socket(handle, is_any_device); + if (ret < 0) { + /* + * Fatal error; the return value is the error code, + * and handle->errbuf has been set to an appropriate + * error message. + */ + status = ret; + goto fail; + } + if (ret > 0) { + /* + * We got a warning; return that, as handle->errbuf + * might have been overwritten by this warning. + */ + status = ret; + } + + /* + * Success (possibly with a warning). + * + * First, try to allocate an event FD for breakloop, if + * we're not going to start in non-blocking mode. + */ + if (!handle->opt.nonblock) { + handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK); + if (handlep->poll_breakloop_fd == -1) { + /* + * Failed. + */ + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "could not open eventfd"); + status = PCAP_ERROR; + goto fail; + } + } + + /* + * Succeeded. + * Try to set up memory-mapped access. + */ + ret = setup_mmapped(handle); + if (ret < 0) { + /* + * We failed to set up to use it, or the + * kernel supports it, but we failed to + * enable it. The return value is the + * error status to return and, if it's + * PCAP_ERROR, handle->errbuf contains + * the error message. + */ + status = ret; + goto fail; + } + if (ret > 0) { + /* + * We got a warning; return that, as handle->errbuf + * might have been overwritten by this warning. + */ + status = ret; + } + + /* + * We succeeded. status has been set to the status to return, + * which might be 0, or might be a PCAP_WARNING_ value. + */ + /* + * Now that we have activated the mmap ring, we can + * set the correct protocol. + */ + if ((ret = iface_bind(handle->fd, handlep->ifindex, + handle->errbuf, pcap_protocol(handle))) != 0) { + status = ret; + goto fail; + } + + handle->inject_op = pcap_inject_linux; + handle->setfilter_op = pcap_setfilter_linux; + handle->setdirection_op = pcap_setdirection_linux; + handle->set_datalink_op = pcap_set_datalink_linux; + handle->setnonblock_op = pcap_setnonblock_linux; + handle->getnonblock_op = pcap_getnonblock_linux; + handle->cleanup_op = pcap_cleanup_linux; + handle->stats_op = pcap_stats_linux; + handle->breakloop_op = pcap_breakloop_linux; + + switch (handlep->tp_version) { + + case TPACKET_V2: + handle->read_op = pcap_read_linux_mmap_v2; + break; +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + handle->read_op = pcap_read_linux_mmap_v3; + break; +#endif + } + handle->oneshot_callback = pcapint_oneshot_linux; + handle->selectable_fd = handle->fd; + + return status; + +fail: + pcap_cleanup_linux(handle); + return status; +} + +static int +pcap_set_datalink_linux(pcap_t *handle, int dlt) +{ + handle->linktype = dlt; + + /* + * Update the offset at which to insert VLAN tags for the + * new link-layer type. + */ + set_vlan_offset(handle); + + return 0; +} + +/* + * linux_check_direction() + * + * Do checks based on packet direction. + */ +static inline int +linux_check_direction(const pcap_t *handle, const struct sockaddr_ll *sll) +{ + struct pcap_linux *handlep = handle->priv; + + if (sll->sll_pkttype == PACKET_OUTGOING) { + /* + * Outgoing packet. + * If this is from the loopback device, reject it; + * we'll see the packet as an incoming packet as well, + * and we don't want to see it twice. + */ + if (sll->sll_ifindex == handlep->lo_ifindex) + return 0; + + /* + * If this is an outgoing CAN or CAN FD frame, and + * the user doesn't only want outgoing packets, + * reject it; CAN devices and drivers, and the CAN + * stack, always arrange to loop back transmitted + * packets, so they also appear as incoming packets. + * We don't want duplicate packets, and we can't + * easily distinguish packets looped back by the CAN + * layer than those received by the CAN layer, so we + * eliminate this packet instead. + * + * We check whether this is a CAN or CAN FD frame + * by checking whether the device's hardware type + * is ARPHRD_CAN. + */ + if (sll->sll_hatype == ARPHRD_CAN && + handle->direction != PCAP_D_OUT) + return 0; + + /* + * If the user only wants incoming packets, reject it. + */ + if (handle->direction == PCAP_D_IN) + return 0; + } else { + /* + * Incoming packet. + * If the user only wants outgoing packets, reject it. + */ + if (handle->direction == PCAP_D_OUT) + return 0; + } + return 1; +} + +/* + * Check whether the device to which the pcap_t is bound still exists. + * We do so by asking what address the socket is bound to, and checking + * whether the ifindex in the address is -1, meaning "that device is gone", + * or some other value, meaning "that device still exists". + */ +static int +device_still_exists(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + struct sockaddr_ll addr; + socklen_t addr_len; + + /* + * If handlep->ifindex is -1, the socket isn't bound, meaning + * we're capturing on the "any" device; that device never + * disappears. (It should also never be configured down, so + * we shouldn't even get here, but let's make sure.) + */ + if (handlep->ifindex == -1) + return (1); /* it's still here */ + + /* + * OK, now try to get the address for the socket. + */ + addr_len = sizeof (addr); + if (getsockname(handle->fd, (struct sockaddr *) &addr, &addr_len) == -1) { + /* + * Error - report an error and return -1. + */ + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "getsockname failed"); + return (-1); + } + if (addr.sll_ifindex == -1) { + /* + * This means the device went away. + */ + return (0); + } + + /* + * The device presumably just went down. + */ + return (1); +} + +static int +pcap_inject_linux(pcap_t *handle, const void *buf, int size) +{ + struct pcap_linux *handlep = handle->priv; + int ret; + + if (handlep->ifindex == -1) { + /* + * We don't support sending on the "any" device. + */ + pcapint_strlcpy(handle->errbuf, + "Sending packets isn't supported on the \"any\" device", + PCAP_ERRBUF_SIZE); + return (-1); + } + + if (handlep->cooked) { + /* + * We don't support sending on cooked-mode sockets. + * + * XXX - how do you send on a bound cooked-mode + * socket? + * Is a "sendto()" required there? + */ + pcapint_strlcpy(handle->errbuf, + "Sending packets isn't supported in cooked mode", + PCAP_ERRBUF_SIZE); + return (-1); + } + + ret = (int)send(handle->fd, buf, size, 0); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + return (ret); +} + +/* + * Get the statistics for the given packet capture handle. + */ +static int +pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_linux *handlep = handle->priv; +#ifdef HAVE_TPACKET3 + /* + * For sockets using TPACKET_V2, the extra stuff at the end + * of a struct tpacket_stats_v3 will not be filled in, and + * we don't look at it so this is OK even for those sockets. + * In addition, the PF_PACKET socket code in the kernel only + * uses the length parameter to compute how much data to + * copy out and to indicate how much data was copied out, so + * it's OK to base it on the size of a struct tpacket_stats. + * + * XXX - it's probably OK, in fact, to just use a + * struct tpacket_stats for V3 sockets, as we don't + * care about the tp_freeze_q_cnt stat. + */ + struct tpacket_stats_v3 kstats; +#else /* HAVE_TPACKET3 */ + struct tpacket_stats kstats; +#endif /* HAVE_TPACKET3 */ + socklen_t len = sizeof (struct tpacket_stats); + + long long if_dropped = 0; + + /* + * To fill in ps_ifdrop, we parse + * /sys/class/net/{if_name}/statistics/rx_{missed,fifo}_errors + * for the numbers + */ + if (handle->opt.promisc) + { + /* + * XXX - is there any reason to do this by remembering + * the last counts value, subtracting it from the + * current counts value, and adding that to stat.ps_ifdrop, + * maintaining stat.ps_ifdrop as a count, rather than just + * saving the *initial* counts value and setting + * stat.ps_ifdrop to the difference between the current + * value and the initial value? + * + * One reason might be to handle the count wrapping + * around, on platforms where the count is 32 bits + * and where you might get more than 2^32 dropped + * packets; is there any other reason? + * + * (We maintain the count as a long long int so that, + * if the kernel maintains the counts as 64-bit even + * on 32-bit platforms, we can handle the real count. + * + * Unfortunately, we can't report 64-bit counts; we + * need a better API for reporting statistics, such as + * one that reports them in a style similar to the + * pcapng Interface Statistics Block, so that 1) the + * counts are 64-bit, 2) it's easier to add new statistics + * without breaking the ABI, and 3) it's easier to + * indicate to a caller that wants one particular + * statistic that it's not available by just not supplying + * it.) + */ + if_dropped = handlep->sysfs_dropped; + handlep->sysfs_dropped = linux_if_drops(handlep->device); + handlep->stat.ps_ifdrop += (u_int)(handlep->sysfs_dropped - if_dropped); + } + + /* + * Try to get the packet counts from the kernel. + */ + if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, + &kstats, &len) > -1) { + /* + * "ps_recv" counts only packets that *passed* the + * filter, not packets that didn't pass the filter. + * This includes packets later dropped because we + * ran out of buffer space. + * + * "ps_drop" counts packets dropped because we ran + * out of buffer space. It doesn't count packets + * dropped by the interface driver. It counts only + * packets that passed the filter. + * + * See above for ps_ifdrop. + * + * Both statistics include packets not yet read from + * the kernel by libpcap, and thus not yet seen by + * the application. + * + * In "linux/net/packet/af_packet.c", at least in 2.6.27 + * through 5.6 kernels, "tp_packets" is incremented for + * every packet that passes the packet filter *and* is + * successfully copied to the ring buffer; "tp_drops" is + * incremented for every packet dropped because there's + * not enough free space in the ring buffer. + * + * When the statistics are returned for a PACKET_STATISTICS + * "getsockopt()" call, "tp_drops" is added to "tp_packets", + * so that "tp_packets" counts all packets handed to + * the PF_PACKET socket, including packets dropped because + * there wasn't room on the socket buffer - but not + * including packets that didn't pass the filter. + * + * In the BSD BPF, the count of received packets is + * incremented for every packet handed to BPF, regardless + * of whether it passed the filter. + * + * We can't make "pcap_stats()" work the same on both + * platforms, but the best approximation is to return + * "tp_packets" as the count of packets and "tp_drops" + * as the count of drops. + * + * Keep a running total because each call to + * getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, .... + * resets the counters to zero. + */ + handlep->stat.ps_recv += kstats.tp_packets; + handlep->stat.ps_drop += kstats.tp_drops; + *stats = handlep->stat; + return 0; + } + + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, errno, + "failed to get statistics from socket"); + return -1; +} + +/* + * A PF_PACKET socket can be bound to any network interface. + */ +static int +can_be_bound(const char *name _U_) +{ + return (1); +} + +/* + * Get a socket to use with various interface ioctls. + */ +static int +get_if_ioctl_socket(void) +{ + int fd; + + /* + * This is a bit ugly. + * + * There isn't a socket type that's guaranteed to work. + * + * AF_NETLINK will work *if* you have Netlink configured into the + * kernel (can it be configured out if you have any networking + * support at all?) *and* if you're running a sufficiently recent + * kernel, but not all the kernels we support are sufficiently + * recent - that feature was introduced in Linux 4.6. + * + * AF_UNIX will work *if* you have UNIX-domain sockets configured + * into the kernel and *if* you're not on a system that doesn't + * allow them - some SELinux systems don't allow you create them. + * Most systems probably have them configured in, but not all systems + * have them configured in and allow them to be created. + * + * AF_INET will work *if* you have IPv4 configured into the kernel, + * but, apparently, some systems have network adapters but have + * kernels without IPv4 support. + * + * AF_INET6 will work *if* you have IPv6 configured into the + * kernel, but if you don't have AF_INET, you might not have + * AF_INET6, either (that is, independently on its own grounds). + * + * AF_PACKET would work, except that some of these calls should + * work even if you *don't* have capture permission (you should be + * able to enumerate interfaces and get information about them + * without capture permission; you shouldn't get a failure until + * you try pcap_activate()). (If you don't allow programs to + * get as much information as possible about interfaces if you + * don't have permission to capture, you run the risk of users + * asking "why isn't it showing XXX" - or, worse, if you don't + * show interfaces *at all* if you don't have permission to + * capture on them, "why do no interfaces show up?" - when the + * real problem is a permissions problem. Error reports of that + * type require a lot more back-and-forth to debug, as evidenced + * by many Wireshark bugs/mailing list questions/Q&A questions.) + * + * So: + * + * we first try an AF_NETLINK socket, where "try" includes + * "try to do a device ioctl on it", as, in the future, once + * pre-4.6 kernels are sufficiently rare, that will probably + * be the mechanism most likely to work; + * + * if that fails, we try an AF_UNIX socket, as that's less + * likely to be configured out on a networking-capable system + * than is IP; + * + * if that fails, we try an AF_INET6 socket; + * + * if that fails, we try an AF_INET socket. + */ + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); + if (fd != -1) { + /* + * OK, let's make sure we can do an SIOCGIFNAME + * ioctl. + */ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + if (ioctl(fd, SIOCGIFNAME, &ifr) == 0 || + errno != EOPNOTSUPP) { + /* + * It succeeded, or failed for some reason + * other than "netlink sockets don't support + * device ioctls". Go with the AF_NETLINK + * socket. + */ + return (fd); + } + + /* + * OK, that didn't work, so it's as bad as "netlink + * sockets aren't available". Close the socket and + * drive on. + */ + close(fd); + } + + /* + * Now try an AF_UNIX socket. + */ + fd = socket(AF_UNIX, SOCK_RAW, 0); + if (fd != -1) { + /* + * OK, we got it! + */ + return (fd); + } + + /* + * Now try an AF_INET6 socket. + */ + fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd != -1) { + return (fd); + } + + /* + * Now try an AF_INET socket. + * + * XXX - if that fails, is there anything else we should try? + * AF_CAN, for embedded systems in vehicles, in case they're + * built without Internet protocol support? Any other socket + * types popular in non-Internet embedded systems? + */ + return (socket(AF_INET, SOCK_DGRAM, 0)); +} + +/* + * Get additional flags for a device, using SIOCGIFMEDIA. + */ +static int +get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) +{ + int sock; + FILE *fh; + unsigned int arptype; + struct ifreq ifr; + struct ethtool_value info; + + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return 0; + } + + sock = get_if_ioctl_socket(); + if (sock == -1) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "Can't create socket to get ethtool information for %s", + name); + return -1; + } + + /* + * OK, what type of network is this? + * In particular, is it wired or wireless? + */ + if (is_wifi(name)) { + /* + * Wi-Fi, hence wireless. + */ + *flags |= PCAP_IF_WIRELESS; + } else { + /* + * OK, what does /sys/class/net/{if_name}/type contain? + * (We don't use that for Wi-Fi, as it'll report + * "Ethernet", i.e. ARPHRD_ETHER, for non-monitor- + * mode devices.) + */ + char *pathstr; + + if (asprintf(&pathstr, "/sys/class/net/%s/type", name) == -1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s: Can't generate path name string for /sys/class/net device", + name); + close(sock); + return -1; + } + fh = fopen(pathstr, "r"); + if (fh != NULL) { + if (fscanf(fh, "%u", &arptype) == 1) { + /* + * OK, we got an ARPHRD_ type; what is it? + */ + switch (arptype) { + + case ARPHRD_LOOPBACK: + /* + * These are types to which + * "connected" and "disconnected" + * don't apply, so don't bother + * asking about it. + * + * XXX - add other types? + */ + close(sock); + fclose(fh); + free(pathstr); + return 0; + + case ARPHRD_IRDA: + case ARPHRD_IEEE80211: + case ARPHRD_IEEE80211_PRISM: + case ARPHRD_IEEE80211_RADIOTAP: +#ifdef ARPHRD_IEEE802154 + case ARPHRD_IEEE802154: +#endif +#ifdef ARPHRD_IEEE802154_MONITOR + case ARPHRD_IEEE802154_MONITOR: +#endif +#ifdef ARPHRD_6LOWPAN + case ARPHRD_6LOWPAN: +#endif + /* + * Various wireless types. + */ + *flags |= PCAP_IF_WIRELESS; + break; + } + } + fclose(fh); + } + free(pathstr); + } + +#ifdef ETHTOOL_GLINK + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + info.cmd = ETHTOOL_GLINK; + /* + * XXX - while Valgrind handles SIOCETHTOOL and knows that + * the ETHTOOL_GLINK command sets the .data member of the + * structure, Memory Sanitizer doesn't yet do so: + * + * https://bugs.llvm.org/show_bug.cgi?id=45814 + * + * For now, we zero it out to squelch warnings; if the bug + * in question is fixed, we can remove this. + */ + info.data = 0; + ifr.ifr_data = (caddr_t)&info; + if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) { + int save_errno = errno; + + switch (save_errno) { + + case EOPNOTSUPP: + case EINVAL: + /* + * OK, this OS version or driver doesn't support + * asking for this information. + * XXX - distinguish between "this doesn't + * support ethtool at all because it's not + * that type of device" vs. "this doesn't + * support ethtool even though it's that + * type of device", and return "unknown". + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + close(sock); + return 0; + + case ENODEV: + /* + * OK, no such device. + * The user will find that out when they try to + * activate the device; just say "OK" and + * don't set anything. + */ + close(sock); + return 0; + + default: + /* + * Other error. + */ + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + save_errno, + "%s: SIOCETHTOOL(ETHTOOL_GLINK) ioctl failed", + name); + close(sock); + return -1; + } + } + + /* + * Is it connected? + */ + if (info.data) { + /* + * It's connected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; + } else { + /* + * It's disconnected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + } +#endif + + close(sock); + return 0; +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + /* + * Get the list of regular interfaces first. + */ + if (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound, + get_if_flags) == -1) + return (-1); /* failure */ + + /* + * Add the "any" device. + */ + if (pcap_add_any_dev(devlistp, errbuf) == NULL) + return (-1); + + return (0); +} + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +static int +pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d) +{ + /* + * It's guaranteed, at this point, that d is a valid + * direction value. + */ + handle->direction = d; + return 0; +} + +static int +is_wifi(const char *device) +{ + char *pathstr; + struct stat statb; + + /* + * See if there's a sysfs wireless directory for it. + * If so, it's a wireless interface. + */ + if (asprintf(&pathstr, "/sys/class/net/%s/wireless", device) == -1) { + /* + * Just give up here. + */ + return 0; + } + if (stat(pathstr, &statb) == 0) { + free(pathstr); + return 1; + } + free(pathstr); + + return 0; +} + +/* + * Linux uses the ARP hardware type to identify the type of an + * interface. pcap uses the DLT_xxx constants for this. This + * function takes a pointer to a "pcap_t", and an ARPHRD_xxx + * constant, as arguments, and sets "handle->linktype" to the + * appropriate DLT_XXX constant and sets "handle->offset" to + * the appropriate value (to make "handle->offset" plus link-layer + * header length be a multiple of 4, so that the link-layer payload + * will be aligned on a 4-byte boundary when capturing packets). + * (If the offset isn't set here, it'll be 0; add code as appropriate + * for cases where it shouldn't be 0.) + * + * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture + * in cooked mode; otherwise, we can't use cooked mode, so we have + * to pick some type that works in raw mode, or fail. + * + * Sets the link type to -1 if unable to map the type. + * + * Returns 0 on success or a PCAP_ERROR_ value on error. + */ +static int map_arphrd_to_dlt(pcap_t *handle, int arptype, + const char *device, int cooked_ok) +{ + static const char cdma_rmnet[] = "cdma_rmnet"; + + switch (arptype) { + + case ARPHRD_ETHER: + /* + * For various annoying reasons having to do with DHCP + * software, some versions of Android give the mobile- + * phone-network interface an ARPHRD_ value of + * ARPHRD_ETHER, even though the packets supplied by + * that interface have no link-layer header, and begin + * with an IP header, so that the ARPHRD_ value should + * be ARPHRD_NONE. + * + * Detect those devices by checking the device name, and + * use DLT_RAW for them. + */ + if (strncmp(device, cdma_rmnet, sizeof cdma_rmnet - 1) == 0) { + handle->linktype = DLT_RAW; + return 0; + } + + /* + * Is this a real Ethernet device? If so, give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + * + * XXX - are there any other sorts of "fake Ethernet" that + * have ARPHRD_ETHER but that shouldn't offer DLT_DOCSIS as + * a Cisco CMTS won't put traffic onto it or get traffic + * bridged onto it? ISDN is handled in "setup_socket()", + * as we fall back on cooked mode there, and we use + * is_wifi() to check for 802.11 devices; are there any + * others? + */ + if (!is_wifi(device)) { + int ret; + + /* + * This is not a Wi-Fi device but it could be + * a DSA master/management network device. + */ + ret = iface_dsa_get_proto_info(device, handle); + if (ret < 0) + return ret; + + if (ret == 1) { + /* + * This is a DSA master/management network + * device linktype is already set by + * iface_dsa_get_proto_info() set an + * appropriate offset here. + */ + handle->offset = 2; + break; + } + + /* + * It's not a Wi-Fi device; offer DOCSIS. + */ + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (handle->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc"); + return (PCAP_ERROR); + } + handle->dlt_list[0] = DLT_EN10MB; + handle->dlt_list[1] = DLT_DOCSIS; + handle->dlt_count = 2; + } + /* FALLTHROUGH */ + + case ARPHRD_METRICOM: + case ARPHRD_LOOPBACK: + handle->linktype = DLT_EN10MB; + handle->offset = 2; + break; + + case ARPHRD_EETHER: + handle->linktype = DLT_EN3MB; + break; + + case ARPHRD_AX25: + handle->linktype = DLT_AX25_KISS; + break; + + case ARPHRD_PRONET: + handle->linktype = DLT_PRONET; + break; + + case ARPHRD_CHAOS: + handle->linktype = DLT_CHAOS; + break; +#ifndef ARPHRD_CAN +#define ARPHRD_CAN 280 +#endif + case ARPHRD_CAN: + handle->linktype = DLT_CAN_SOCKETCAN; + break; + +#ifndef ARPHRD_IEEE802_TR +#define ARPHRD_IEEE802_TR 800 /* From Linux 2.4 */ +#endif + case ARPHRD_IEEE802_TR: + case ARPHRD_IEEE802: + handle->linktype = DLT_IEEE802; + handle->offset = 2; + break; + + case ARPHRD_ARCNET: + handle->linktype = DLT_ARCNET_LINUX; + break; + +#ifndef ARPHRD_FDDI /* From Linux 2.2.13 */ +#define ARPHRD_FDDI 774 +#endif + case ARPHRD_FDDI: + handle->linktype = DLT_FDDI; + handle->offset = 3; + break; + +#ifndef ARPHRD_ATM /* FIXME: How to #include this? */ +#define ARPHRD_ATM 19 +#endif + case ARPHRD_ATM: + /* + * The Classical IP implementation in ATM for Linux + * supports both what RFC 1483 calls "LLC Encapsulation", + * in which each packet has an LLC header, possibly + * with a SNAP header as well, prepended to it, and + * what RFC 1483 calls "VC Based Multiplexing", in which + * different virtual circuits carry different network + * layer protocols, and no header is prepended to packets. + * + * They both have an ARPHRD_ type of ARPHRD_ATM, so + * you can't use the ARPHRD_ type to find out whether + * captured packets will have an LLC header, and, + * while there's a socket ioctl to *set* the encapsulation + * type, there's no ioctl to *get* the encapsulation type. + * + * This means that + * + * programs that dissect Linux Classical IP frames + * would have to check for an LLC header and, + * depending on whether they see one or not, dissect + * the frame as LLC-encapsulated or as raw IP (I + * don't know whether there's any traffic other than + * IP that would show up on the socket, or whether + * there's any support for IPv6 in the Linux + * Classical IP code); + * + * filter expressions would have to compile into + * code that checks for an LLC header and does + * the right thing. + * + * Both of those are a nuisance - and, at least on systems + * that support PF_PACKET sockets, we don't have to put + * up with those nuisances; instead, we can just capture + * in cooked mode. That's what we'll do, if we can. + * Otherwise, we'll just fail. + */ + if (cooked_ok) + handle->linktype = DLT_LINUX_SLL; + else + handle->linktype = -1; + break; + +#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */ +#define ARPHRD_IEEE80211 801 +#endif + case ARPHRD_IEEE80211: + handle->linktype = DLT_IEEE802_11; + break; + +#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ +#define ARPHRD_IEEE80211_PRISM 802 +#endif + case ARPHRD_IEEE80211_PRISM: + handle->linktype = DLT_PRISM_HEADER; + break; + +#ifndef ARPHRD_IEEE80211_RADIOTAP /* new */ +#define ARPHRD_IEEE80211_RADIOTAP 803 +#endif + case ARPHRD_IEEE80211_RADIOTAP: + handle->linktype = DLT_IEEE802_11_RADIO; + break; + + case ARPHRD_PPP: + /* + * Some PPP code in the kernel supplies no link-layer + * header whatsoever to PF_PACKET sockets; other PPP + * code supplies PPP link-layer headers ("syncppp.c"); + * some PPP code might supply random link-layer + * headers (PPP over ISDN - there's code in Ethereal, + * for example, to cope with PPP-over-ISDN captures + * with which the Ethereal developers have had to cope, + * heuristically trying to determine which of the + * oddball link-layer headers particular packets have). + * + * As such, we just punt, and run all PPP interfaces + * in cooked mode, if we can; otherwise, we just treat + * it as DLT_RAW, for now - if somebody needs to capture, + * on a 2.0[.x] kernel, on PPP devices that supply a + * link-layer header, they'll have to add code here to + * map to the appropriate DLT_ type (possibly adding a + * new DLT_ type, if necessary). + */ + if (cooked_ok) + handle->linktype = DLT_LINUX_SLL; + else { + /* + * XXX - handle ISDN types here? We can't fall + * back on cooked sockets, so we'd have to + * figure out from the device name what type of + * link-layer encapsulation it's using, and map + * that to an appropriate DLT_ value, meaning + * we'd map "isdnN" devices to DLT_RAW (they + * supply raw IP packets with no link-layer + * header) and "isdY" devices to a new DLT_I4L_IP + * type that has only an Ethernet packet type as + * a link-layer header. + * + * But sometimes we seem to get random crap + * in the link-layer header when capturing on + * ISDN devices.... + */ + handle->linktype = DLT_RAW; + } + break; + +#ifndef ARPHRD_CISCO +#define ARPHRD_CISCO 513 /* previously ARPHRD_HDLC */ +#endif + case ARPHRD_CISCO: + handle->linktype = DLT_C_HDLC; + break; + + /* Not sure if this is correct for all tunnels, but it + * works for CIPE */ + case ARPHRD_TUNNEL: +#ifndef ARPHRD_SIT +#define ARPHRD_SIT 776 /* From Linux 2.2.13 */ +#endif + case ARPHRD_SIT: + case ARPHRD_CSLIP: + case ARPHRD_SLIP6: + case ARPHRD_CSLIP6: + case ARPHRD_ADAPT: + case ARPHRD_SLIP: +#ifndef ARPHRD_RAWHDLC +#define ARPHRD_RAWHDLC 518 +#endif + case ARPHRD_RAWHDLC: +#ifndef ARPHRD_DLCI +#define ARPHRD_DLCI 15 +#endif + case ARPHRD_DLCI: + /* + * XXX - should some of those be mapped to DLT_LINUX_SLL + * instead? Should we just map all of them to DLT_LINUX_SLL? + */ + handle->linktype = DLT_RAW; + break; + +#ifndef ARPHRD_FRAD +#define ARPHRD_FRAD 770 +#endif + case ARPHRD_FRAD: + handle->linktype = DLT_FRELAY; + break; + + case ARPHRD_LOCALTLK: + handle->linktype = DLT_LTALK; + break; + + case 18: + /* + * RFC 4338 defines an encapsulation for IP and ARP + * packets that's compatible with the RFC 2625 + * encapsulation, but that uses a different ARP + * hardware type and hardware addresses. That + * ARP hardware type is 18; Linux doesn't define + * any ARPHRD_ value as 18, but if it ever officially + * supports RFC 4338-style IP-over-FC, it should define + * one. + * + * For now, we map it to DLT_IP_OVER_FC, in the hopes + * that this will encourage its use in the future, + * should Linux ever officially support RFC 4338-style + * IP-over-FC. + */ + handle->linktype = DLT_IP_OVER_FC; + break; + +#ifndef ARPHRD_FCPP +#define ARPHRD_FCPP 784 +#endif + case ARPHRD_FCPP: +#ifndef ARPHRD_FCAL +#define ARPHRD_FCAL 785 +#endif + case ARPHRD_FCAL: +#ifndef ARPHRD_FCPL +#define ARPHRD_FCPL 786 +#endif + case ARPHRD_FCPL: +#ifndef ARPHRD_FCFABRIC +#define ARPHRD_FCFABRIC 787 +#endif + case ARPHRD_FCFABRIC: + /* + * Back in 2002, Donald Lee at Cray wanted a DLT_ for + * IP-over-FC: + * + * https://www.mail-archive.com/tcpdump-workers@sandelman.ottawa.on.ca/msg01043.html + * + * and one was assigned. + * + * In a later private discussion (spun off from a message + * on the ethereal-users list) on how to get that DLT_ + * value in libpcap on Linux, I ended up deciding that + * the best thing to do would be to have him tweak the + * driver to set the ARPHRD_ value to some ARPHRD_FCxx + * type, and map all those types to DLT_IP_OVER_FC: + * + * I've checked into the libpcap and tcpdump CVS tree + * support for DLT_IP_OVER_FC. In order to use that, + * you'd have to modify your modified driver to return + * one of the ARPHRD_FCxxx types, in "fcLINUXfcp.c" - + * change it to set "dev->type" to ARPHRD_FCFABRIC, for + * example (the exact value doesn't matter, it can be + * any of ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, or + * ARPHRD_FCFABRIC). + * + * 11 years later, Christian Svensson wanted to map + * various ARPHRD_ values to DLT_FC_2 and + * DLT_FC_2_WITH_FRAME_DELIMS for raw Fibre Channel + * frames: + * + * https://github.com/mcr/libpcap/pull/29 + * + * There doesn't seem to be any network drivers that uses + * any of the ARPHRD_FC* values for IP-over-FC, and + * it's not exactly clear what the "Dummy types for non + * ARP hardware" are supposed to mean (link-layer + * header type? Physical network type?), so it's + * not exactly clear why the ARPHRD_FC* types exist + * in the first place. + * + * For now, we map them to DLT_FC_2, and provide an + * option of DLT_FC_2_WITH_FRAME_DELIMS, as well as + * DLT_IP_OVER_FC just in case there's some old + * driver out there that uses one of those types for + * IP-over-FC on which somebody wants to capture + * packets. + */ + handle->linktype = DLT_FC_2; + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 3); + if (handle->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc"); + return (PCAP_ERROR); + } + handle->dlt_list[0] = DLT_FC_2; + handle->dlt_list[1] = DLT_FC_2_WITH_FRAME_DELIMS; + handle->dlt_list[2] = DLT_IP_OVER_FC; + handle->dlt_count = 3; + break; + +#ifndef ARPHRD_IRDA +#define ARPHRD_IRDA 783 +#endif + case ARPHRD_IRDA: + /* Don't expect IP packet out of this interfaces... */ + handle->linktype = DLT_LINUX_IRDA; + /* We need to save packet direction for IrDA decoding, + * so let's use "Linux-cooked" mode. Jean II + * + * XXX - this is handled in setup_socket(). */ + /* handlep->cooked = 1; */ + break; + + /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation + * is needed, please report it to */ +#ifndef ARPHRD_LAPD +#define ARPHRD_LAPD 8445 +#endif + case ARPHRD_LAPD: + /* Don't expect IP packet out of this interfaces... */ + handle->linktype = DLT_LINUX_LAPD; + break; + +#ifndef ARPHRD_NONE +#define ARPHRD_NONE 0xFFFE +#endif + case ARPHRD_NONE: + /* + * No link-layer header; packets are just IP + * packets, so use DLT_RAW. + */ + handle->linktype = DLT_RAW; + break; + +#ifndef ARPHRD_IEEE802154 +#define ARPHRD_IEEE802154 804 +#endif + case ARPHRD_IEEE802154: + handle->linktype = DLT_IEEE802_15_4_NOFCS; + break; + +#ifndef ARPHRD_NETLINK +#define ARPHRD_NETLINK 824 +#endif + case ARPHRD_NETLINK: + handle->linktype = DLT_NETLINK; + /* + * We need to use cooked mode, so that in sll_protocol we + * pick up the netlink protocol type such as NETLINK_ROUTE, + * NETLINK_GENERIC, NETLINK_FIB_LOOKUP, etc. + * + * XXX - this is handled in setup_socket(). + */ + /* handlep->cooked = 1; */ + break; + +#ifndef ARPHRD_VSOCKMON +#define ARPHRD_VSOCKMON 826 +#endif + case ARPHRD_VSOCKMON: + handle->linktype = DLT_VSOCK; + break; + + default: + handle->linktype = -1; + break; + } + return (0); +} + +/* + * Try to set up a PF_PACKET socket. + * Returns 0 or a PCAP_WARNING_ value on success and a PCAP_ERROR_ value + * on failure. + */ +static int +setup_socket(pcap_t *handle, int is_any_device) +{ + struct pcap_linux *handlep = handle->priv; + const char *device = handle->opt.device; + int status = 0; + int sock_fd, arptype; + int val; + int err = 0; + struct packet_mreq mr; +#if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) + int bpf_extensions; + socklen_t len = sizeof(bpf_extensions); +#endif + + /* + * Open a socket with protocol family packet. If cooked is true, + * we open a SOCK_DGRAM socket for the cooked interface, otherwise + * we open a SOCK_RAW socket for the raw interface. + * + * The protocol is set to 0. This means we will receive no + * packets until we "bind" the socket with a non-zero + * protocol. This allows us to setup the ring buffers without + * dropping any packets. + */ + sock_fd = is_any_device ? + socket(PF_PACKET, SOCK_DGRAM, 0) : + socket(PF_PACKET, SOCK_RAW, 0); + + if (sock_fd == -1) { + if (errno == EPERM || errno == EACCES) { + /* + * You don't have permission to open the + * socket. + */ + status = PCAP_ERROR_PERM_DENIED; + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to create packet socket failed - CAP_NET_RAW may be required"); + } else if (errno == EAFNOSUPPORT) { + /* + * PF_PACKET sockets not supported. + * Perhaps we're running on the WSL1 module + * in the Windows NT kernel rather than on + * a real Linux kernel. + */ + status = PCAP_ERROR_CAPTURE_NOTSUP; + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "PF_PACKET sockets not supported - is this WSL1?"); + } else { + /* + * Other error. + */ + status = PCAP_ERROR; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + return status; + } + + /* + * Get the interface index of the loopback device. + * If the attempt fails, don't fail, just set the + * "handlep->lo_ifindex" to -1. + * + * XXX - can there be more than one device that loops + * packets back, i.e. devices other than "lo"? If so, + * we'd need to find them all, and have an array of + * indices for them, and check all of them in + * "pcap_read_packet()". + */ + handlep->lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf); + + /* + * Default value for offset to align link-layer payload + * on a 4-byte boundary. + */ + handle->offset = 0; + + /* + * What kind of frames do we have to deal with? Fall back + * to cooked mode if we have an unknown interface type + * or a type we know doesn't work well in raw mode. + */ + if (!is_any_device) { + /* Assume for now we don't need cooked mode. */ + handlep->cooked = 0; + + if (handle->opt.rfmon) { + /* + * We were asked to turn on monitor mode. + * Do so before we get the link-layer type, + * because entering monitor mode could change + * the link-layer type. + */ + err = enter_rfmon_mode(handle, sock_fd, device); + if (err < 0) { + /* Hard failure */ + close(sock_fd); + return err; + } + if (err == 0) { + /* + * Nothing worked for turning monitor mode + * on. + */ + close(sock_fd); + + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * Either monitor mode has been turned on for + * the device, or we've been given a different + * device to open for monitor mode. If we've + * been given a different device, use it. + */ + if (handlep->mondevice != NULL) + device = handlep->mondevice; + } + arptype = iface_get_arptype(sock_fd, device, handle->errbuf); + if (arptype < 0) { + close(sock_fd); + return arptype; + } + status = map_arphrd_to_dlt(handle, arptype, device, 1); + if (status < 0) { + close(sock_fd); + return status; + } + if (handle->linktype == -1 || + handle->linktype == DLT_LINUX_SLL || + handle->linktype == DLT_LINUX_IRDA || + handle->linktype == DLT_LINUX_LAPD || + handle->linktype == DLT_NETLINK || + (handle->linktype == DLT_EN10MB && + (strncmp("isdn", device, 4) == 0 || + strncmp("isdY", device, 4) == 0))) { + /* + * Unknown interface type (-1), or a + * device we explicitly chose to run + * in cooked mode (e.g., PPP devices), + * or an ISDN device (whose link-layer + * type we can only determine by using + * APIs that may be different on different + * kernels) - reopen in cooked mode. + * + * If the type is unknown, return a warning; + * map_arphrd_to_dlt() has already set the + * warning message. + */ + if (close(sock_fd) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "close"); + return PCAP_ERROR; + } + sock_fd = socket(PF_PACKET, SOCK_DGRAM, 0); + if (sock_fd < 0) { + /* + * Fatal error. We treat this as + * a generic error; we already know + * that we were able to open a + * PF_PACKET/SOCK_RAW socket, so + * any failure is a "this shouldn't + * happen" case. + */ + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "socket"); + return PCAP_ERROR; + } + handlep->cooked = 1; + + /* + * Get rid of any link-layer type list + * we allocated - this only supports cooked + * capture. + */ + if (handle->dlt_list != NULL) { + free(handle->dlt_list); + handle->dlt_list = NULL; + handle->dlt_count = 0; + } + + if (handle->linktype == -1) { + /* + * Warn that we're falling back on + * cooked mode; we may want to + * update "map_arphrd_to_dlt()" + * to handle the new type. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "arptype %d not " + "supported by libpcap - " + "falling back to cooked " + "socket", + arptype); + status = PCAP_WARNING; + } + + /* + * IrDA capture is not a real "cooked" capture, + * it's IrLAP frames, not IP packets. The + * same applies to LAPD capture. + */ + if (handle->linktype != DLT_LINUX_IRDA && + handle->linktype != DLT_LINUX_LAPD && + handle->linktype != DLT_NETLINK) + handle->linktype = DLT_LINUX_SLL; + } + + handlep->ifindex = iface_get_id(sock_fd, device, + handle->errbuf); + if (handlep->ifindex == -1) { + close(sock_fd); + return PCAP_ERROR; + } + + if ((err = iface_bind(sock_fd, handlep->ifindex, + handle->errbuf, 0)) != 0) { + close(sock_fd); + return err; + } + } else { + /* + * The "any" device. + */ + if (handle->opt.rfmon) { + /* + * It doesn't support monitor mode. + */ + close(sock_fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* + * It uses cooked mode. + * Support both DLT_LINUX_SLL and DLT_LINUX_SLL2. + */ + handlep->cooked = 1; + handle->linktype = DLT_LINUX_SLL; + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (handle->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc"); + return (PCAP_ERROR); + } + handle->dlt_list[0] = DLT_LINUX_SLL; + handle->dlt_list[1] = DLT_LINUX_SLL2; + handle->dlt_count = 2; + + /* + * We're not bound to a device. + * For now, we're using this as an indication + * that we can't transmit; stop doing that only + * if we figure out how to transmit in cooked + * mode. + */ + handlep->ifindex = -1; + } + + /* + * Select promiscuous mode on if "promisc" is set. + * + * Do not turn allmulti mode on if we don't select + * promiscuous mode - on some devices (e.g., Orinoco + * wireless interfaces), allmulti mode isn't supported + * and the driver implements it by turning promiscuous + * mode on, and that screws up the operation of the + * card as a normal networking interface, and on no + * other platform I know of does starting a non- + * promiscuous capture affect which multicast packets + * are received by the interface. + */ + + /* + * Hmm, how can we set promiscuous mode on all interfaces? + * I am not sure if that is possible at all. For now, we + * silently ignore attempts to turn promiscuous mode on + * for the "any" device (so you don't have to explicitly + * disable it in programs such as tcpdump). + */ + + if (!is_any_device && handle->opt.promisc) { + memset(&mr, 0, sizeof(mr)); + mr.mr_ifindex = handlep->ifindex; + mr.mr_type = PACKET_MR_PROMISC; + if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr, sizeof(mr)) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_ADD_MEMBERSHIP)"); + close(sock_fd); + return PCAP_ERROR; + } + } + + /* + * Enable auxiliary data and reserve room for reconstructing + * VLAN headers. + * + * XXX - is enabling auxiliary data necessary, now that we + * only support memory-mapped capture? The kernel's memory-mapped + * capture code doesn't seem to check whether auxiliary data + * is enabled, it seems to provide it whether it is or not. + */ + val = 1; + if (setsockopt(sock_fd, SOL_PACKET, PACKET_AUXDATA, &val, + sizeof(val)) == -1 && errno != ENOPROTOOPT) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "setsockopt (PACKET_AUXDATA)"); + close(sock_fd); + return PCAP_ERROR; + } + handle->offset += VLAN_TAG_LEN; + + /* + * If we're in cooked mode, make the snapshot length + * large enough to hold a "cooked mode" header plus + * 1 byte of packet data (so we don't pass a byte + * count of 0 to "recvfrom()"). + * XXX - we don't know whether this will be DLT_LINUX_SLL + * or DLT_LINUX_SLL2, so make sure it's big enough for + * a DLT_LINUX_SLL2 "cooked mode" header; a snapshot length + * that small is silly anyway. + */ + if (handlep->cooked) { + if (handle->snapshot < SLL2_HDR_LEN + 1) + handle->snapshot = SLL2_HDR_LEN + 1; + } + handle->bufsize = handle->snapshot; + + /* + * Set the offset at which to insert VLAN tags. + */ + set_vlan_offset(handle); + + if (handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) { + int nsec_tstamps = 1; + + if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, &nsec_tstamps, sizeof(nsec_tstamps)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "setsockopt: unable to set SO_TIMESTAMPNS"); + close(sock_fd); + return PCAP_ERROR; + } + } + + /* + * We've succeeded. Save the socket FD in the pcap structure. + */ + handle->fd = sock_fd; + +#if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) + /* + * Can we generate special code for VLAN checks? + * (XXX - what if we need the special code but it's not supported + * by the OS? Is that possible?) + */ + if (getsockopt(sock_fd, SOL_SOCKET, SO_BPF_EXTENSIONS, + &bpf_extensions, &len) == 0) { + if (bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT) { + /* + * Yes, we can. Request that we do so. + */ + handle->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING; + } + } +#endif /* defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT) */ + + return status; +} + +/* + * Attempt to setup memory-mapped access. + * + * On success, returns 0 if there are no warnings or a PCAP_WARNING_ code + * if there is a warning. + * + * On error, returns the appropriate error code; if that is PCAP_ERROR, + * sets handle->errbuf to the appropriate message. + */ +static int +setup_mmapped(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + int status; + + /* + * Attempt to allocate a buffer to hold the contents of one + * packet, for use by the oneshot callback. + */ + handlep->oneshot_buffer = malloc(handle->snapshot); + if (handlep->oneshot_buffer == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't allocate oneshot buffer"); + return PCAP_ERROR; + } + + if (handle->opt.buffer_size == 0) { + /* by default request 2M for the ring buffer */ + handle->opt.buffer_size = 2*1024*1024; + } + status = prepare_tpacket_socket(handle); + if (status == -1) { + free(handlep->oneshot_buffer); + handlep->oneshot_buffer = NULL; + return PCAP_ERROR; + } + status = create_ring(handle); + if (status < 0) { + /* + * Error attempting to enable memory-mapped capture; + * fail. The return value is the status to return. + */ + free(handlep->oneshot_buffer); + handlep->oneshot_buffer = NULL; + return status; + } + + /* + * Success. status has been set either to 0 if there are no + * warnings or to a PCAP_WARNING_ value if there is a warning. + * + * handle->offset is used to get the current position into the rx ring. + * handle->cc is used to store the ring size. + */ + + /* + * Set the timeout to use in poll() before returning. + */ + set_poll_timeout(handlep); + + return status; +} + +/* + * Attempt to set the socket to the specified version of the memory-mapped + * header. + * + * Return 0 if we succeed; return 1 if we fail because that version isn't + * supported; return -1 on any other error, and set handle->errbuf. + */ +static int +init_tpacket(pcap_t *handle, int version, const char *version_str) +{ + struct pcap_linux *handlep = handle->priv; + int val = version; + socklen_t len = sizeof(val); + + /* + * Probe whether kernel supports the specified TPACKET version; + * this also gets the length of the header for that version. + * + * This socket option was introduced in 2.6.27, which was + * also the first release with TPACKET_V2 support. + */ + if (getsockopt(handle->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { + if (errno == EINVAL) { + /* + * EINVAL means this specific version of TPACKET + * is not supported. Tell the caller they can try + * with a different one; if they've run out of + * others to try, let them set the error message + * appropriately. + */ + return 1; + } + + /* + * All other errors are fatal. + */ + if (errno == ENOPROTOOPT) { + /* + * PACKET_HDRLEN isn't supported, which means + * that memory-mapped capture isn't supported. + * Indicate that in the message. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Kernel doesn't support memory-mapped capture; a 2.6.27 or later 2.x kernel is required, with CONFIG_PACKET_MMAP specified for 2.x kernels"); + } else { + /* + * Some unexpected error. + */ + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't get %s header len on packet socket", + version_str); + } + return -1; + } + handlep->tp_hdrlen = val; + + val = version; + if (setsockopt(handle->fd, SOL_PACKET, PACKET_VERSION, &val, + sizeof(val)) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't activate %s on packet socket", version_str); + return -1; + } + handlep->tp_version = version; + + return 0; +} + +/* + * Attempt to set the socket to version 3 of the memory-mapped header and, + * if that fails because version 3 isn't supported, attempt to fall + * back to version 2. If version 2 isn't supported, just fail. + * + * Return 0 if we succeed and -1 on any other error, and set handle->errbuf. + */ +static int +prepare_tpacket_socket(pcap_t *handle) +{ + int ret; + +#ifdef HAVE_TPACKET3 + /* + * Try setting the version to TPACKET_V3. + * + * The only mode in which buffering is done on PF_PACKET + * sockets, so that packets might not be delivered + * immediately, is TPACKET_V3 mode. + * + * The buffering cannot be disabled in that mode, so + * if the user has requested immediate mode, we don't + * use TPACKET_V3. + */ + if (!handle->opt.immediate) { + ret = init_tpacket(handle, TPACKET_V3, "TPACKET_V3"); + if (ret == 0) { + /* + * Success. + */ + return 0; + } + if (ret == -1) { + /* + * We failed for some reason other than "the + * kernel doesn't support TPACKET_V3". + */ + return -1; + } + + /* + * This means it returned 1, which means "the kernel + * doesn't support TPACKET_V3"; try TPACKET_V2. + */ + } +#endif /* HAVE_TPACKET3 */ + + /* + * Try setting the version to TPACKET_V2. + */ + ret = init_tpacket(handle, TPACKET_V2, "TPACKET_V2"); + if (ret == 0) { + /* + * Success. + */ + return 0; + } + + if (ret == 1) { + /* + * OK, the kernel supports memory-mapped capture, but + * not TPACKET_V2. Set the error message appropriately. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Kernel doesn't support TPACKET_V2; a 2.6.27 or later kernel is required"); + } + + /* + * We failed. + */ + return -1; +} + +#define MAX(a,b) ((a)>(b)?(a):(b)) + +/* + * Attempt to set up memory-mapped access. + * + * On success, returns 0 if there are no warnings or to a PCAP_WARNING_ code + * if there is a warning. + * + * On error, returns the appropriate error code; if that is PCAP_ERROR, + * sets handle->errbuf to the appropriate message. + */ +static int +create_ring(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + unsigned i, j, frames_per_block; +#ifdef HAVE_TPACKET3 + /* + * For sockets using TPACKET_V2, the extra stuff at the end of a + * struct tpacket_req3 will be ignored, so this is OK even for + * those sockets. + */ + struct tpacket_req3 req; +#else + struct tpacket_req req; +#endif + socklen_t len; + unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff; + unsigned int frame_size; + int status; + + /* + * Start out assuming no warnings. + */ + status = 0; + + /* + * Reserve space for VLAN tag reconstruction. + */ + tp_reserve = VLAN_TAG_LEN; + + /* + * If we're capturing in cooked mode, reserve space for + * a DLT_LINUX_SLL2 header; we don't know yet whether + * we'll be using DLT_LINUX_SLL or DLT_LINUX_SLL2, as + * that can be changed on an open device, so we reserve + * space for the larger of the two. + * + * XXX - we assume that the kernel is still adding + * 16 bytes of extra space, so we subtract 16 from + * SLL2_HDR_LEN to get the additional space needed. + * (Are they doing that for DLT_LINUX_SLL, the link- + * layer header for which is 16 bytes?) + * + * XXX - should we use TPACKET_ALIGN(SLL2_HDR_LEN - 16)? + */ + if (handlep->cooked) + tp_reserve += SLL2_HDR_LEN - 16; + + /* + * Try to request that amount of reserve space. + * This must be done before creating the ring buffer. + */ + len = sizeof(tp_reserve); + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RESERVE, + &tp_reserve, len) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "setsockopt (PACKET_RESERVE)"); + return PCAP_ERROR; + } + + switch (handlep->tp_version) { + + case TPACKET_V2: + /* Note that with large snapshot length (say 256K, which is + * the default for recent versions of tcpdump, Wireshark, + * TShark, dumpcap or 64K, the value that "-s 0" has given for + * a long time with tcpdump), if we use the snapshot + * length to calculate the frame length, only a few frames + * will be available in the ring even with pretty + * large ring size (and a lot of memory will be unused). + * + * Ideally, we should choose a frame length based on the + * minimum of the specified snapshot length and the maximum + * packet size. That's not as easy as it sounds; consider, + * for example, an 802.11 interface in monitor mode, where + * the frame would include a radiotap header, where the + * maximum radiotap header length is device-dependent. + * + * So, for now, we just do this for Ethernet devices, where + * there's no metadata header, and the link-layer header is + * fixed length. We can get the maximum packet size by + * adding 18, the Ethernet header length plus the CRC length + * (just in case we happen to get the CRC in the packet), to + * the MTU of the interface; we fetch the MTU in the hopes + * that it reflects support for jumbo frames. (Even if the + * interface is just being used for passive snooping, the + * driver might set the size of buffers in the receive ring + * based on the MTU, so that the MTU limits the maximum size + * of packets that we can receive.) + * + * If segmentation/fragmentation or receive offload are + * enabled, we can get reassembled/aggregated packets larger + * than MTU, but bounded to 65535 plus the Ethernet overhead, + * due to kernel and protocol constraints */ + frame_size = handle->snapshot; + if (handle->linktype == DLT_EN10MB) { + unsigned int max_frame_len; + int mtu; + int offload; + + mtu = iface_get_mtu(handle->fd, handle->opt.device, + handle->errbuf); + if (mtu == -1) + return PCAP_ERROR; + offload = iface_get_offload(handle); + if (offload == -1) + return PCAP_ERROR; + if (offload) + max_frame_len = MAX(mtu, 65535); + else + max_frame_len = mtu; + max_frame_len += 18; + + if (frame_size > max_frame_len) + frame_size = max_frame_len; + } + + /* NOTE: calculus matching those in tpacket_rcv() + * in linux-2.6/net/packet/af_packet.c + */ + len = sizeof(sk_type); + if (getsockopt(handle->fd, SOL_SOCKET, SO_TYPE, &sk_type, + &len) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "getsockopt (SO_TYPE)"); + return PCAP_ERROR; + } + maclen = (sk_type == SOCK_DGRAM) ? 0 : MAX_LINKHEADER_SIZE; + /* XXX: in the kernel maclen is calculated from + * LL_ALLOCATED_SPACE(dev) and vnet_hdr.hdr_len + * in: packet_snd() in linux-2.6/net/packet/af_packet.c + * then packet_alloc_skb() in linux-2.6/net/packet/af_packet.c + * then sock_alloc_send_pskb() in linux-2.6/net/core/sock.c + * but I see no way to get those sizes in userspace, + * like for instance with an ifreq ioctl(); + * the best thing I've found so far is MAX_HEADER in + * the kernel part of linux-2.6/include/linux/netdevice.h + * which goes up to 128+48=176; since pcap-linux.c + * defines a MAX_LINKHEADER_SIZE of 256 which is + * greater than that, let's use it.. maybe is it even + * large enough to directly replace macoff.. + */ + tp_hdrlen = TPACKET_ALIGN(handlep->tp_hdrlen) + sizeof(struct sockaddr_ll) ; + netoff = TPACKET_ALIGN(tp_hdrlen + (maclen < 16 ? 16 : maclen)) + tp_reserve; + /* NOTE: AFAICS tp_reserve may break the TPACKET_ALIGN + * of netoff, which contradicts + * linux-2.6/Documentation/networking/packet_mmap.txt + * documenting that: + * "- Gap, chosen so that packet data (Start+tp_net) + * aligns to TPACKET_ALIGNMENT=16" + */ + /* NOTE: in linux-2.6/include/linux/skbuff.h: + * "CPUs often take a performance hit + * when accessing unaligned memory locations" + */ + macoff = netoff - maclen; + req.tp_frame_size = TPACKET_ALIGN(macoff + frame_size); + /* + * Round the buffer size up to a multiple of the + * frame size (rather than rounding down, which + * would give a buffer smaller than our caller asked + * for, and possibly give zero frames if the requested + * buffer size is too small for one frame). + */ + req.tp_frame_nr = (handle->opt.buffer_size + req.tp_frame_size - 1)/req.tp_frame_size; + break; + +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + /* The "frames" for this are actually buffers that + * contain multiple variable-sized frames. + * + * We pick a "frame" size of MAXIMUM_SNAPLEN to leave + * enough room for at least one reasonably-sized packet + * in the "frame". */ + req.tp_frame_size = MAXIMUM_SNAPLEN; + /* + * Round the buffer size up to a multiple of the + * "frame" size (rather than rounding down, which + * would give a buffer smaller than our caller asked + * for, and possibly give zero "frames" if the requested + * buffer size is too small for one "frame"). + */ + req.tp_frame_nr = (handle->opt.buffer_size + req.tp_frame_size - 1)/req.tp_frame_size; + break; +#endif + default: + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Internal error: unknown TPACKET_ value %u", + handlep->tp_version); + return PCAP_ERROR; + } + + /* compute the minimum block size that will handle this frame. + * The block has to be page size aligned. + * The max block size allowed by the kernel is arch-dependent and + * it's not explicitly checked here. */ + req.tp_block_size = getpagesize(); + while (req.tp_block_size < req.tp_frame_size) + req.tp_block_size <<= 1; + + frames_per_block = req.tp_block_size/req.tp_frame_size; + + /* + * PACKET_TIMESTAMP was added after linux/net_tstamp.h was, + * so we check for PACKET_TIMESTAMP. We check for + * linux/net_tstamp.h just in case a system somehow has + * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might + * be unnecessary. + * + * SIOCSHWTSTAMP was introduced in the patch that introduced + * linux/net_tstamp.h, so we don't bother checking whether + * SIOCSHWTSTAMP is defined (if your Linux system has + * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your + * Linux system is badly broken). + */ +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) + /* + * If we were told to do so, ask the kernel and the driver + * to use hardware timestamps. + * + * Hardware timestamps are only supported with mmapped + * captures. + */ + if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER || + handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) { + struct hwtstamp_config hwconfig; + struct ifreq ifr; + int timesource; + + /* + * Ask for hardware time stamps on all packets, + * including transmitted packets. + */ + memset(&hwconfig, 0, sizeof(hwconfig)); + hwconfig.tx_type = HWTSTAMP_TX_ON; + hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); + ifr.ifr_data = (void *)&hwconfig; + + /* + * This may require CAP_NET_ADMIN. + */ + if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) { + switch (errno) { + + case EPERM: + /* + * Treat this as an error, as the + * user should try to run this + * with the appropriate privileges - + * and, if they can't, shouldn't + * try requesting hardware time stamps. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to set hardware timestamp failed - CAP_NET_ADMIN may be required"); + return PCAP_ERROR_PERM_DENIED; + + case EOPNOTSUPP: + case ERANGE: + /* + * Treat this as a warning, as the + * only way to fix the warning is to + * get an adapter that supports hardware + * time stamps for *all* packets. + * (ERANGE means "we support hardware + * time stamps, but for packets matching + * that particular filter", so it means + * "we don't support hardware time stamps + * for all incoming packets" here.) + * + * We'll just fall back on the standard + * host time stamps. + */ + status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP; + break; + + default: + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCSHWTSTAMP failed"); + return PCAP_ERROR; + } + } else { + /* + * Well, that worked. Now specify the type of + * hardware time stamp we want for this + * socket. + */ + if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) { + /* + * Hardware timestamp, synchronized + * with the system clock. + */ + timesource = SOF_TIMESTAMPING_SYS_HARDWARE; + } else { + /* + * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware + * timestamp, not synchronized with the + * system clock. + */ + timesource = SOF_TIMESTAMPING_RAW_HARDWARE; + } + if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP, + (void *)×ource, sizeof(timesource))) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't set PACKET_TIMESTAMP"); + return PCAP_ERROR; + } + } + } +#endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */ + + /* ask the kernel to create the ring */ +retry: + req.tp_block_nr = req.tp_frame_nr / frames_per_block; + + /* req.tp_frame_nr is requested to match frames_per_block*req.tp_block_nr */ + req.tp_frame_nr = req.tp_block_nr * frames_per_block; + +#ifdef HAVE_TPACKET3 + /* timeout value to retire block - use the configured buffering timeout, or default if <0. */ + if (handlep->timeout > 0) { + /* Use the user specified timeout as the block timeout */ + req.tp_retire_blk_tov = handlep->timeout; + } else if (handlep->timeout == 0) { + /* + * In pcap, this means "infinite timeout"; TPACKET_V3 + * doesn't support that, so just set it to UINT_MAX + * milliseconds. In the TPACKET_V3 loop, if the + * timeout is 0, and we haven't yet seen any packets, + * and we block and still don't have any packets, we + * keep blocking until we do. + */ + req.tp_retire_blk_tov = UINT_MAX; + } else { + /* + * XXX - this is not valid; use 0, meaning "have the + * kernel pick a default", for now. + */ + req.tp_retire_blk_tov = 0; + } + /* private data not used */ + req.tp_sizeof_priv = 0; + /* Rx ring - feature request bits - none (rxhash will not be filled) */ + req.tp_feature_req_word = 0; +#endif + + if (setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, + (void *) &req, sizeof(req))) { + if ((errno == ENOMEM) && (req.tp_block_nr > 1)) { + /* + * Memory failure; try to reduce the requested ring + * size. + * + * We used to reduce this by half -- do 5% instead. + * That may result in more iterations and a longer + * startup, but the user will be much happier with + * the resulting buffer size. + */ + if (req.tp_frame_nr < 20) + req.tp_frame_nr -= 1; + else + req.tp_frame_nr -= req.tp_frame_nr/20; + goto retry; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't create rx ring on packet socket"); + return PCAP_ERROR; + } + + /* memory map the rx ring */ + handlep->mmapbuflen = req.tp_block_nr * req.tp_block_size; + handlep->mmapbuf = mmap(0, handlep->mmapbuflen, + PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0); + if (handlep->mmapbuf == MAP_FAILED) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't mmap rx ring"); + + /* clear the allocated ring on error*/ + destroy_ring(handle); + return PCAP_ERROR; + } + + /* allocate a ring for each frame header pointer*/ + handle->cc = req.tp_frame_nr; + handle->buffer = malloc(handle->cc * sizeof(union thdr *)); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't allocate ring of frame headers"); + + destroy_ring(handle); + return PCAP_ERROR; + } + + /* fill the header ring with proper frame ptr*/ + handle->offset = 0; + for (i=0; immapbuf[i*req.tp_block_size]; + for (j=0; joffset) { + RING_GET_CURRENT_FRAME(handle) = base; + base += req.tp_frame_size; + } + } + + handle->bufsize = req.tp_frame_size; + handle->offset = 0; + return status; +} + +/* free all ring related resources*/ +static void +destroy_ring(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + + /* + * Tell the kernel to destroy the ring. + * We don't check for setsockopt failure, as 1) we can't recover + * from an error and 2) we might not yet have set it up in the + * first place. + */ + struct tpacket_req req; + memset(&req, 0, sizeof(req)); + (void)setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING, + (void *) &req, sizeof(req)); + + /* if ring is mapped, unmap it*/ + if (handlep->mmapbuf) { + /* do not test for mmap failure, as we can't recover from any error */ + (void)munmap(handlep->mmapbuf, handlep->mmapbuflen); + handlep->mmapbuf = NULL; + } +} + +/* + * Special one-shot callback, used for pcap_next() and pcap_next_ex(), + * for Linux mmapped capture. + * + * The problem is that pcap_next() and pcap_next_ex() expect the packet + * data handed to the callback to be valid after the callback returns, + * but pcap_read_linux_mmap() has to release that packet as soon as + * the callback returns (otherwise, the kernel thinks there's still + * at least one unprocessed packet available in the ring, so a select() + * will immediately return indicating that there's data to process), so, + * in the callback, we have to make a copy of the packet. + * + * Yes, this means that, if the capture is using the ring buffer, using + * pcap_next() or pcap_next_ex() requires more copies than using + * pcap_loop() or pcap_dispatch(). If that bothers you, don't use + * pcap_next() or pcap_next_ex(). + */ +static void +pcapint_oneshot_linux(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *)user; + pcap_t *handle = sp->pd; + struct pcap_linux *handlep = handle->priv; + + *sp->hdr = *h; + memcpy(handlep->oneshot_buffer, bytes, h->caplen); + *sp->pkt = handlep->oneshot_buffer; +} + +static int +pcap_getnonblock_linux(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + + /* use negative value of timeout to indicate non blocking ops */ + return (handlep->timeout<0); +} + +static int +pcap_setnonblock_linux(pcap_t *handle, int nonblock) +{ + struct pcap_linux *handlep = handle->priv; + + /* + * Set the file descriptor to the requested mode, as we use + * it for sending packets. + */ + if (pcapint_setnonblock_fd(handle, nonblock) == -1) + return -1; + + /* + * Map each value to their corresponding negation to + * preserve the timeout value provided with pcap_set_timeout. + */ + if (nonblock) { + /* + * We're setting the mode to non-blocking mode. + */ + if (handlep->timeout >= 0) { + /* + * Indicate that we're switching to + * non-blocking mode. + */ + handlep->timeout = ~handlep->timeout; + } + if (handlep->poll_breakloop_fd != -1) { + /* Close the eventfd; we do not need it in nonblock mode. */ + close(handlep->poll_breakloop_fd); + handlep->poll_breakloop_fd = -1; + } + } else { + /* + * We're setting the mode to blocking mode. + */ + if (handlep->poll_breakloop_fd == -1) { + /* If we did not have an eventfd, open one now that we are blocking. */ + if ( ( handlep->poll_breakloop_fd = eventfd(0, EFD_NONBLOCK) ) == -1 ) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "could not open eventfd"); + return -1; + } + } + if (handlep->timeout < 0) { + handlep->timeout = ~handlep->timeout; + } + } + /* Update the timeout to use in poll(). */ + set_poll_timeout(handlep); + return 0; +} + +/* + * Get the status field of the ring buffer frame at a specified offset. + */ +static inline u_int +pcap_get_ring_frame_status(pcap_t *handle, int offset) +{ + struct pcap_linux *handlep = handle->priv; + union thdr h; + + h.raw = RING_GET_FRAME_AT(handle, offset); + switch (handlep->tp_version) { + case TPACKET_V2: + return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE); + break; +#ifdef HAVE_TPACKET3 + case TPACKET_V3: + return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE); + break; +#endif + } + /* This should not happen. */ + return 0; +} + +/* + * Block waiting for frames to be available. + */ +static int pcap_wait_for_frames_mmap(pcap_t *handle) +{ + struct pcap_linux *handlep = handle->priv; + int timeout; + struct ifreq ifr; + int ret; + struct pollfd pollinfo[2]; + int numpollinfo; + pollinfo[0].fd = handle->fd; + pollinfo[0].events = POLLIN; + if ( handlep->poll_breakloop_fd == -1 ) { + numpollinfo = 1; + pollinfo[1].revents = 0; + /* + * We set pollinfo[1].revents to zero, even though + * numpollinfo = 1 meaning that poll() doesn't see + * pollinfo[1], so that we do not have to add a + * conditional of numpollinfo > 1 below when we + * test pollinfo[1].revents. + */ + } else { + pollinfo[1].fd = handlep->poll_breakloop_fd; + pollinfo[1].events = POLLIN; + numpollinfo = 2; + } + + /* + * Keep polling until we either get some packets to read, see + * that we got told to break out of the loop, get a fatal error, + * or discover that the device went away. + * + * In non-blocking mode, we must still do one poll() to catch + * any pending error indications, but the poll() has a timeout + * of 0, so that it doesn't block, and we quit after that one + * poll(). + * + * If we've seen an ENETDOWN, it might be the first indication + * that the device went away, or it might just be that it was + * configured down. Unfortunately, there's no guarantee that + * the device has actually been removed as an interface, because: + * + * 1) if, as appears to be the case at least some of the time, + * the PF_PACKET socket code first gets a NETDEV_DOWN indication + * for the device and then gets a NETDEV_UNREGISTER indication + * for it, the first indication will cause a wakeup with ENETDOWN + * but won't set the packet socket's field for the interface index + * to -1, and the second indication won't cause a wakeup (because + * the first indication also caused the protocol hook to be + * unregistered) but will set the packet socket's field for the + * interface index to -1; + * + * 2) even if just a NETDEV_UNREGISTER indication is registered, + * the packet socket's field for the interface index only gets + * set to -1 after the wakeup, so there's a small but non-zero + * risk that a thread blocked waiting for the wakeup will get + * to the "fetch the socket name" code before the interface index + * gets set to -1, so it'll get the old interface index. + * + * Therefore, if we got an ENETDOWN and haven't seen a packet + * since then, we assume that we might be waiting for the interface + * to disappear, and poll with a timeout to try again in a short + * period of time. If we *do* see a packet, the interface has + * come back up again, and is *definitely* still there, so we + * don't need to poll. + */ + for (;;) { + /* + * Yes, we do this even in non-blocking mode, as it's + * the only way to get error indications from a + * tpacket socket. + * + * The timeout is 0 in non-blocking mode, so poll() + * returns immediately. + */ + timeout = handlep->poll_timeout; + + /* + * If we got an ENETDOWN and haven't gotten an indication + * that the device has gone away or that the device is up, + * we don't yet know for certain whether the device has + * gone away or not, do a poll() with a 1-millisecond timeout, + * as we have to poll indefinitely for "device went away" + * indications until we either get one or see that the + * device is up. + */ + if (handlep->netdown) { + if (timeout != 0) + timeout = 1; + } + ret = poll(pollinfo, numpollinfo, timeout); + if (ret < 0) { + /* + * Error. If it's not EINTR, report it. + */ + if (errno != EINTR) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't poll on packet socket"); + return PCAP_ERROR; + } + + /* + * It's EINTR; if we were told to break out of + * the loop, do so. + */ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } else if (ret > 0) { + /* + * OK, some descriptor is ready. + * Check the socket descriptor first. + * + * As I read the Linux man page, pollinfo[0].revents + * will either be POLLIN, POLLERR, POLLHUP, or POLLNVAL. + */ + if (pollinfo[0].revents == POLLIN) { + /* + * OK, we may have packets to + * read. + */ + break; + } + if (pollinfo[0].revents != 0) { + /* + * There's some indication other than + * "you can read on this descriptor" on + * the descriptor. + */ + if (pollinfo[0].revents & POLLNVAL) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Invalid polling request on packet socket"); + return PCAP_ERROR; + } + if (pollinfo[0].revents & (POLLHUP | POLLRDHUP)) { + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Hangup on packet socket"); + return PCAP_ERROR; + } + if (pollinfo[0].revents & POLLERR) { + /* + * Get the error. + */ + int err; + socklen_t errlen; + + errlen = sizeof(err); + if (getsockopt(handle->fd, SOL_SOCKET, + SO_ERROR, &err, &errlen) == -1) { + /* + * The call *itself* returned + * an error; make *that* + * the error. + */ + err = errno; + } + + /* + * OK, we have the error. + */ + if (err == ENETDOWN) { + /* + * The device on which we're + * capturing went away or the + * interface was taken down. + * + * We don't know for certain + * which happened, and the + * next poll() may indicate + * that there are packets + * to be read, so just set + * a flag to get us to do + * checks later, and set + * the required select + * timeout to 1 millisecond + * so that event loops that + * check our socket descriptor + * also time out so that + * they can call us and we + * can do the checks. + */ + handlep->netdown = 1; + handle->required_select_timeout = &netdown_timeout; + } else if (err == 0) { + /* + * This shouldn't happen, so + * report a special indication + * that it did. + */ + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "Error condition on packet socket: Reported error was 0"); + return PCAP_ERROR; + } else { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, + err, + "Error condition on packet socket"); + return PCAP_ERROR; + } + } + } + /* + * Now check the event device. + */ + if (pollinfo[1].revents & POLLIN) { + ssize_t nread; + uint64_t value; + + /* + * This should never fail, but, just + * in case.... + */ + nread = read(handlep->poll_breakloop_fd, &value, + sizeof(value)); + if (nread == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, + errno, + "Error reading from event FD"); + return PCAP_ERROR; + } + + /* + * According to the Linux read(2) man + * page, read() will transfer at most + * 2^31-1 bytes, so the return value is + * either -1 or a value between 0 + * and 2^31-1, so it's non-negative. + * + * Cast it to size_t to squelch + * warnings from the compiler; add this + * comment to squelch warnings from + * humans reading the code. :-) + * + * Don't treat an EOF as an error, but + * *do* treat a short read as an error; + * that "shouldn't happen", but.... + */ + if (nread != 0 && + (size_t)nread < sizeof(value)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Short read from event FD: expected %zu, got %zd", + sizeof(value), nread); + return PCAP_ERROR; + } + + /* + * This event gets signaled by a + * pcap_breakloop() call; if we were told + * to break out of the loop, do so. + */ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + } + + /* + * Either: + * + * 1) we got neither an error from poll() nor any + * readable descriptors, in which case there + * are no packets waiting to read + * + * or + * + * 2) We got readable descriptors but the PF_PACKET + * socket wasn't one of them, in which case there + * are no packets waiting to read + * + * so, if we got an ENETDOWN, we've drained whatever + * packets were available to read at the point of the + * ENETDOWN. + * + * So, if we got an ENETDOWN and haven't gotten an indication + * that the device has gone away or that the device is up, + * we don't yet know for certain whether the device has + * gone away or not, check whether the device exists and is + * up. + */ + if (handlep->netdown) { + if (!device_still_exists(handle)) { + /* + * The device doesn't exist any more; + * report that. + * + * XXX - we should really return an + * appropriate error for that, but + * pcap_dispatch() etc. aren't documented + * as having error returns other than + * PCAP_ERROR or PCAP_ERROR_BREAK. + */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "The interface disappeared"); + return PCAP_ERROR; + } + + /* + * The device still exists; try to see if it's up. + */ + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, handlep->device, + sizeof(ifr.ifr_name)); + if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) { + if (errno == ENXIO || errno == ENODEV) { + /* + * OK, *now* it's gone. + * + * XXX - see above comment. + */ + snprintf(handle->errbuf, + PCAP_ERRBUF_SIZE, + "The interface disappeared"); + return PCAP_ERROR; + } else { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "%s: Can't get flags", + handlep->device); + return PCAP_ERROR; + } + } + if (ifr.ifr_flags & IFF_UP) { + /* + * It's up, so it definitely still exists. + * Cancel the ENETDOWN indication - we + * presumably got it due to the interface + * going down rather than the device going + * away - and revert to "no required select + * timeout. + */ + handlep->netdown = 0; + handle->required_select_timeout = NULL; + } + } + + /* + * If we're in non-blocking mode, just quit now, rather + * than spinning in a loop doing poll()s that immediately + * time out if there's no indication on any descriptor. + */ + if (handlep->poll_timeout == 0) + break; + } + return 0; +} + +/* handle a single memory mapped packet */ +static int pcap_handle_packet_mmap( + pcap_t *handle, + pcap_handler callback, + u_char *user, + unsigned char *frame, + unsigned int tp_len, + unsigned int tp_mac, + unsigned int tp_snaplen, + unsigned int tp_sec, + unsigned int tp_usec, + int tp_vlan_tci_valid, + __u16 tp_vlan_tci, + __u16 tp_vlan_tpid) +{ + struct pcap_linux *handlep = handle->priv; + unsigned char *bp; + struct sockaddr_ll *sll; + struct pcap_pkthdr pcaphdr; + unsigned int snaplen = tp_snaplen; + struct utsname utsname; + + /* perform sanity check on internal offset. */ + if (tp_mac + tp_snaplen > handle->bufsize) { + /* + * Report some system information as a debugging aid. + */ + if (uname(&utsname) != -1) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "corrupted frame on kernel ring mac " + "offset %u + caplen %u > frame len %d " + "(kernel %.32s version %s, machine %.16s)", + tp_mac, tp_snaplen, handle->bufsize, + utsname.release, utsname.version, + utsname.machine); + } else { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "corrupted frame on kernel ring mac " + "offset %u + caplen %u > frame len %d", + tp_mac, tp_snaplen, handle->bufsize); + } + return -1; + } + + /* run filter on received packet + * If the kernel filtering is enabled we need to run the + * filter until all the frames present into the ring + * at filter creation time are processed. + * In this case, blocks_to_filter_in_userland is used + * as a counter for the packet we need to filter. + * Note: alternatively it could be possible to stop applying + * the filter when the ring became empty, but it can possibly + * happen a lot later... */ + bp = frame + tp_mac; + + /* if required build in place the sll header*/ + sll = (void *)(frame + TPACKET_ALIGN(handlep->tp_hdrlen)); + if (handlep->cooked) { + if (handle->linktype == DLT_LINUX_SLL2) { + struct sll2_header *hdrp; + + /* + * The kernel should have left us with enough + * space for an sll header; back up the packet + * data pointer into that space, as that'll be + * the beginning of the packet we pass to the + * callback. + */ + bp -= SLL2_HDR_LEN; + + /* + * Let's make sure that's past the end of + * the tpacket header, i.e. >= + * ((u_char *)thdr + TPACKET_HDRLEN), so we + * don't step on the header when we construct + * the sll header. + */ + if (bp < (u_char *)frame + + TPACKET_ALIGN(handlep->tp_hdrlen) + + sizeof(struct sockaddr_ll)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "cooked-mode frame doesn't have room for sll header"); + return -1; + } + + /* + * OK, that worked; construct the sll header. + */ + hdrp = (struct sll2_header *)bp; + hdrp->sll2_protocol = sll->sll_protocol; + hdrp->sll2_reserved_mbz = 0; + hdrp->sll2_if_index = htonl(sll->sll_ifindex); + hdrp->sll2_hatype = htons(sll->sll_hatype); + hdrp->sll2_pkttype = sll->sll_pkttype; + hdrp->sll2_halen = sll->sll_halen; + memcpy(hdrp->sll2_addr, sll->sll_addr, SLL_ADDRLEN); + + snaplen += sizeof(struct sll2_header); + } else { + struct sll_header *hdrp; + + /* + * The kernel should have left us with enough + * space for an sll header; back up the packet + * data pointer into that space, as that'll be + * the beginning of the packet we pass to the + * callback. + */ + bp -= SLL_HDR_LEN; + + /* + * Let's make sure that's past the end of + * the tpacket header, i.e. >= + * ((u_char *)thdr + TPACKET_HDRLEN), so we + * don't step on the header when we construct + * the sll header. + */ + if (bp < (u_char *)frame + + TPACKET_ALIGN(handlep->tp_hdrlen) + + sizeof(struct sockaddr_ll)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "cooked-mode frame doesn't have room for sll header"); + return -1; + } + + /* + * OK, that worked; construct the sll header. + */ + hdrp = (struct sll_header *)bp; + hdrp->sll_pkttype = htons(sll->sll_pkttype); + hdrp->sll_hatype = htons(sll->sll_hatype); + hdrp->sll_halen = htons(sll->sll_halen); + memcpy(hdrp->sll_addr, sll->sll_addr, SLL_ADDRLEN); + hdrp->sll_protocol = sll->sll_protocol; + + snaplen += sizeof(struct sll_header); + } + } else { + /* + * If this is a packet from a CAN device, so that + * sll->sll_hatype is ARPHRD_CAN, then, as we're + * not capturing in cooked mode, its link-layer + * type is DLT_CAN_SOCKETCAN. Fix up the header + * provided by the code below us to match what + * DLT_CAN_SOCKETCAN is expected to provide. + */ + if (sll->sll_hatype == ARPHRD_CAN) { + pcap_can_socketcan_hdr *canhdr = (pcap_can_socketcan_hdr *)bp; + uint16_t protocol = ntohs(sll->sll_protocol); + + /* + * Check the protocol field from the sll header. + * If it's one of the known CAN protocol types, + * make sure the appropriate flags are set, so + * that a program can tell what type of frame + * it is. + * + * The two flags are: + * + * CANFD_FDF, which is in the fd_flags field + * of the CAN classic/CAN FD header; + * + * CANXL_XLF, which is in the flags field + * of the CAN XL header, which overlaps + * the payload_length field of the CAN + * classic/CAN FD header. + */ + switch (protocol) { + + case LINUX_SLL_P_CAN: + /* + * CAN classic. + * + * Zero out the fd_flags and reserved + * fields, in case they're uninitialized + * crap, and clear the CANXL_XLF bit in + * the payload_length field. + * + * This means that the CANFD_FDF flag isn't + * set in the fd_flags field, and that + * the CANXL_XLF bit isn't set in the + * payload_length field, so this frame + * will appear to be a CAN classic frame. + */ + canhdr->payload_length &= ~CANXL_XLF; + canhdr->fd_flags = 0; + canhdr->reserved1 = 0; + canhdr->reserved2 = 0; + break; + + case LINUX_SLL_P_CANFD: + /* + * Set CANFD_FDF in the fd_flags field, + * and clear the CANXL_XLF bit in the + * payload_length field, so this frame + * will appear to be a CAN FD frame. + */ + canhdr->payload_length &= ~CANXL_XLF; + canhdr->fd_flags |= CANFD_FDF; + + /* + * Zero out all the unknown bits in fd_flags + * and clear the reserved fields, so that + * a program reading this can assume that + * CANFD_FDF is set because we set it, not + * because some uninitialized crap was + * provided in the fd_flags field. + * + * (At least some LINKTYPE_CAN_SOCKETCAN + * files attached to Wireshark bugs had + * uninitialized junk there, so it does + * happen.) + * + * Update this if Linux adds more flag bits + * to the fd_flags field or uses either of + * the reserved fields for FD frames. + */ + canhdr->fd_flags &= (CANFD_FDF|CANFD_ESI|CANFD_BRS); + canhdr->reserved1 = 0; + canhdr->reserved2 = 0; + break; + + case LINUX_SLL_P_CANXL: + /* + * CAN XL frame. + * + * Make sure the CANXL_XLF bit is set in + * the payload_length field, so that + * this frame will appear to be a + * CAN XL frame. + */ + canhdr->payload_length |= CANXL_XLF; + break; + } + + /* + * Put multi-byte header fields in a byte-order + *-independent format. + */ + if (canhdr->payload_length & CANXL_XLF) { + /* + * This is a CAN XL frame. + * + * DLT_CAN_SOCKETCAN is specified as having + * the Priority ID/VCID field in big-- + * endian byte order, and the payload length + * and Acceptance Field in little-endian byte + * order. but capturing on a CAN device + * provides them in host byte order. + * Convert them to the appropriate byte + * orders. + * + * The reason we put the first field + * into big-endian byte order is that + * older libpcap code, ignorant of + * CAN XL, treated it as the CAN ID + * field and put it into big-endian + * byte order, and we don't want to + * break code that understands CAN XL + * headers, and treats that field as + * being big-endian. + * + * The other fields are put in little- + * endian byte order is that older + * libpcap code, ignorant of CAN XL, + * left those fields alone, and the + * processors on which the CAN XL + * frames were captured are likely + * to be little-endian processors. + */ + pcap_can_socketcan_xl_hdr *canxl_hdr = (pcap_can_socketcan_xl_hdr *)bp; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + /* + * We're capturing on a little-endian + * machine, so we put the priority/VCID + * field into big-endian byte order, and + * leave the payload length and acceptance + * field in little-endian byte order. + */ + /* Byte-swap priority/VCID. */ + canxl_hdr->priority_vcid = SWAPLONG(canxl_hdr->priority_vcid); +#elif __BYTE_ORDER == __BIG_ENDIAN + /* + * We're capturing on a big-endian + * machine, so we want to leave the + * priority/VCID field alone, and byte-swap + * the payload length and acceptance + * fields to little-endian. + */ + /* Byte-swap the payload length */ + canxl_hdr->payload_length = SWAPSHORT(canxl_hdr->payload_length); + + /* + * Byte-swap the acceptance field. + * + * XXX - is it just a 4-octet string, + * not in any byte order? + */ + canxl_hdr->acceptance_field = SWAPLONG(canxl_hdr->acceptance_field); +#else +#error "Unknown byte order" +#endif + } else { + /* + * CAN or CAN FD frame. + * + * DLT_CAN_SOCKETCAN is specified as having + * the CAN ID and flags in network byte + * order, but capturing on a CAN device + * provides it in host byte order. Convert + * it to network byte order. + */ + canhdr->can_id = htonl(canhdr->can_id); + } + } + } + + if (handlep->filter_in_userland && handle->fcode.bf_insns) { + struct pcap_bpf_aux_data aux_data; + + aux_data.vlan_tag_present = tp_vlan_tci_valid; + aux_data.vlan_tag = tp_vlan_tci & 0x0fff; + + if (pcapint_filter_with_aux_data(handle->fcode.bf_insns, + bp, + tp_len, + snaplen, + &aux_data) == 0) + return 0; + } + + if (!linux_check_direction(handle, sll)) + return 0; + + /* get required packet info from ring header */ + pcaphdr.ts.tv_sec = tp_sec; + pcaphdr.ts.tv_usec = tp_usec; + pcaphdr.caplen = tp_snaplen; + pcaphdr.len = tp_len; + + /* if required build in place the sll header*/ + if (handlep->cooked) { + /* update packet len */ + if (handle->linktype == DLT_LINUX_SLL2) { + pcaphdr.caplen += SLL2_HDR_LEN; + pcaphdr.len += SLL2_HDR_LEN; + } else { + pcaphdr.caplen += SLL_HDR_LEN; + pcaphdr.len += SLL_HDR_LEN; + } + } + + if (tp_vlan_tci_valid && + handlep->vlan_offset != -1 && + tp_snaplen >= (unsigned int) handlep->vlan_offset) + { + struct vlan_tag *tag; + + /* + * Move everything in the header, except the type field, + * down VLAN_TAG_LEN bytes, to allow us to insert the + * VLAN tag between that stuff and the type field. + */ + bp -= VLAN_TAG_LEN; + memmove(bp, bp + VLAN_TAG_LEN, handlep->vlan_offset); + + /* + * Now insert the tag. + */ + tag = (struct vlan_tag *)(bp + handlep->vlan_offset); + tag->vlan_tpid = htons(tp_vlan_tpid); + tag->vlan_tci = htons(tp_vlan_tci); + + /* + * Add the tag to the packet lengths. + */ + pcaphdr.caplen += VLAN_TAG_LEN; + pcaphdr.len += VLAN_TAG_LEN; + } + + /* + * The only way to tell the kernel to cut off the + * packet at a snapshot length is with a filter program; + * if there's no filter program, the kernel won't cut + * the packet off. + * + * Trim the snapshot length to be no longer than the + * specified snapshot length. + * + * XXX - an alternative is to put a filter, consisting + * of a "ret " instruction, on the socket + * in the activate routine, so that the truncation is + * done in the kernel even if nobody specified a filter; + * that means that less buffer space is consumed in + * the memory-mapped buffer. + */ + if (pcaphdr.caplen > (bpf_u_int32)handle->snapshot) + pcaphdr.caplen = handle->snapshot; + + /* pass the packet to the user */ + callback(user, &pcaphdr, bp); + + return 1; +} + +static int +pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + union thdr h; + int pkts = 0; + int ret; + + /* wait for frames availability.*/ + h.raw = RING_GET_CURRENT_FRAME(handle); + if (!packet_mmap_acquire(h.h2)) { + /* + * The current frame is owned by the kernel; wait for + * a frame to be handed to us. + */ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + } + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(max_packets)) + max_packets = INT_MAX; + + while (pkts < max_packets) { + /* + * Get the current ring buffer frame, and break if + * it's still owned by the kernel. + */ + h.raw = RING_GET_CURRENT_FRAME(handle); + if (!packet_mmap_acquire(h.h2)) + break; + + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + h.raw, + h.h2->tp_len, + h.h2->tp_mac, + h.h2->tp_snaplen, + h.h2->tp_sec, + handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? h.h2->tp_nsec : h.h2->tp_nsec / 1000, + VLAN_VALID(h.h2, h.h2), + h.h2->tp_vlan_tci, + VLAN_TPID(h.h2, h.h2)); + if (ret == 1) { + pkts++; + } else if (ret < 0) { + return ret; + } + + /* + * Hand this block back to the kernel, and, if we're + * counting blocks that need to be filtered in userland + * after having been filtered by the kernel, count + * the one we've just processed. + */ + packet_mmap_release(h.h2); + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + return pkts; +} + +#ifdef HAVE_TPACKET3 +static int +pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, + u_char *user) +{ + struct pcap_linux *handlep = handle->priv; + union thdr h; + int pkts = 0; + int ret; + +again: + if (handlep->current_packet == NULL) { + /* wait for frames availability.*/ + h.raw = RING_GET_CURRENT_FRAME(handle); + if (!packet_mmap_v3_acquire(h.h3)) { + /* + * The current frame is owned by the kernel; wait + * for a frame to be handed to us. + */ + ret = pcap_wait_for_frames_mmap(handle); + if (ret) { + return ret; + } + } + } + h.raw = RING_GET_CURRENT_FRAME(handle); + if (!packet_mmap_v3_acquire(h.h3)) { + if (pkts == 0 && handlep->timeout == 0) { + /* Block until we see a packet. */ + goto again; + } + return pkts; + } + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(max_packets)) + max_packets = INT_MAX; + + while (pkts < max_packets) { + int packets_to_read; + + if (handlep->current_packet == NULL) { + h.raw = RING_GET_CURRENT_FRAME(handle); + if (!packet_mmap_v3_acquire(h.h3)) + break; + + handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt; + handlep->packets_left = h.h3->hdr.bh1.num_pkts; + } + packets_to_read = handlep->packets_left; + + if (packets_to_read > (max_packets - pkts)) { + /* + * There are more packets in the buffer than + * the number of packets we have left to + * process to get up to the maximum number + * of packets to process. Only process enough + * of them to get us up to that maximum. + */ + packets_to_read = max_packets - pkts; + } + + while (packets_to_read-- && !handle->break_loop) { + struct tpacket3_hdr* tp3_hdr = (struct tpacket3_hdr*) handlep->current_packet; + ret = pcap_handle_packet_mmap( + handle, + callback, + user, + handlep->current_packet, + tp3_hdr->tp_len, + tp3_hdr->tp_mac, + tp3_hdr->tp_snaplen, + tp3_hdr->tp_sec, + handle->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? tp3_hdr->tp_nsec : tp3_hdr->tp_nsec / 1000, + VLAN_VALID(tp3_hdr, &tp3_hdr->hv1), + tp3_hdr->hv1.tp_vlan_tci, + VLAN_TPID(tp3_hdr, &tp3_hdr->hv1)); + if (ret == 1) { + pkts++; + } else if (ret < 0) { + handlep->current_packet = NULL; + return ret; + } + handlep->current_packet += tp3_hdr->tp_next_offset; + handlep->packets_left--; + } + + if (handlep->packets_left <= 0) { + /* + * Hand this block back to the kernel, and, if + * we're counting blocks that need to be + * filtered in userland after having been + * filtered by the kernel, count the one we've + * just processed. + */ + packet_mmap_v3_release(h.h3); + if (handlep->blocks_to_filter_in_userland > 0) { + handlep->blocks_to_filter_in_userland--; + if (handlep->blocks_to_filter_in_userland == 0) { + /* + * No more blocks need to be filtered + * in userland. + */ + handlep->filter_in_userland = 0; + } + } + + /* next block */ + if (++handle->offset >= handle->cc) + handle->offset = 0; + + handlep->current_packet = NULL; + } + + /* check for break loop condition*/ + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + if (pkts == 0 && handlep->timeout == 0) { + /* Block until we see a packet. */ + goto again; + } + return pkts; +} +#endif /* HAVE_TPACKET3 */ + +/* + * Attach the given BPF code to the packet capture device. + */ +static int +pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter) +{ + struct pcap_linux *handlep; + struct sock_fprog fcode; + int can_filter_in_kernel; + int err = 0; + int n, offset; + + if (!handle) + return -1; + if (!filter) { + pcapint_strlcpy(handle->errbuf, "setfilter: No filter specified", + PCAP_ERRBUF_SIZE); + return -1; + } + + handlep = handle->priv; + + /* Make our private copy of the filter */ + + if (pcapint_install_bpf_program(handle, filter) < 0) + /* pcapint_install_bpf_program() filled in errbuf */ + return -1; + + /* + * Run user level packet filter by default. Will be overridden if + * installing a kernel filter succeeds. + */ + handlep->filter_in_userland = 1; + + /* Install kernel level filter if possible */ + +#ifdef USHRT_MAX + if (handle->fcode.bf_len > USHRT_MAX) { + /* + * fcode.len is an unsigned short for current kernel. + * I have yet to see BPF-Code with that much + * instructions but still it is possible. So for the + * sake of correctness I added this check. + */ + fprintf(stderr, "Warning: Filter too complex for kernel\n"); + fcode.len = 0; + fcode.filter = NULL; + can_filter_in_kernel = 0; + } else +#endif /* USHRT_MAX */ + { + /* + * Oh joy, the Linux kernel uses struct sock_fprog instead + * of struct bpf_program and of course the length field is + * of different size. Pointed out by Sebastian + * + * Oh, and we also need to fix it up so that all "ret" + * instructions with non-zero operands have MAXIMUM_SNAPLEN + * as the operand if we're not capturing in memory-mapped + * mode, and so that, if we're in cooked mode, all memory- + * reference instructions use special magic offsets in + * references to the link-layer header and assume that the + * link-layer payload begins at 0; "fix_program()" will do + * that. + */ + switch (fix_program(handle, &fcode)) { + + case -1: + default: + /* + * Fatal error; just quit. + * (The "default" case shouldn't happen; we + * return -1 for that reason.) + */ + return -1; + + case 0: + /* + * The program performed checks that we can't make + * work in the kernel. + */ + can_filter_in_kernel = 0; + break; + + case 1: + /* + * We have a filter that'll work in the kernel. + */ + can_filter_in_kernel = 1; + break; + } + } + + /* + * NOTE: at this point, we've set both the "len" and "filter" + * fields of "fcode". As of the 2.6.32.4 kernel, at least, + * those are the only members of the "sock_fprog" structure, + * so we initialize every member of that structure. + * + * If there is anything in "fcode" that is not initialized, + * it is either a field added in a later kernel, or it's + * padding. + * + * If a new field is added, this code needs to be updated + * to set it correctly. + * + * If there are no other fields, then: + * + * if the Linux kernel looks at the padding, it's + * buggy; + * + * if the Linux kernel doesn't look at the padding, + * then if some tool complains that we're passing + * uninitialized data to the kernel, then the tool + * is buggy and needs to understand that it's just + * padding. + */ + if (can_filter_in_kernel) { + if ((err = set_kernel_filter(handle, &fcode)) == 0) + { + /* + * Installation succeeded - using kernel filter, + * so userland filtering not needed. + */ + handlep->filter_in_userland = 0; + } + else if (err == -1) /* Non-fatal error */ + { + /* + * Print a warning if we weren't able to install + * the filter for a reason other than "this kernel + * isn't configured to support socket filters. + */ + if (errno == ENOMEM) { + /* + * Either a kernel memory allocation + * failure occurred, or there's too + * much "other/option memory" allocated + * for this socket. Suggest that they + * increase the "other/option memory" + * limit. + */ + fprintf(stderr, + "Warning: Couldn't allocate kernel memory for filter: try increasing net.core.optmem_max with sysctl\n"); + } else if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) { + fprintf(stderr, + "Warning: Kernel filter failed: %s\n", + pcap_strerror(errno)); + } + } + } + + /* + * If we're not using the kernel filter, get rid of any kernel + * filter that might've been there before, e.g. because the + * previous filter could work in the kernel, or because some other + * code attached a filter to the socket by some means other than + * calling "pcap_setfilter()". Otherwise, the kernel filter may + * filter out packets that would pass the new userland filter. + */ + if (handlep->filter_in_userland) { + if (reset_kernel_filter(handle) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't remove kernel filter"); + err = -2; /* fatal error */ + } + } + + /* + * Free up the copy of the filter that was made by "fix_program()". + */ + if (fcode.filter != NULL) + free(fcode.filter); + + if (err == -2) + /* Fatal error */ + return -1; + + /* + * If we're filtering in userland, there's nothing to do; + * the new filter will be used for the next packet. + */ + if (handlep->filter_in_userland) + return 0; + + /* + * We're filtering in the kernel; the packets present in + * all blocks currently in the ring were already filtered + * by the old filter, and so will need to be filtered in + * userland by the new filter. + * + * Get an upper bound for the number of such blocks; first, + * walk the ring backward and count the free blocks. + */ + offset = handle->offset; + if (--offset < 0) + offset = handle->cc - 1; + for (n=0; n < handle->cc; ++n) { + if (--offset < 0) + offset = handle->cc - 1; + if (pcap_get_ring_frame_status(handle, offset) != TP_STATUS_KERNEL) + break; + } + + /* + * If we found free blocks, decrement the count of free + * blocks by 1, just in case we lost a race with another + * thread of control that was adding a packet while + * we were counting and that had run the filter before + * we changed it. + * + * XXX - could there be more than one block added in + * this fashion? + * + * XXX - is there a way to avoid that race, e.g. somehow + * wait for all packets that passed the old filter to + * be added to the ring? + */ + if (n != 0) + n--; + + /* + * Set the count of blocks worth of packets to filter + * in userland to the total number of blocks in the + * ring minus the number of free blocks we found, and + * turn on userland filtering. (The count of blocks + * worth of packets to filter in userland is guaranteed + * not to be zero - n, above, couldn't be set to a + * value > handle->cc, and if it were equal to + * handle->cc, it wouldn't be zero, and thus would + * be decremented to handle->cc - 1.) + */ + handlep->blocks_to_filter_in_userland = handle->cc - n; + handlep->filter_in_userland = 1; + + return 0; +} + +/* + * Return the index of the given device name. Fill ebuf and return + * -1 on failure. + */ +static int +iface_get_id(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFINDEX"); + return -1; + } + + return ifr.ifr_ifindex; +} + +/* + * Bind the socket associated with FD to the given device. + * Return 0 on success or a PCAP_ERROR_ value on a hard error. + */ +static int +iface_bind(int fd, int ifindex, char *ebuf, int protocol) +{ + struct sockaddr_ll sll; + int ret, err; + socklen_t errlen = sizeof(err); + + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifindex < 0 ? 0 : ifindex; + sll.sll_protocol = protocol; + + if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) { + if (errno == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } + if (errno == ENODEV) { + /* + * There's nothing more to say, so clear the + * error message. + */ + ebuf[0] = '\0'; + ret = PCAP_ERROR_NO_SUCH_DEVICE; + } else { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "bind"); + } + return ret; + } + + /* Any pending errors, e.g., network is down? */ + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "getsockopt (SO_ERROR)"); + return PCAP_ERROR; + } + + if (err == ENETDOWN) { + /* + * Return a "network down" indication, so that + * the application can report that rather than + * saying we had a mysterious failure and + * suggest that they report a problem to the + * libpcap developers. + */ + return PCAP_ERROR_IFACE_NOT_UP; + } else if (err > 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + err, "bind"); + return PCAP_ERROR; + } + + return 0; +} + +/* + * Try to enter monitor mode. + * If we have libnl, try to create a new monitor-mode device and + * capture on that; otherwise, just say "not supported". + */ +#ifdef HAVE_LIBNL +static int +enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device) +{ + struct pcap_linux *handlep = handle->priv; + int ret; + char phydev_path[PATH_MAX+1]; + struct nl80211_state nlstate; + struct ifreq ifr; + u_int n; + + /* + * Is this a mac80211 device? + */ + ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX); + if (ret < 0) + return ret; /* error */ + if (ret == 0) + return 0; /* no error, but not mac80211 device */ + + /* + * XXX - is this already a monN device? + * If so, we're done. + */ + + /* + * OK, it's apparently a mac80211 device. + * Try to find an unused monN device for it. + */ + ret = nl80211_init(handle, &nlstate, device); + if (ret != 0) + return ret; + for (n = 0; n < UINT_MAX; n++) { + /* + * Try mon{n}. + */ + char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */ + + snprintf(mondevice, sizeof mondevice, "mon%u", n); + ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice); + if (ret == 1) { + /* + * Success. We don't clean up the libnl state + * yet, as we'll be using it later. + */ + goto added; + } + if (ret < 0) { + /* + * Hard failure. Just return ret; handle->errbuf + * has already been set. + */ + nl80211_cleanup(&nlstate); + return ret; + } + } + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "%s: No free monN interfaces", device); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + +added: + +#if 0 + /* + * Sleep for .1 seconds. + */ + delay.tv_sec = 0; + delay.tv_nsec = 500000000; + nanosleep(&delay, NULL); +#endif + + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!pcapint_do_addexit(handle)) { + /* + * "atexit()" failed; don't put the interface + * in rfmon mode, just give up. + */ + del_mon_if(handle, sock_fd, &nlstate, device, + handlep->mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + + /* + * Now configure the monitor interface up. + */ + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, handlep->mondevice, sizeof(ifr.ifr_name)); + if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s: Can't get flags for %s", device, + handlep->mondevice); + del_mon_if(handle, sock_fd, &nlstate, device, + handlep->mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + ifr.ifr_flags |= IFF_UP|IFF_RUNNING; + if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s: Can't set flags for %s", device, + handlep->mondevice); + del_mon_if(handle, sock_fd, &nlstate, device, + handlep->mondevice); + nl80211_cleanup(&nlstate); + return PCAP_ERROR; + } + + /* + * Success. Clean up the libnl state. + */ + nl80211_cleanup(&nlstate); + + /* + * Note that we have to delete the monitor device when we close + * the handle. + */ + handlep->must_do_on_close |= MUST_DELETE_MONIF; + + /* + * Add this to the list of pcaps to close when we exit. + */ + pcapint_add_to_pcaps_to_close(handle); + + return 1; +} +#else /* HAVE_LIBNL */ +static int +enter_rfmon_mode(pcap_t *handle _U_, int sock_fd _U_, const char *device _U_) +{ + /* + * We don't have libnl, so we can't do monitor mode. + */ + return 0; +} +#endif /* HAVE_LIBNL */ + +#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) +/* + * Map SOF_TIMESTAMPING_ values to PCAP_TSTAMP_ values. + */ +static const struct { + int soft_timestamping_val; + int pcap_tstamp_val; +} sof_ts_type_map[3] = { + { SOF_TIMESTAMPING_SOFTWARE, PCAP_TSTAMP_HOST }, + { SOF_TIMESTAMPING_SYS_HARDWARE, PCAP_TSTAMP_ADAPTER }, + { SOF_TIMESTAMPING_RAW_HARDWARE, PCAP_TSTAMP_ADAPTER_UNSYNCED } +}; +#define NUM_SOF_TIMESTAMPING_TYPES (sizeof sof_ts_type_map / sizeof sof_ts_type_map[0]) + +/* + * Set the list of time stamping types to include all types. + */ +static int +iface_set_all_ts_types(pcap_t *handle, char *ebuf) +{ + u_int i; + + handle->tstamp_type_list = malloc(NUM_SOF_TIMESTAMPING_TYPES * sizeof(u_int)); + if (handle->tstamp_type_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) + handle->tstamp_type_list[i] = sof_ts_type_map[i].pcap_tstamp_val; + handle->tstamp_type_count = NUM_SOF_TIMESTAMPING_TYPES; + return 0; +} + +/* + * Get a list of time stamp types. + */ +#ifdef ETHTOOL_GET_TS_INFO +static int +iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf) +{ + int fd; + struct ifreq ifr; + struct ethtool_ts_info info; + int num_ts_types; + u_int i, j; + + /* + * This doesn't apply to the "any" device; you can't say "turn on + * hardware time stamping for all devices that exist now and arrange + * that it be turned on for any device that appears in the future", + * and not all devices even necessarily *support* hardware time + * stamping, so don't report any time stamp types. + */ + if (strcmp(device, "any") == 0) { + handle->tstamp_type_list = NULL; + return 0; + } + + /* + * Create a socket from which to fetch time stamping capabilities. + */ + fd = get_if_ioctl_socket(); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "socket for SIOCETHTOOL(ETHTOOL_GET_TS_INFO)"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GET_TS_INFO; + ifr.ifr_data = (caddr_t)&info; + if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { + int save_errno = errno; + + close(fd); + switch (save_errno) { + + case EOPNOTSUPP: + case EINVAL: + /* + * OK, this OS version or driver doesn't support + * asking for the time stamping types, so let's + * just return all the possible types. + */ + if (iface_set_all_ts_types(handle, ebuf) == -1) + return -1; + return 0; + + case ENODEV: + /* + * OK, no such device. + * The user will find that out when they try to + * activate the device; just return an empty + * list of time stamp types. + */ + handle->tstamp_type_list = NULL; + return 0; + + default: + /* + * Other error. + */ + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + save_errno, + "%s: SIOCETHTOOL(ETHTOOL_GET_TS_INFO) ioctl failed", + device); + return -1; + } + } + close(fd); + + /* + * Do we support hardware time stamping of *all* packets? + */ + if (!(info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))) { + /* + * No, so don't report any time stamp types. + * + * XXX - some devices either don't report + * HWTSTAMP_FILTER_ALL when they do support it, or + * report HWTSTAMP_FILTER_ALL but map it to only + * time stamping a few PTP packets. See + * http://marc.info/?l=linux-netdev&m=146318183529571&w=2 + * + * Maybe that got fixed later. + */ + handle->tstamp_type_list = NULL; + return 0; + } + + num_ts_types = 0; + for (i = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { + if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) + num_ts_types++; + } + if (num_ts_types != 0) { + handle->tstamp_type_list = malloc(num_ts_types * sizeof(u_int)); + if (handle->tstamp_type_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + for (i = 0, j = 0; i < NUM_SOF_TIMESTAMPING_TYPES; i++) { + if (info.so_timestamping & sof_ts_type_map[i].soft_timestamping_val) { + handle->tstamp_type_list[j] = sof_ts_type_map[i].pcap_tstamp_val; + j++; + } + } + handle->tstamp_type_count = num_ts_types; + } else + handle->tstamp_type_list = NULL; + + return 0; +} +#else /* ETHTOOL_GET_TS_INFO */ +static int +iface_get_ts_types(const char *device, pcap_t *handle, char *ebuf) +{ + /* + * This doesn't apply to the "any" device; you can't say "turn on + * hardware time stamping for all devices that exist now and arrange + * that it be turned on for any device that appears in the future", + * and not all devices even necessarily *support* hardware time + * stamping, so don't report any time stamp types. + */ + if (strcmp(device, "any") == 0) { + handle->tstamp_type_list = NULL; + return 0; + } + + /* + * We don't have an ioctl to use to ask what's supported, + * so say we support everything. + */ + if (iface_set_all_ts_types(handle, ebuf) == -1) + return -1; + return 0; +} +#endif /* ETHTOOL_GET_TS_INFO */ +#else /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ +static int +iface_get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_) +{ + /* + * Nothing to fetch, so it always "succeeds". + */ + return 0; +} +#endif /* defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP) */ + +/* + * Find out if we have any form of fragmentation/reassembly offloading. + * + * We do so using SIOCETHTOOL checking for various types of offloading; + * if SIOCETHTOOL isn't defined, or we don't have any #defines for any + * of the types of offloading, there's nothing we can do to check, so + * we just say "no, we don't". + * + * We treat EOPNOTSUPP, EINVAL and, if eperm_ok is true, EPERM as + * indications that the operation isn't supported. We do EPERM + * weirdly because the SIOCETHTOOL code in later kernels 1) doesn't + * support ETHTOOL_GUFO, 2) also doesn't include it in the list + * of ethtool operations that don't require CAP_NET_ADMIN privileges, + * and 3) does the "is this permitted" check before doing the "is + * this even supported" check, so it fails with "this is not permitted" + * rather than "this is not even supported". To work around this + * annoyance, we only treat EPERM as an error for the first feature, + * and assume that they all do the same permission checks, so if the + * first one is allowed all the others are allowed if supported. + */ +#if defined(SIOCETHTOOL) && (defined(ETHTOOL_GTSO) || defined(ETHTOOL_GUFO) || defined(ETHTOOL_GGSO) || defined(ETHTOOL_GFLAGS) || defined(ETHTOOL_GGRO)) +static int +iface_ethtool_flag_ioctl(pcap_t *handle, int cmd, const char *cmdname, + int eperm_ok) +{ + struct ifreq ifr; + struct ethtool_value eval; + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, handle->opt.device, sizeof(ifr.ifr_name)); + eval.cmd = cmd; + eval.data = 0; + ifr.ifr_data = (caddr_t)&eval; + if (ioctl(handle->fd, SIOCETHTOOL, &ifr) == -1) { + if (errno == EOPNOTSUPP || errno == EINVAL || + (errno == EPERM && eperm_ok)) { + /* + * OK, let's just return 0, which, in our + * case, either means "no, what we're asking + * about is not enabled" or "all the flags + * are clear (i.e., nothing is enabled)". + */ + return 0; + } + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s: SIOCETHTOOL(%s) ioctl failed", + handle->opt.device, cmdname); + return -1; + } + return eval.data; +} + +/* + * XXX - it's annoying that we have to check for offloading at all, but, + * given that we have to, it's still annoying that we have to check for + * particular types of offloading, especially that shiny new types of + * offloading may be added - and, worse, may not be checkable with + * a particular ETHTOOL_ operation; ETHTOOL_GFEATURES would, in + * theory, give those to you, but the actual flags being used are + * opaque (defined in a non-uapi header), and there doesn't seem to + * be any obvious way to ask the kernel what all the offloading flags + * are - at best, you can ask for a set of strings(!) to get *names* + * for various flags. (That whole mechanism appears to have been + * designed for the sole purpose of letting ethtool report flags + * by name and set flags by name, with the names having no semantics + * ethtool understands.) + */ +static int +iface_get_offload(pcap_t *handle) +{ + int ret; + +#ifdef ETHTOOL_GTSO + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GTSO, "ETHTOOL_GTSO", 0); + if (ret == -1) + return -1; + if (ret) + return 1; /* TCP segmentation offloading on */ +#endif + +#ifdef ETHTOOL_GGSO + /* + * XXX - will this cause large unsegmented packets to be + * handed to PF_PACKET sockets on transmission? If not, + * this need not be checked. + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGSO, "ETHTOOL_GGSO", 0); + if (ret == -1) + return -1; + if (ret) + return 1; /* generic segmentation offloading on */ +#endif + +#ifdef ETHTOOL_GFLAGS + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GFLAGS, "ETHTOOL_GFLAGS", 0); + if (ret == -1) + return -1; + if (ret & ETH_FLAG_LRO) + return 1; /* large receive offloading on */ +#endif + +#ifdef ETHTOOL_GGRO + /* + * XXX - will this cause large reassembled packets to be + * handed to PF_PACKET sockets on receipt? If not, + * this need not be checked. + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GGRO, "ETHTOOL_GGRO", 0); + if (ret == -1) + return -1; + if (ret) + return 1; /* generic (large) receive offloading on */ +#endif + +#ifdef ETHTOOL_GUFO + /* + * Do this one last, as support for it was removed in later + * kernels, and it fails with EPERM on those kernels rather + * than with EOPNOTSUPP (see explanation in comment for + * iface_ethtool_flag_ioctl()). + */ + ret = iface_ethtool_flag_ioctl(handle, ETHTOOL_GUFO, "ETHTOOL_GUFO", 1); + if (ret == -1) + return -1; + if (ret) + return 1; /* UDP fragmentation offloading on */ +#endif + + return 0; +} +#else /* SIOCETHTOOL */ +static int +iface_get_offload(pcap_t *handle _U_) +{ + /* + * XXX - do we need to get this information if we don't + * have the ethtool ioctls? If so, how do we do that? + */ + return 0; +} +#endif /* SIOCETHTOOL */ + +static struct dsa_proto { + const char *name; + bpf_u_int32 linktype; +} dsa_protos[] = { + /* + * None is special and indicates that the interface does not have + * any tagging protocol configured, and is therefore a standard + * Ethernet interface. + */ + { "none", DLT_EN10MB }, + { "brcm", DLT_DSA_TAG_BRCM }, + { "brcm-prepend", DLT_DSA_TAG_BRCM_PREPEND }, + { "dsa", DLT_DSA_TAG_DSA }, + { "edsa", DLT_DSA_TAG_EDSA }, +}; + +static int +iface_dsa_get_proto_info(const char *device, pcap_t *handle) +{ + char *pathstr; + unsigned int i; + /* + * Make this significantly smaller than PCAP_ERRBUF_SIZE; + * the tag *shouldn't* have some huge long name, and making + * it smaller keeps newer versions of GCC from whining that + * the error message if we don't support the tag could + * overflow the error message buffer. + */ + char buf[128]; + ssize_t r; + int fd; + + fd = asprintf(&pathstr, "/sys/class/net/%s/dsa/tagging", device); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + fd, "asprintf"); + return PCAP_ERROR; + } + + fd = open(pathstr, O_RDONLY); + free(pathstr); + /* + * This is not fatal, kernel >= 4.20 *might* expose this attribute + */ + if (fd < 0) + return 0; + + r = read(fd, buf, sizeof(buf) - 1); + if (r <= 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "read"); + close(fd); + return PCAP_ERROR; + } + close(fd); + + /* + * Buffer should be LF terminated. + */ + if (buf[r - 1] == '\n') + r--; + buf[r] = '\0'; + + for (i = 0; i < sizeof(dsa_protos) / sizeof(dsa_protos[0]); i++) { + if (strlen(dsa_protos[i].name) == (size_t)r && + strcmp(buf, dsa_protos[i].name) == 0) { + handle->linktype = dsa_protos[i].linktype; + switch (dsa_protos[i].linktype) { + case DLT_EN10MB: + return 0; + default: + return 1; + } + } + } + + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "unsupported DSA tag: %s", buf); + + return PCAP_ERROR; +} + +/* + * Query the kernel for the MTU of the given interface. + */ +static int +iface_get_mtu(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + + if (!device) + return BIGGER_THAN_ALL_MTUS; + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMTU"); + return -1; + } + + return ifr.ifr_mtu; +} + +/* + * Get the hardware type of the given interface as ARPHRD_xxx constant. + */ +static int +iface_get_arptype(int fd, const char *device, char *ebuf) +{ + struct ifreq ifr; + int ret; + + memset(&ifr, 0, sizeof(ifr)); + pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { + if (errno == ENODEV) { + /* + * No such device. + * + * There's nothing more to say, so clear + * the error message. + */ + ret = PCAP_ERROR_NO_SUCH_DEVICE; + ebuf[0] = '\0'; + } else { + ret = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFHWADDR"); + } + return ret; + } + + return ifr.ifr_hwaddr.sa_family; +} + +static int +fix_program(pcap_t *handle, struct sock_fprog *fcode) +{ + struct pcap_linux *handlep = handle->priv; + size_t prog_size; + register int i; + register struct bpf_insn *p; + struct bpf_insn *f; + int len; + + /* + * Make a copy of the filter, and modify that copy if + * necessary. + */ + prog_size = sizeof(*handle->fcode.bf_insns) * handle->fcode.bf_len; + len = handle->fcode.bf_len; + f = (struct bpf_insn *)malloc(prog_size); + if (f == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + memcpy(f, handle->fcode.bf_insns, prog_size); + fcode->len = len; + fcode->filter = (struct sock_filter *) f; + + for (i = 0; i < len; ++i) { + p = &f[i]; + /* + * What type of instruction is this? + */ + switch (BPF_CLASS(p->code)) { + + case BPF_LD: + case BPF_LDX: + /* + * It's a load instruction; is it loading + * from the packet? + */ + switch (BPF_MODE(p->code)) { + + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + /* + * Yes; are we in cooked mode? + */ + if (handlep->cooked) { + /* + * Yes, so we need to fix this + * instruction. + */ + if (fix_offset(handle, p) < 0) { + /* + * We failed to do so. + * Return 0, so our caller + * knows to punt to userland. + */ + return 0; + } + } + break; + } + break; + } + } + return 1; /* we succeeded */ +} + +static int +fix_offset(pcap_t *handle, struct bpf_insn *p) +{ + /* + * Existing references to auxiliary data shouldn't be adjusted. + * + * Note that SKF_AD_OFF is negative, but p->k is unsigned, so + * we use >= and cast SKF_AD_OFF to unsigned. + */ + if (p->k >= (bpf_u_int32)SKF_AD_OFF) + return 0; + if (handle->linktype == DLT_LINUX_SLL2) { + /* + * What's the offset? + */ + if (p->k >= SLL2_HDR_LEN) { + /* + * It's within the link-layer payload; that starts + * at an offset of 0, as far as the kernel packet + * filter is concerned, so subtract the length of + * the link-layer header. + */ + p->k -= SLL2_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the protocol field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; + } else if (p->k == 4) { + /* + * It's the ifindex field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_IFINDEX; + } else if (p->k == 10) { + /* + * It's the packet type field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; + } else if ((bpf_int32)(p->k) > 0) { + /* + * It's within the header, but it's not one of + * those fields; we can't do that in the kernel, + * so punt to userland. + */ + return -1; + } + } else { + /* + * What's the offset? + */ + if (p->k >= SLL_HDR_LEN) { + /* + * It's within the link-layer payload; that starts + * at an offset of 0, as far as the kernel packet + * filter is concerned, so subtract the length of + * the link-layer header. + */ + p->k -= SLL_HDR_LEN; + } else if (p->k == 0) { + /* + * It's the packet type field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PKTTYPE; + } else if (p->k == 14) { + /* + * It's the protocol field; map it to the + * special magic kernel offset for that field. + */ + p->k = SKF_AD_OFF + SKF_AD_PROTOCOL; + } else if ((bpf_int32)(p->k) > 0) { + /* + * It's within the header, but it's not one of + * those fields; we can't do that in the kernel, + * so punt to userland. + */ + return -1; + } + } + return 0; +} + +static int +set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode) +{ + int total_filter_on = 0; + int save_mode; + int ret; + int save_errno; + + /* + * The socket filter code doesn't discard all packets queued + * up on the socket when the filter is changed; this means + * that packets that don't match the new filter may show up + * after the new filter is put onto the socket, if those + * packets haven't yet been read. + * + * This means, for example, that if you do a tcpdump capture + * with a filter, the first few packets in the capture might + * be packets that wouldn't have passed the filter. + * + * We therefore discard all packets queued up on the socket + * when setting a kernel filter. (This isn't an issue for + * userland filters, as the userland filtering is done after + * packets are queued up.) + * + * To flush those packets, we put the socket in read-only mode, + * and read packets from the socket until there are no more to + * read. + * + * In order to keep that from being an infinite loop - i.e., + * to keep more packets from arriving while we're draining + * the queue - we put the "total filter", which is a filter + * that rejects all packets, onto the socket before draining + * the queue. + * + * This code deliberately ignores any errors, so that you may + * get bogus packets if an error occurs, rather than having + * the filtering done in userland even if it could have been + * done in the kernel. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, + &total_fcode, sizeof(total_fcode)) == 0) { + char drain[1]; + + /* + * Note that we've put the total filter onto the socket. + */ + total_filter_on = 1; + + /* + * Save the socket's current mode, and put it in + * non-blocking mode; we drain it by reading packets + * until we get an error (which is normally a + * "nothing more to be read" error). + */ + save_mode = fcntl(handle->fd, F_GETFL, 0); + if (save_mode == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't get FD flags when changing filter"); + return -2; + } + if (fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't set nonblocking mode when changing filter"); + return -2; + } + while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0) + ; + save_errno = errno; + if (save_errno != EAGAIN) { + /* + * Fatal error. + * + * If we can't restore the mode or reset the + * kernel filter, there's nothing we can do. + */ + (void)fcntl(handle->fd, F_SETFL, save_mode); + (void)reset_kernel_filter(handle); + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, save_errno, + "recv failed when changing filter"); + return -2; + } + if (fcntl(handle->fd, F_SETFL, save_mode) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't restore FD flags when changing filter"); + return -2; + } + } + + /* + * Now attach the new filter. + */ + ret = setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER, + fcode, sizeof(*fcode)); + if (ret == -1 && total_filter_on) { + /* + * Well, we couldn't set that filter on the socket, + * but we could set the total filter on the socket. + * + * This could, for example, mean that the filter was + * too big to put into the kernel, so we'll have to + * filter in userland; in any case, we'll be doing + * filtering in userland, so we need to remove the + * total filter so we see packets. + */ + save_errno = errno; + + /* + * If this fails, we're really screwed; we have the + * total filter on the socket, and it won't come off. + * Report it as a fatal error. + */ + if (reset_kernel_filter(handle) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "can't remove kernel total filter"); + return -2; /* fatal error */ + } + + errno = save_errno; + } + return ret; +} + +static int +reset_kernel_filter(pcap_t *handle) +{ + int ret; + /* + * setsockopt() barfs unless it get a dummy parameter. + * valgrind whines unless the value is initialized, + * as it has no idea that setsockopt() ignores its + * parameter. + */ + int dummy = 0; + + ret = setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER, + &dummy, sizeof(dummy)); + /* + * Ignore ENOENT - it means "we don't have a filter", so there + * was no filter to remove, and there's still no filter. + * + * Also ignore ENONET, as a lot of kernel versions had a + * typo where ENONET, rather than ENOENT, was returned. + */ + if (ret == -1 && errno != ENOENT && errno != ENONET) + return -1; + return 0; +} + +int +pcap_set_protocol_linux(pcap_t *p, int protocol) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.protocol = protocol; + return (0); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ +#if defined(HAVE_TPACKET3) + return (PCAP_VERSION_STRING " (with TPACKET_V3)"); +#else + return (PCAP_VERSION_STRING " (with TPACKET_V2)"); +#endif +} diff --git a/src/libpcap-1.10.5/pcap-namedb.h b/src/libpcap-1.10.5/pcap-namedb.h new file mode 100644 index 0000000000..d5908c9208 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-namedb.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/src/libpcap-1.10.5/pcap-netfilter-linux.c b/src/libpcap-1.10.5/pcap-netfilter-linux.c new file mode 100644 index 0000000000..344bae4772 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-netfilter-linux.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "pcap-int.h" +#include "diag-control.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* NOTE: if your program drops privileges after pcap_activate() it WON'T work with nfqueue. + * It took me quite some time to debug ;/ + * + * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privileges, + * and in nfqueue we need to send verdict reply after receiving packet. + * + * In tcpdump you can disable dropping privileges with -Z root + */ + +#include "pcap-netfilter-linux.h" + +#define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg)))) + +#define NFLOG_IFACE "nflog" +#define NFQUEUE_IFACE "nfqueue" + +typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t; + +/* + * Private data for capturing on Linux netfilter sockets. + */ +struct pcap_netfilter { + u_int packets_read; /* count of packets read with recvfrom() */ + u_int packets_nobufs; /* ENOBUFS counter */ +}; + +static int nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict); + + +static int +netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_netfilter *handlep = handle->priv; + register u_char *bp, *ep; + int count = 0; + ssize_t len; + + /* + * Has "pcap_breakloop()" been called? + */ + if (handle->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + len = handle->cc; + if (len == 0) { + /* + * The buffer is empty; refill it. + * + * We ignore EINTR, as that might just be due to a signal + * being delivered - if the signal should interrupt the + * loop, the signal handler should call pcap_breakloop() + * to set handle->break_loop (we ignore it on other + * platforms as well). + */ + do { + len = recv(handle->fd, handle->buffer, handle->bufsize, 0); + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + if (len == -1 && errno == ENOBUFS) + handlep->packets_nobufs++; + } while ((len == -1) && (errno == EINTR || errno == ENOBUFS)); + + if (len < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "Can't receive packet"); + return PCAP_ERROR; + } + + bp = (unsigned char *)handle->buffer; + } else + bp = handle->bp; + + /* + * Loop through each message. + * + * This assumes that a single buffer of message will have + * <= INT_MAX packets, so the message count doesn't overflow. + */ + ep = bp + len; + while (bp < ep) { + const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp; + uint32_t msg_len; + nftype_t type = OTHER; + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (handle->break_loop) { + handle->bp = bp; + handle->cc = (int)(ep - bp); + if (count == 0) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } else + return count; + } + /* + * NLMSG_SPACE(0) might be signed or might be unsigned, + * depending on whether the kernel defines NLMSG_ALIGNTO + * as 4, which older kernels do, or as 4U, which newer + * kernels do. + * + * ep - bp is of type ptrdiff_t, which is signed. + * + * To squelch warnings, we cast both to size_t, which + * is unsigned; ep >= bp, so the cast is safe. + */ + if ((size_t)(ep - bp) < (size_t)NLMSG_SPACE(0)) { + /* + * There's less than one netlink message left + * in the buffer. Give up. + */ + break; + } + + if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len); + return -1; + } + + if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && + NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) + type = NFLOG; + else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && + NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET) + type = NFQUEUE; + + if (type != OTHER) { + const unsigned char *payload = NULL; + struct pcap_pkthdr pkth; + + const struct nfgenmsg *nfg = NULL; + int id = 0; + + if (handle->linktype != DLT_NFLOG) { + const struct nfattr *payload_attr = NULL; + + if (nlh->nlmsg_len < HDR_LENGTH) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len); + return -1; + } + + nfg = NLMSG_DATA(nlh); + if (nlh->nlmsg_len > HDR_LENGTH) { + struct nfattr *attr = NFM_NFA(nfg); + int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH); + + while (NFA_OK(attr, attr_len)) { + if (type == NFQUEUE) { + switch (NFA_TYPE(attr)) { + case NFQA_PACKET_HDR: + { + const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr); + + id = ntohl(pkt_hdr->packet_id); + break; + } + case NFQA_PAYLOAD: + payload_attr = attr; + break; + } + + } else if (type == NFLOG) { + switch (NFA_TYPE(attr)) { + case NFULA_PAYLOAD: + payload_attr = attr; + break; + } + } + attr = NFA_NEXT(attr, attr_len); + } + } + + if (payload_attr) { + payload = NFA_DATA(payload_attr); + pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr); + } + + } else { + payload = NLMSG_DATA(nlh); + pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr)); + } + + if (payload) { + /* pkth.caplen = min (payload_len, handle->snapshot); */ + + gettimeofday(&pkth.ts, NULL); + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) + { + handlep->packets_read++; + callback(user, &pkth, payload); + count++; + } + } + + if (type == NFQUEUE) { + /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */ + /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG, + so nfg is always initialized to NLMSG_DATA(nlh). */ + if (nfg != NULL) + nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT); + } + } + + msg_len = NLMSG_ALIGN(nlh->nlmsg_len); + /* + * If the message length would run past the end of the + * buffer, truncate it to the remaining space in the + * buffer. + * + * To squelch warnings, we cast ep - bp to uint32_t, which + * is unsigned and is the type of msg_len; ep >= bp, and + * len should fit in 32 bits (either it's set from an int + * or it's set from a recv() call with a buffer size that's + * an int, and we're assuming either ILP32 or LP64), so + * the cast is safe. + */ + if (msg_len > (uint32_t)(ep - bp)) + msg_len = (uint32_t)(ep - bp); + + bp += msg_len; + if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) { + handle->bp = bp; + handle->cc = (int)(ep - bp); + if (handle->cc < 0) + handle->cc = 0; + return count; + } + } + + handle->cc = 0; + return count; +} + +static int +netfilter_set_datalink(pcap_t *handle, int dlt) +{ + handle->linktype = dlt; + return 0; +} + +static int +netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_netfilter *handlep = handle->priv; + + stats->ps_recv = handlep->packets_read; + stats->ps_drop = handlep->packets_nobufs; + stats->ps_ifdrop = 0; + return 0; +} + +static int +netfilter_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on netfilter devices"); + return (-1); +} + +struct my_nfattr { + uint16_t nfa_len; + uint16_t nfa_type; + void *data; +}; + +static int +netfilter_send_config_msg(const pcap_t *handle, uint16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa) +{ + char buf[1024] __attribute__ ((aligned)); + memset(buf, 0, sizeof(buf)); + + struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr)); + + struct sockaddr_nl snl; + static unsigned int seq_id; + + if (!seq_id) +DIAG_OFF_NARROWING + seq_id = time(NULL); +DIAG_ON_NARROWING + ++seq_id; + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg)); + nlh->nlmsg_type = msg_type; + nlh->nlmsg_flags = NLM_F_REQUEST | (ack ? NLM_F_ACK : 0); + nlh->nlmsg_pid = 0; /* to kernel */ + nlh->nlmsg_seq = seq_id; + + nfg->nfgen_family = family; + nfg->version = NFNETLINK_V0; + nfg->res_id = htons(res_id); + + if (mynfa) { + struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len)); + + nfa->nfa_type = mynfa->nfa_type; + nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len); + memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len); + nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len); + } + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1) + return -1; + + if (!ack) + return 0; + + /* waiting for reply loop */ + do { + socklen_t addrlen = sizeof(snl); + int len; + + /* ignore interrupt system call error */ + do { + /* + * The buffer is not so big that its size won't + * fit into an int. + */ + len = (int)recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen); + } while ((len == -1) && (errno == EINTR)); + + if (len <= 0) + return len; + + if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) { + errno = EINVAL; + return -1; + } + + nlh = (struct nlmsghdr *) buf; + if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */ + continue; + + while ((u_int)len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, (u_int)len)) { + if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) { + if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return -1; + } + errno = -(*((int *)NLMSG_DATA(nlh))); + return (errno == 0) ? 0 : -1; + } + nlh = NLMSG_NEXT(nlh, len); + } + } while (1); + + return -1; /* never here */ +} + +static int +nflog_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) +{ + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, 1, family, group_id, mynfa); +} + +static int +nflog_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int8_t family) +{ + struct nfulnl_msg_config_cmd msg; + struct my_nfattr nfa; + + msg.command = cmd; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_CMD; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, family, group_id, &nfa); +} + +static int +nflog_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) +{ + struct nfulnl_msg_config_mode msg; + struct my_nfattr nfa; + + msg.copy_range = htonl(copy_range); + msg.copy_mode = copy_mode; + + nfa.data = &msg; + nfa.nfa_type = NFULA_CFG_MODE; + nfa.nfa_len = sizeof(msg); + + return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict) +{ + struct nfqnl_msg_verdict_hdr msg; + struct my_nfattr nfa; + + msg.id = htonl(id); + msg.verdict = htonl(verdict); + + nfa.data = &msg; + nfa.nfa_type = NFQA_VERDICT_HDR; + nfa.nfa_len = sizeof(msg); + + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT, 0, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa) +{ + return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG, 1, family, group_id, mynfa); +} + +static int +nfqueue_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int16_t pf) +{ + struct nfqnl_msg_config_cmd msg; + struct my_nfattr nfa; + + msg.command = cmd; + msg.pf = htons(pf); + + nfa.data = &msg; + nfa.nfa_type = NFQA_CFG_CMD; + nfa.nfa_len = sizeof(msg); + + return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +nfqueue_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range) +{ + struct nfqnl_msg_config_params msg; + struct my_nfattr nfa; + + msg.copy_range = htonl(copy_range); + msg.copy_mode = copy_mode; + + nfa.data = &msg; + nfa.nfa_type = NFQA_CFG_PARAMS; + nfa.nfa_len = sizeof(msg); + + return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa); +} + +static int +netfilter_activate(pcap_t* handle) +{ + const char *dev = handle->opt.device; + unsigned short groups[32]; + int group_count = 0; + nftype_t type = OTHER; + int i; + + if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) { + dev += strlen(NFLOG_IFACE); + type = NFLOG; + + } else if (strncmp(dev, NFQUEUE_IFACE, strlen(NFQUEUE_IFACE)) == 0) { + dev += strlen(NFQUEUE_IFACE); + type = NFQUEUE; + } + + if (type != OTHER && *dev == ':') { + dev++; + while (*dev) { + long int group_id; + char *end_dev; + + if (group_count == 32) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Maximum 32 netfilter groups! dev: %s", + handle->opt.device); + return PCAP_ERROR; + } + + group_id = strtol(dev, &end_dev, 0); + if (end_dev != dev) { + if (group_id < 0 || group_id > 65535) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Netfilter group range from 0 to 65535 (got %ld)", + group_id); + return PCAP_ERROR; + } + + groups[group_count++] = (unsigned short) group_id; + dev = end_dev; + } + if (*dev != ',') + break; + dev++; + } + } + + if (type == OTHER || *dev) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get netfilter group(s) index from %s", + handle->opt.device); + return PCAP_ERROR; + } + + /* if no groups, add default: 0 */ + if (!group_count) { + groups[0] = 0; + group_count = 1; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 128 + handle->snapshot; + handle->offset = 0; + handle->read_op = netfilter_read_linux; + handle->inject_op = netfilter_inject_linux; + handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = NULL; + handle->set_datalink_op = netfilter_set_datalink; + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + handle->stats_op = netfilter_stats_linux; + + /* Create netlink socket */ + handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (handle->fd < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't create raw socket"); + return PCAP_ERROR; + } + + if (type == NFLOG) { + handle->linktype = DLT_NFLOG; + handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (handle->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't allocate DLT list"); + goto close_fail; + } + handle->dlt_list[0] = DLT_NFLOG; + handle->dlt_list[1] = DLT_IPV4; + handle->dlt_count = 2; + } else + handle->linktype = DLT_IPV4; + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't allocate dump buffer"); + goto close_fail; + } + + if (type == NFLOG) { + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "NFULNL_CFG_CMD_PF_UNBIND"); + goto close_fail; + } + + if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "NFULNL_CFG_CMD_PF_BIND"); + goto close_fail; + } + + /* Bind socket to the nflog groups */ + for (i = 0; i < group_count; i++) { + if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't listen on group index"); + goto close_fail; + } + + if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "NFULNL_COPY_PACKET"); + goto close_fail; + } + } + + } else { + if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_UNBIND"); + goto close_fail; + } + + if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_BIND"); + goto close_fail; + } + + /* Bind socket to the nfqueue groups */ + for (i = 0; i < group_count; i++) { + if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't listen on group index"); + goto close_fail; + } + + if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "NFQNL_COPY_PACKET"); + goto close_fail; + } + } + } + + if (handle->opt.rfmon) { + /* + * Monitor mode doesn't apply to netfilter devices. + */ + pcapint_cleanup_live_common(handle); + return PCAP_ERROR_RFMON_NOTSUP; + } + + if (handle->opt.buffer_size != 0) { + /* + * Set the socket buffer size to the specified value. + */ + if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "SO_RCVBUF"); + goto close_fail; + } + } + + handle->selectable_fd = handle->fd; + return 0; + +close_fail: + pcapint_cleanup_live_common(handle); + return PCAP_ERROR; +} + +pcap_t * +netfilter_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + pcap_t *p; + + /* Does this look like an netfilter device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + + /* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */ + if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0) + cp += sizeof NFLOG_IFACE - 1; + else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0) + cp += sizeof NFQUEUE_IFACE - 1; + else { + /* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */ + *is_ours = 0; + return NULL; + } + + /* + * Yes - is that either the end of the name, or is it followed + * by a colon? + */ + if (*cp != ':' && *cp != '\0') { + /* Nope */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_netfilter); + if (p == NULL) + return (NULL); + + p->activate_op = netfilter_activate; + return (p); +} + +int +netfilter_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + int sock; + + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (sock < 0) { + /* if netlink is not supported this is not fatal */ + if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) + return 0; + pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE, + errno, "Can't open netlink socket"); + return -1; + } + close(sock); + + /* + * The notion of "connected" vs. "disconnected" doesn't apply. + * XXX - what about "up" and "running"? + */ + if (pcapint_add_dev(devlistp, NFLOG_IFACE, + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, + "Linux netfilter log (NFLOG) interface", err_str) == NULL) + return -1; + if (pcapint_add_dev(devlistp, NFQUEUE_IFACE, + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, + "Linux netfilter queue (NFQUEUE) interface", err_str) == NULL) + return -1; + return 0; +} diff --git a/src/libpcap-1.10.5/pcap-netfilter-linux.h b/src/libpcap-1.10.5/pcap-netfilter-linux.h new file mode 100644 index 0000000000..97b73108fe --- /dev/null +++ b/src/libpcap-1.10.5/pcap-netfilter-linux.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Jakub Zawadzki + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Prototypes for netlink-related functions + */ +int netfilter_findalldevs(pcap_if_list_t *devlistp, char *err_str); +pcap_t *netfilter_create(const char *device, char *ebuf, int *is_ours); diff --git a/src/libpcap-1.10.5/pcap-netmap.c b/src/libpcap-1.10.5/pcap-netmap.c new file mode 100644 index 0000000000..f17f36ca20 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-netmap.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2014 Luigi Rizzo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NETMAP_WITH_LIBS +#include + +#include "pcap-int.h" +#include "pcap-netmap.h" + +#ifndef __FreeBSD__ + /* + * On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh. + * Remap to IFF_PROMISC on other platforms. + * + * XXX - DragonFly BSD? + */ + #define IFF_PPROMISC IFF_PROMISC +#endif /* __FreeBSD__ */ + +struct pcap_netmap { + struct nm_desc *d; /* pointer returned by nm_open() */ + pcap_handler cb; /* callback and argument */ + u_char *cb_arg; + int must_clear_promisc; /* flag */ + uint64_t rx_pkts; /* # of pkts received before the filter */ +}; + + +static int +pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_netmap *pn = p->priv; + + ps->ps_recv = (u_int)pn->rx_pkts; + ps->ps_drop = 0; + ps->ps_ifdrop = 0; + return 0; +} + + +static void +pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf) +{ + pcap_t *p = (pcap_t *)arg; + struct pcap_netmap *pn = p->priv; + const struct bpf_insn *pc = p->fcode.bf_insns; + + ++pn->rx_pkts; + if (pc == NULL || pcapint_filter(pc, buf, h->len, h->caplen)) + pn->cb(pn->cb_arg, h, buf); +} + + +static int +pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) +{ + int ret; + struct pcap_netmap *pn = p->priv; + struct nm_desc *d = pn->d; + struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 }; + + pn->cb = cb; + pn->cb_arg = user; + + for (;;) { + if (p->break_loop) { + p->break_loop = 0; + return PCAP_ERROR_BREAK; + } + /* nm_dispatch won't run forever */ + + ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p); + if (ret != 0) + break; + errno = 0; + ret = poll(&pfd, 1, p->opt.timeout); + } + return ret; +} + + +/* XXX need to check the NIOCTXSYNC/poll */ +static int +pcap_netmap_inject(pcap_t *p, const void *buf, int size) +{ + struct pcap_netmap *pn = p->priv; + struct nm_desc *d = pn->d; + + return nm_inject(d, buf, size); +} + + +static int +pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) +{ + struct pcap_netmap *pn = p->priv; + struct nm_desc *d = pn->d; + struct ifreq ifr; + int error, fd = d->fd; + +#ifdef __linux__ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + fprintf(stderr, "Error: cannot get device control socket.\n"); + return -1; + } +#endif /* __linux__ */ + bzero(&ifr, sizeof(ifr)); + strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); + switch (what) { + case SIOCSIFFLAGS: + /* + * The flags we pass in are 32-bit and unsigned. + * + * On most if not all UN*Xes, ifr_flags is 16-bit and + * signed, and the result of assigning a longer + * unsigned value to a shorter signed value is + * implementation-defined (even if, in practice, it'll + * do what's intended on all platforms we support + * result of assigning a 32-bit unsigned value). + * So we mask out the upper 16 bits. + */ + ifr.ifr_flags = *if_flags & 0xffff; +#ifdef __FreeBSD__ + /* + * In FreeBSD, we need to set the high-order flags, + * as we're using IFF_PPROMISC, which is in those bits. + * + * XXX - DragonFly BSD? + */ + ifr.ifr_flagshigh = *if_flags >> 16; +#endif /* __FreeBSD__ */ + break; + } + error = ioctl(fd, what, &ifr); + if (!error) { + switch (what) { + case SIOCGIFFLAGS: + /* + * The flags we return are 32-bit. + * + * On most if not all UN*Xes, ifr_flags is + * 16-bit and signed, and will get sign- + * extended, so that the upper 16 bits of + * those flags will be forced on. So we + * mask out the upper 16 bits of the + * sign-extended value. + */ + *if_flags = ifr.ifr_flags & 0xffff; +#ifdef __FreeBSD__ + /* + * In FreeBSD, we need to return the + * high-order flags, as we're using + * IFF_PPROMISC, which is in those bits. + * + * XXX - DragonFly BSD? + */ + *if_flags |= (ifr.ifr_flagshigh << 16); +#endif /* __FreeBSD__ */ + } + } +#ifdef __linux__ + close(fd); +#endif /* __linux__ */ + return error ? -1 : 0; +} + + +static void +pcap_netmap_close(pcap_t *p) +{ + struct pcap_netmap *pn = p->priv; + struct nm_desc *d = pn->d; + uint32_t if_flags = 0; + + if (pn->must_clear_promisc) { + pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ + if (if_flags & IFF_PPROMISC) { + if_flags &= ~IFF_PPROMISC; + pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); + } + } + nm_close(d); + pcapint_cleanup_live_common(p); +} + + +static int +pcap_netmap_activate(pcap_t *p) +{ + struct pcap_netmap *pn = p->priv; + struct nm_desc *d; + uint32_t if_flags = 0; + + d = nm_open(p->opt.device, NULL, 0, NULL); + if (d == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "netmap open: cannot access %s", + p->opt.device); + pcapint_cleanup_live_common(p); + return (PCAP_ERROR); + } +#if 0 + fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", + __FUNCTION__, p->opt.device, d, d->fd, + d->first_rx_ring, d->last_rx_ring); +#endif + pn->d = d; + p->fd = d->fd; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) { + pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ + if (!(if_flags & IFF_PPROMISC)) { + pn->must_clear_promisc = 1; + if_flags |= IFF_PPROMISC; + pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); + } + } + p->linktype = DLT_EN10MB; + p->selectable_fd = p->fd; + p->read_op = pcap_netmap_dispatch; + p->inject_op = pcap_netmap_inject; + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = NULL; + p->set_datalink_op = NULL; + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_netmap_stats; + p->cleanup_op = pcap_netmap_close; + + return (0); +} + + +pcap_t * +pcap_netmap_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + + *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4)); + if (! *is_ours) + return NULL; + p = PCAP_CREATE_COMMON(ebuf, struct pcap_netmap); + if (p == NULL) + return (NULL); + p->activate_op = pcap_netmap_activate; + return (p); +} + +/* + * The "device name" for netmap devices isn't a name for a device, it's + * an expression that indicates how the device should be set up, so + * there's no way to enumerate them. + */ +int +pcap_netmap_findalldevs(pcap_if_list_t *devlistp _U_, char *err_str _U_) +{ + return 0; +} diff --git a/src/libpcap-1.10.5/pcap-netmap.h b/src/libpcap-1.10.5/pcap-netmap.h new file mode 100644 index 0000000000..6a414fca76 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-netmap.h @@ -0,0 +1,2 @@ +pcap_t *pcap_netmap_create(const char *, char *, int *); +int pcap_netmap_findalldevs(pcap_if_list_t *devlistp, char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-new.c b/src/libpcap-1.10.5/pcap-new.c new file mode 100644 index 0000000000..822bc9038b --- /dev/null +++ b/src/libpcap-1.10.5/pcap-new.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "ftmacros.h" +#include "diag-control.h" + +/* + * sockutils.h may include on Windows, and pcap-int.h will + * include portability.h, and portability.h, on Windows, expects that + * has already been included, so include sockutils.h first. + */ +#include "sockutils.h" +#include "pcap-int.h" // for the details of the pcap_t structure +#include "pcap-rpcap.h" +#include "rpcap-protocol.h" +#include // for the errno variable +#include // for malloc(), free(), ... +#include // for strstr, etc + +#ifndef _WIN32 +#include // for readdir +#endif + +/* String identifier to be used in the pcap_findalldevs_ex() */ +#define PCAP_TEXT_SOURCE_FILE "File" +#define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1) +/* String identifier to be used in the pcap_findalldevs_ex() */ +#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" +#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1) + +/* String identifier to be used in the pcap_findalldevs_ex() */ +#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host" +#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1) + +/**************************************************** + * * + * Function bodies * + * * + ****************************************************/ + +int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) +{ + int type; + char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE]; + size_t pathlen; + size_t stringlen; + pcap_t *fp; + char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ + pcap_if_t *lastdev; /* Last device in the pcap_if_t list */ + pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */ + + /* List starts out empty. */ + (*alldevs) = NULL; + lastdev = NULL; + + if (strlen(source) > PCAP_BUF_SIZE) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); + return -1; + } + + /* + * Determine the type of the source (file, local, remote) + * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters. + * In the first case, the name of the directory we have to look into must be present (therefore + * the 'name' parameter of the pcap_parsesrcstr() is present). + * In the second case, the name of the adapter is not required (we need just the host). So, we have + * to use a first time this function to get the source type, and a second time to get the appropriate + * info, which depends on the source type. + */ + if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1) + return -1; + + switch (type) + { + case PCAP_SRC_IFLOCAL: + if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1) + return -1; + + /* Initialize temporary string */ + tmpstring[PCAP_BUF_SIZE] = 0; + + /* The user wants to retrieve adapters from a local host */ + if (pcap_findalldevs(alldevs, errbuf) == -1) + return -1; + + if (*alldevs == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "No interfaces found! Make sure libpcap/Npcap is properly installed" + " on the local machine."); + return -1; + } + + /* Scan all the interfaces and modify name and description */ + /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */ + dev = *alldevs; + while (dev) + { + char *localdesc, *desc; + + /* Create the new device identifier */ + if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1) + return -1; + + /* Delete the old pointer */ + free(dev->name); + + /* Make a copy of the new device identifier */ + dev->name = strdup(tmpstring); + if (dev->name == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc() failed"); + pcap_freealldevs(*alldevs); + return -1; + } + + /* + * Create the description. + */ + if ((dev->description == NULL) || (dev->description[0] == 0)) + localdesc = dev->name; + else + localdesc = dev->description; + if (pcapint_asprintf(&desc, "%s '%s' %s", + PCAP_TEXT_SOURCE_ADAPTER, localdesc, + PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc() failed"); + pcap_freealldevs(*alldevs); + return -1; + } + + /* Now overwrite the description */ + free(dev->description); + dev->description = desc; + + dev = dev->next; + } + + return 0; + + case PCAP_SRC_FILE: + { +#ifdef _WIN32 + WIN32_FIND_DATA filedata; + HANDLE filehandle; +#else + struct dirent *filedata; + DIR *unixdir; +#endif + + if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1) + return -1; + + /* Check that the filename is correct */ + stringlen = strlen(name); + + /* The directory must end with '\' in Win32 and '/' in UNIX */ +#ifdef _WIN32 +#define ENDING_CHAR '\\' +#else +#define ENDING_CHAR '/' +#endif + + if (name[stringlen - 1] != ENDING_CHAR) + { + name[stringlen] = ENDING_CHAR; + name[stringlen + 1] = 0; + + stringlen++; + } + + /* Save the path for future reference */ + snprintf(path, sizeof(path), "%s", name); + pathlen = strlen(path); + +#ifdef _WIN32 + /* To perform directory listing, Win32 must have an 'asterisk' as ending char */ + if (name[stringlen - 1] != '*') + { + name[stringlen] = '*'; + name[stringlen + 1] = 0; + } + + filehandle = FindFirstFile(name, &filedata); + + if (filehandle == INVALID_HANDLE_VALUE) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); + return -1; + } + +#else + /* opening the folder */ + unixdir= opendir(path); + if (unixdir == NULL) { + DIAG_OFF_FORMAT_TRUNCATION + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Error when listing files in '%s': %s", path, pcap_strerror(errno)); + DIAG_ON_FORMAT_TRUNCATION + return -1; + } + + /* get the first file into it */ + errno = 0; + filedata= readdir(unixdir); + + if (filedata == NULL) + { + DIAG_OFF_FORMAT_TRUNCATION + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Error when listing files in '%s': %s", path, pcap_strerror(errno)); + DIAG_ON_FORMAT_TRUNCATION + closedir(unixdir); + return -1; + } +#endif + + /* Add all files we find to the list. */ + do + { +#ifdef _WIN32 + /* Skip the file if the pathname won't fit in the buffer */ + if (pathlen + strlen(filedata.cFileName) >= sizeof(filename)) + continue; + snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName); +#else + if (pathlen + strlen(filedata->d_name) >= sizeof(filename)) + continue; + DIAG_OFF_FORMAT_TRUNCATION + snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name); + DIAG_ON_FORMAT_TRUNCATION +#endif + + fp = pcap_open_offline(filename, errbuf); + + if (fp) + { + /* allocate the main structure */ + dev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); + if (dev == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc() failed"); + pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif + return -1; + } + + /* Initialize the structure to 'zero' */ + memset(dev, 0, sizeof(pcap_if_t)); + + /* Append it to the list. */ + if (lastdev == NULL) + { + /* + * List is empty, so it's also + * the first device. + */ + *alldevs = dev; + } + else + { + /* + * Append after the last device. + */ + lastdev->next = dev; + } + /* It's now the last device. */ + lastdev = dev; + + /* Create the new source identifier */ + if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1) + { + pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif + return -1; + } + + dev->name = strdup(tmpstring); + if (dev->name == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc() failed"); + pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif + return -1; + } + + /* + * Create the description. + */ + if (pcapint_asprintf(&dev->description, + "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, + filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc() failed"); + pcap_freealldevs(*alldevs); +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif + return -1; + } + + pcap_close(fp); + } + } +#ifdef _WIN32 + while (FindNextFile(filehandle, &filedata) != 0); +#else + while ( (filedata= readdir(unixdir)) != NULL); +#endif + + + /* Close the search handle. */ +#ifdef _WIN32 + FindClose(filehandle); +#else + closedir(unixdir); +#endif + + return 0; + } + + case PCAP_SRC_IFREMOTE: + return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf); + + default: + pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); + return -1; + } +} + +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf) +{ + char name[PCAP_BUF_SIZE]; + int type; + pcap_t *fp; + int status; + + /* + * A null device name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (source == NULL) + source = "any"; + + if (strlen(source) > PCAP_BUF_SIZE) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); + return NULL; + } + + /* + * Determine the type of the source (file, local, remote) and, + * if it's file or local, the name of the file or capture device. + */ + if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1) + return NULL; + + switch (type) + { + case PCAP_SRC_FILE: + return pcap_open_offline(name, errbuf); + + case PCAP_SRC_IFLOCAL: + fp = pcap_create(name, errbuf); + break; + + case PCAP_SRC_IFREMOTE: + /* + * Although we already have host, port and iface, we prefer + * to pass only 'source' to pcap_open_rpcap(), so that it + * has to call pcap_parsesrcstr() again. + * This is less optimized, but much clearer. + */ + return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf); + + default: + pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); + return NULL; + } + + if (fp == NULL) + return (NULL); + status = pcap_set_snaplen(fp, snaplen); + if (status < 0) + goto fail; + if (flags & PCAP_OPENFLAG_PROMISCUOUS) + { + status = pcap_set_promisc(fp, 1); + if (status < 0) + goto fail; + } + if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS) + { + status = pcap_set_immediate_mode(fp, 1); + if (status < 0) + goto fail; + } +#ifdef _WIN32 + /* + * This flag is supported on Windows only. + * XXX - is there a way to support it with + * the capture mechanisms on UN*X? It's not + * exactly a "set direction" operation; I + * think it means "do not capture packets + * injected with pcap_sendpacket() or + * pcap_inject()". + */ + /* disable loopback capture if requested */ + if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL) + fp->opt.nocapture_local = 1; +#endif /* _WIN32 */ + status = pcap_set_timeout(fp, read_timeout); + if (status < 0) + goto fail; + status = pcap_activate(fp); + if (status < 0) + goto fail; + return fp; + +fail: + DIAG_OFF_FORMAT_TRUNCATION + if (status == PCAP_ERROR) + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + name, fp->errbuf); + else if (status == PCAP_ERROR_NO_SUCH_DEVICE || + status == PCAP_ERROR_PERM_DENIED || + status == PCAP_ERROR_PROMISC_PERM_DENIED) + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", + name, pcap_statustostr(status), fp->errbuf); + else + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + name, pcap_statustostr(status)); + DIAG_ON_FORMAT_TRUNCATION + pcap_close(fp); + return NULL; +} + +struct pcap_samp *pcap_setsampling(pcap_t *p) +{ + return &p->rmt_samp; +} diff --git a/src/libpcap-1.10.5/pcap-nit.c b/src/libpcap-1.10.5/pcap-nit.c new file mode 100644 index 0000000000..a26caba548 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-nit.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * The chunk size for NIT. This is the amount of buffering + * done for read calls. + */ +#define CHUNKSIZE (2*1024) + +/* + * The total buffer space used by NIT. + */ +#define BUFSPACE (4*CHUNKSIZE) + +/* Forwards */ +static int nit_setflags(int, int, int, char *); + +/* + * Private data for capturing on NIT devices. + */ +struct pcap_nit { + struct pcap_stat stat; +}; + +static int +pcap_stats_nit(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_nit *pn = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this does not include packets dropped because we ran out + * of buffer space. + * + * "ps_drop" presumably counts packets dropped by the socket + * because of flow control requirements or resource exhaustion; + * it doesn't count packets dropped by the interface driver. + * As filtering is done in userland, it counts packets regardless + * of whether they would've passed the filter. + * + * These statistics don't include packets not yet read from the + * kernel by libpcap or packets not yet read from libpcap by the + * application. + */ + *ps = pn->stat; + return (0); +} + +static int +pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_nit *pn = p->priv; + register int cc, n; + register u_char *bp, *cp, *ep; + register struct nit_hdr *nh; + register int caplen; + + cc = p->cc; + if (cc == 0) { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "pcap_read"); + return (-1); + } + bp = (u_char *)p->buffer; + } else + bp = p->bp; + + /* + * Loop through each packet. The increment expression + * rounds up to the next int boundary past the end of + * the previous packet. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ + n = 0; + ep = bp + cc; + while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + + nh = (struct nit_hdr *)bp; + cp = bp + sizeof(*nh); + + switch (nh->nh_state) { + + case NIT_CATCH: + break; + + case NIT_NOMBUF: + case NIT_NOCLUSTER: + case NIT_NOSPACE: + pn->stat.ps_drop = nh->nh_dropped; + continue; + + case NIT_SEQNO: + continue; + + default: + snprintf(p->errbuf, sizeof(p->errbuf), + "bad nit state %d", nh->nh_state); + return (-1); + } + ++pn->stat.ps_recv; + bp += ((sizeof(struct nit_hdr) + nh->nh_datalen + + sizeof(int) - 1) & ~(sizeof(int) - 1)); + + caplen = nh->nh_wirelen; + if (caplen > p->snapshot) + caplen = p->snapshot; + if (pcapint_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) { + struct pcap_pkthdr h; + h.ts = nh->nh_timestamp; + h.len = nh->nh_wirelen; + h.caplen = caplen; + (*callback)(user, &h, cp); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + } + p->cc = 0; + return (n); +} + +static int +pcap_inject_nit(pcap_t *p, const void *buf, int size) +{ + struct sockaddr sa; + int ret; + + memset(&sa, 0, sizeof(sa)); + strncpy(sa.sa_data, device, sizeof(sa.sa_data)); + ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa)); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + return (ret); +} + +static int +nit_setflags(pcap_t *p) +{ + struct nit_ioc nioc; + + memset(&nioc, 0, sizeof(nioc)); + nioc.nioc_typetomatch = NT_ALLTYPES; + nioc.nioc_snaplen = p->snapshot; + nioc.nioc_bufalign = sizeof(int); + nioc.nioc_bufoffset = 0; + + if (p->opt.buffer_size != 0) + nioc.nioc_bufspace = p->opt.buffer_size; + else { + /* Default buffer size */ + nioc.nioc_bufspace = BUFSPACE; + } + + if (p->opt.immediate) { + /* + * XXX - will this cause packets to be delivered immediately? + * XXX - given that this is for SunOS prior to 4.0, do + * we care? + */ + nioc.nioc_chunksize = 0; + } else + nioc.nioc_chunksize = CHUNKSIZE; + if (p->opt.timeout != 0) { + nioc.nioc_flags |= NF_TIMEOUT; + nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000; + nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + } + if (p->opt.promisc) + nioc.nioc_flags |= NF_PROMISC; + + if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCSNIT"); + return (-1); + } + return (0); +} + +static int +pcap_activate_nit(pcap_t *p) +{ + int fd; + struct sockaddr_nit snit; + + if (p->opt.rfmon) { + /* + * No monitor mode on SunOS 3.x or earlier (no + * Wi-Fi *devices* for the hardware that supported + * them!). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + if (p->snapshot < 96) + /* + * NIT requires a snapshot length of at least 96. + */ + p->snapshot = 96; + + memset(p, 0, sizeof(*p)); + p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + goto bad; + } + snit.snit_family = AF_NIT; + (void)strncpy(snit.snit_ifname, p->opt.device, NITIFSIZ); + + if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) { + /* + * XXX - there's probably a particular bind error that + * means "there's no such device" and a particular bind + * error that means "that device doesn't support NIT"; + * they might be the same error, if they both end up + * meaning "NIT doesn't know about that device". + */ + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "bind: %s", snit.snit_ifname); + goto bad; + } + if (nit_setflags(p) < 0) + goto bad; + + /* + * NIT supports only ethernets. + */ + p->linktype = DLT_EN10MB; + + p->bufsize = BUFSPACE; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + + /* + * "p->fd" is a socket, so "select()" should work on it. + */ + p->selectable_fd = p->fd; + + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + + p->read_op = pcap_read_nit; + p->inject_op = pcap_inject_nit; + p->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_nit; + + return (0); + bad: + pcapint_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_nit); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_nit; + return (p); +} + +/* + * XXX - there's probably a particular bind error that means "that device + * doesn't support NIT"; if so, we should try a bind and use that. + */ +static int +can_be_bound(const char *name _U_) +{ + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do. + * XXX - is there a way to find out whether an adapter has + * something plugged into it? + */ + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound, + get_if_flags)); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-npf.c b/src/libpcap-1.10.5/pcap-npf.c new file mode 100644 index 0000000000..76346f574b --- /dev/null +++ b/src/libpcap-1.10.5/pcap-npf.c @@ -0,0 +1,2777 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include /* for INT_MAX */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#include +#include + +/* + * XXX - Packet32.h defines bpf_program, so we can't include + * , which also defines it; that's why we define + * PCAP_DONT_INCLUDE_PCAP_BPF_H, + * + * However, no header in the WinPcap or Npcap SDKs defines the + * macros for BPF code, so we have to define them ourselves. + */ +#define BPF_RET 0x06 +#define BPF_K 0x00 + +/* Old-school MinGW have these headers in a different place. + */ +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) + #include + #include +#else + #include /* MSVC/TDM-MinGW/MinGW64 */ +#endif + +#ifdef HAVE_DAG_API + #include + #include +#endif /* HAVE_DAG_API */ + +#include "diag-control.h" + +#include "pcap-airpcap.h" + +static int pcap_setfilter_npf(pcap_t *, struct bpf_program *); +static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); +static int pcap_getnonblock_npf(pcap_t *); +static int pcap_setnonblock_npf(pcap_t *, int); + +/*dimension of the buffer in the pcap_t structure*/ +#define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 + +/*dimension of the buffer in the kernel driver NPF */ +#define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 + +/* Equivalent to ntohs(), but a lot faster under Windows */ +#define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) + +/* + * Private data for capturing on WinPcap/Npcap devices. + */ +struct pcap_win { + ADAPTER *adapter; /* the packet32 ADAPTER for the device */ + int nonblock; + int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ + int filtering_in_kernel; /* using kernel filter */ + +#ifdef HAVE_DAG_API + int dag_fcs_bits; /* Number of checksum bits from link layer */ +#endif + +#ifdef ENABLE_REMOTE + int samp_npkt; /* parameter needed for sampling, with '1 out of N' method has been requested */ + struct timeval samp_time; /* parameter needed for sampling, with '1 every N ms' method has been requested */ +#endif +}; + +/* + * Define stub versions of the monitor-mode support routines if this + * isn't Npcap. HAVE_NPCAP_PACKET_API is defined by Npcap but not + * WinPcap. + */ +#ifndef HAVE_NPCAP_PACKET_API +static int +PacketIsMonitorModeSupported(PCHAR AdapterName _U_) +{ + /* + * We don't support monitor mode. + */ + return (0); +} + +static int +PacketSetMonitorMode(PCHAR AdapterName _U_, int mode _U_) +{ + /* + * This should never be called, as PacketIsMonitorModeSupported() + * will return 0, meaning "we don't support monitor mode, so + * don't try to turn it on or off". + */ + return (0); +} + +static int +PacketGetMonitorMode(PCHAR AdapterName _U_) +{ + /* + * This should fail, so that pcap_activate_npf() returns + * PCAP_ERROR_RFMON_NOTSUP if our caller requested monitor + * mode. + */ + return (-1); +} +#endif + +/* + * If a driver returns an NTSTATUS value: + * + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781 + * + * with the "Customer" bit set, it will not be mapped to a Windows error + * value in userland, so it will be returned by GetLastError(). + * + * Note that "driver" here includes the Npcap NPF driver, as various + * versions would take NT status values and set the "Customer" bit + * before returning the status code. The commit message for the + * change that started doing that is + * + * Returned a customer-defined NTSTATUS in OID requests to avoid + * NTSTATUS-to-Win32 Error code translation. + * + * but I don't know why the goal was to avoid that translation. For + * a while, I suspected that the NT status STATUS_NOT_SUPPORTED was + * getting mapped to ERROR_GEN_FAILURE, but, in the cases where + * attempts to set promiscuous mode on regular Ethernet devices were + * failing with ERROR_GEN_FAILURE, it turns out that the drivers for + * those devices were NetAdapterCx drivers, and Microsoft's NetAdapterCx + * mechanism wasn't providing the correct "bytes processed" value on + * attempts to set OIDs, and the Npcap NPF driver was checking for + * that and returning STATUS_UNSUCCESSFUL, which gets mapped to + * ERROR_GEN_FAILURE, so perhaps there's no need to avoid that + * translation. + * + * Attempting to set the hardware filter on a Microsoft Surface Pro's + * Mobile Broadband Adapter returns an error that appears to be + * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's + * probably indicating that it doesn't support that. It was probably + * the NPF driver setting that bit. + */ +#define NT_STATUS_CUSTOMER_DEFINED 0x20000000 + +/* + * PacketRequest() makes a DeviceIoControl() call to the NPF driver to + * perform the OID request, with a BIOCQUERYOID ioctl. The kernel code + * should get back one of NDIS_STATUS_INVALID_OID, NDIS_STATUS_NOT_SUPPORTED, + * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't supported by + * the OS or the driver. + * + * Currently, that code may be returned by the Npcap NPF driver with the + * NT_STATUS_CUSTOMER_DEFINED bit. That prevents the return status from + * being mapped to a Windows error code; if the NPF driver were to stop + * ORing in the NT_STATUS_CUSTOMER_DEFINED bit, it's not obvious how those + * the NDIS_STATUS_ values that don't correspond to NTSTATUS values would + * be translated to Windows error values (NDIS_STATUS_NOT_SUPPORTED is + * the same as STATUS_NOT_SUPPORTED, which is an NTSTATUS value that is + * mapped to ERROR_NOT_SUPPORTED). + */ +#define NDIS_STATUS_INVALID_OID 0xc0010017 +#define NDIS_STATUS_NOT_SUPPORTED 0xc00000bb /* STATUS_NOT_SUPPORTED */ +#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 + +static int +oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, + char *errbuf) +{ + PACKET_OID_DATA *oid_data_arg; + + /* + * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). + * It should be big enough to hold "*lenp" bytes of data; it + * will actually be slightly larger, as PACKET_OID_DATA has a + * 1-byte data array at the end, standing in for the variable-length + * data that's actually there. + */ + oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); + if (oid_data_arg == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Couldn't allocate argument buffer for PacketRequest"); + return (PCAP_ERROR); + } + + /* + * No need to copy the data - we're doing a fetch. + */ + oid_data_arg->Oid = oid; + oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ + if (!PacketRequest(adapter, FALSE, oid_data_arg)) { + pcapint_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); + free(oid_data_arg); + return (-1); + } + + /* + * Get the length actually supplied. + */ + *lenp = oid_data_arg->Length; + + /* + * Copy back the data we fetched. + */ + memcpy(data, oid_data_arg->Data, *lenp); + free(oid_data_arg); + return (0); +} + +static int +pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_win *pw = p->priv; + struct bpf_stat bstats; + + /* + * Try to get statistics. + * + * (Please note - "struct pcap_stat" is *not* the same as + * WinPcap's "struct bpf_stat". It might currently have the + * same layout, but let's not cheat. + * + * Note also that we don't fill in ps_capt, as we might have + * been called by code compiled against an earlier version of + * WinPcap that didn't have ps_capt, in which case filling it + * in would stomp on whatever comes after the structure passed + * to us. + */ + if (!PacketGetStats(pw->adapter, &bstats)) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStats error"); + return (-1); + } + ps->ps_recv = bstats.bs_recv; + ps->ps_drop = bstats.bs_drop; + + /* + * XXX - PacketGetStats() doesn't fill this in, so we just + * return 0. + */ +#if 0 + ps->ps_ifdrop = bstats.ps_ifdrop; +#else + ps->ps_ifdrop = 0; +#endif + + return (0); +} + +/* + * Win32-only routine for getting statistics. + * + * This way is definitely safer than passing the pcap_stat * from the userland. + * In fact, there could happen than the user allocates a variable which is not + * big enough for the new structure, and the library will write in a zone + * which is not allocated to this variable. + * + * In this way, we're pretty sure we are writing on memory allocated to this + * variable. + * + * XXX - but this is the wrong way to handle statistics. Instead, we should + * have an API that returns data in a form like the Options section of a + * pcapng Interface Statistics Block: + * + * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6 + * + * which would let us add new statistics straightforwardly and indicate which + * statistics we are and are *not* providing, rather than having to provide + * possibly-bogus values for statistics we can't provide. + */ +static struct pcap_stat * +pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) +{ + struct pcap_win *pw = p->priv; + struct bpf_stat bstats; + + *pcap_stat_size = sizeof (p->stat); + + /* + * Try to get statistics. + * + * (Please note - "struct pcap_stat" is *not* the same as + * WinPcap's "struct bpf_stat". It might currently have the + * same layout, but let's not cheat.) + */ + if (!PacketGetStatsEx(pw->adapter, &bstats)) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStatsEx error"); + return (NULL); + } + p->stat.ps_recv = bstats.bs_recv; + p->stat.ps_drop = bstats.bs_drop; + p->stat.ps_ifdrop = bstats.ps_ifdrop; + /* + * Just in case this is ever compiled for a target other than + * Windows, which is somewhere between extremely unlikely and + * impossible. + */ +#ifdef _WIN32 + p->stat.ps_capt = bstats.bs_capt; +#endif + return (&p->stat); +} + +/* Set the dimension of the kernel-level capture buffer */ +static int +pcap_setbuff_npf(pcap_t *p, int dim) +{ + struct pcap_win *pw = p->priv; + + if(PacketSetBuff(pw->adapter,dim)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); + return (-1); + } + return (0); +} + +/* Set the driver working mode */ +static int +pcap_setmode_npf(pcap_t *p, int mode) +{ + struct pcap_win *pw = p->priv; + + if(PacketSetMode(pw->adapter,mode)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); + return (-1); + } + + return (0); +} + +/*set the minimum amount of data that will release a read call*/ +static int +pcap_setmintocopy_npf(pcap_t *p, int size) +{ + struct pcap_win *pw = p->priv; + + if(PacketSetMinToCopy(pw->adapter, size)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); + return (-1); + } + return (0); +} + +static HANDLE +pcap_getevent_npf(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + + return (PacketGetReadEvent(pw->adapter)); +} + +static int +pcap_oid_get_request_npf(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) +{ + struct pcap_win *pw = p->priv; + + return (oid_get_request(pw->adapter, oid, data, lenp, p->errbuf)); +} + +static int +pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, + size_t *lenp) +{ + struct pcap_win *pw = p->priv; + PACKET_OID_DATA *oid_data_arg; + + /* + * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). + * It should be big enough to hold "*lenp" bytes of data; it + * will actually be slightly larger, as PACKET_OID_DATA has a + * 1-byte data array at the end, standing in for the variable-length + * data that's actually there. + */ + oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); + if (oid_data_arg == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Couldn't allocate argument buffer for PacketRequest"); + return (PCAP_ERROR); + } + + oid_data_arg->Oid = oid; + oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ + memcpy(oid_data_arg->Data, data, *lenp); + if (!PacketRequest(pw->adapter, TRUE, oid_data_arg)) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); + free(oid_data_arg); + return (PCAP_ERROR); + } + + /* + * Get the length actually copied. + */ + *lenp = oid_data_arg->Length; + + /* + * No need to copy the data - we're doing a set. + */ + free(oid_data_arg); + return (0); +} + +static u_int +pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) +{ + struct pcap_win *pw = p->priv; + u_int res; + + res = PacketSendPackets(pw->adapter, + queue->buffer, + queue->len, + (BOOLEAN)sync); + + if(res != queue->len){ + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error queueing packets"); + } + + return (res); +} + +static int +pcap_setuserbuffer_npf(pcap_t *p, int size) +{ + unsigned char *new_buff; + + if (size<=0) { + /* Bogus parameter */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error: invalid size %d",size); + return (-1); + } + + /* Allocate the buffer */ + new_buff=(unsigned char*)malloc(sizeof(char)*size); + + if (!new_buff) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error: not enough memory"); + return (-1); + } + + free(p->buffer); + + p->buffer=new_buff; + p->bufsize=size; + + return (0); +} + +#ifdef HAVE_NPCAP_PACKET_API +/* + * Kernel dump mode isn't supported in Npcap; calls to PacketSetDumpName(), + * PacketSetDumpLimits(), and PacketIsDumpEnded() will get compile-time + * deprecation warnings. + * + * Avoid calling them; just return errors indicating that kernel dump + * mode isn't supported in Npcap. + */ +static int +pcap_live_dump_npf(pcap_t *p, char *filename _U_, int maxsize _U_, + int maxpacks _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Npcap doesn't support kernel dump mode"); + return (-1); +} +static int +pcap_live_dump_ended_npf(pcap_t *p, int sync) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Npcap doesn't support kernel dump mode"); + return (-1); +} +#else /* HAVE_NPCAP_PACKET_API */ +static int +pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks) +{ + struct pcap_win *pw = p->priv; + BOOLEAN res; + + /* Set the packet driver in dump mode */ + res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP); + if(res == FALSE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error setting dump mode"); + return (-1); + } + + /* Set the name of the dump file */ + res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename)); + if(res == FALSE){ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error setting kernel dump file name"); + return (-1); + } + + /* Set the limits of the dump file */ + res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks); + if(res == FALSE) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Error setting dump limit"); + return (-1); + } + + return (0); +} + +static int +pcap_live_dump_ended_npf(pcap_t *p, int sync) +{ + struct pcap_win *pw = p->priv; + + return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync)); +} +#endif /* HAVE_NPCAP_PACKET_API */ + +#ifdef HAVE_AIRPCAP_API +static PAirpcapHandle +pcap_get_airpcap_handle_npf(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + + return (PacketGetAirPcapHandle(pw->adapter)); +} +#else /* HAVE_AIRPCAP_API */ +static PAirpcapHandle +pcap_get_airpcap_handle_npf(pcap_t *p _U_) +{ + return (NULL); +} +#endif /* HAVE_AIRPCAP_API */ + +static int +pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + PACKET Packet; + int cc; + int n; + register u_char *bp, *ep; + u_char *datap; + struct pcap_win *pw = p->priv; + + cc = p->cc; + if (cc == 0) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + + /* + * Capture the packets. + * + * The PACKET structure had a bunch of extra stuff for + * Windows 9x/Me, but the only interesting data in it + * in the versions of Windows that we support is just + * a copy of p->buffer, a copy of p->buflen, and the + * actual number of bytes read returned from + * PacketReceivePacket(), none of which has to be + * retained from call to call, so we just keep one on + * the stack. + */ + PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); + if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { + /* + * Did the device go away? + * If so, the error we get can either be + * ERROR_GEN_FAILURE or ERROR_DEVICE_REMOVED. + */ + DWORD errcode = GetLastError(); + + if (errcode == ERROR_GEN_FAILURE || + errcode == ERROR_DEVICE_REMOVED) { + /* + * The device on which we're capturing + * went away, or it became unusable + * by NPF due to a suspend/resume. + * + * ERROR_GEN_FAILURE comes from + * STATUS_UNSUCCESSFUL, as well as some + * other NT status codes that the Npcap + * driver is unlikely to return. + * XXX - hopefully no other error + * conditions are indicated by this. + * + * ERROR_DEVICE_REMOVED comes from + * STATUS_DEVICE_REMOVED. + * + * We report the Windows status code + * name and the corresponding NT status + * code name, for the benefit of attempts + * to debug cases where this error is + * reported when the device *wasn't* + * removed, either because it's not + * removable, it's removable but wasn't + * removed, or it's a device that doesn't + * correspond to a physical device. + * + * XXX - we really should return an + * appropriate error for that, but + * pcap_dispatch() etc. aren't + * documented as having error returns + * other than PCAP_ERROR or PCAP_ERROR_BREAK. + */ + const char *errcode_msg; + + if (errcode == ERROR_GEN_FAILURE) + errcode_msg = "ERROR_GEN_FAILURE/STATUS_UNSUCCESSFUL"; + else + errcode_msg = "ERROR_DEVICE_REMOVED/STATUS_DEVICE_REMOVED"; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The interface disappeared (error code %s)", + errcode_msg); + } else { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, errcode, + "PacketReceivePacket error"); + } + return (PCAP_ERROR); + } + + cc = Packet.ulBytesReceived; + + bp = p->buffer; + } + else + bp = p->bp; + + /* + * Loop through each packet. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ +#define bhp ((struct bpf_hdr *)bp) + n = 0; + ep = bp + cc; + for (;;) { + register u_int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return PCAP_ERROR_BREAK + * to indicate that we were told to break out of the loop, + * otherwise leave the flag set, so that the *next* call + * will break out of the loop without having read any + * packets, and return the number of packets we've + * processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } else { + p->bp = bp; + p->cc = (int) (ep - bp); + return (n); + } + } + if (bp >= ep) + break; + + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + datap = bp + hdrlen; + + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * + * XXX - pcapint_filter() should always return TRUE if + * handed a null pointer for the program, but it might + * just try to "run" the filter, so we check here. + */ + if (pw->filtering_in_kernel || + p->fcode.bf_insns == NULL || + pcapint_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { +#ifdef ENABLE_REMOTE + switch (p->rmt_samp.method) { + + case PCAP_SAMP_1_EVERY_N: + pw->samp_npkt = (pw->samp_npkt + 1) % p->rmt_samp.value; + + /* Discard all packets that are not '1 out of N' */ + if (pw->samp_npkt != 0) { + bp += Packet_WORDALIGN(caplen + hdrlen); + continue; + } + break; + + case PCAP_SAMP_FIRST_AFTER_N_MS: + { + struct pcap_pkthdr *pkt_header = (struct pcap_pkthdr*) bp; + + /* + * Check if the timestamp of the arrived + * packet is smaller than our target time. + */ + if (pkt_header->ts.tv_sec < pw->samp_time.tv_sec || + (pkt_header->ts.tv_sec == pw->samp_time.tv_sec && pkt_header->ts.tv_usec < pw->samp_time.tv_usec)) { + bp += Packet_WORDALIGN(caplen + hdrlen); + continue; + } + + /* + * The arrived packet is suitable for being + * delivered to our caller, so let's update + * the target time. + */ + pw->samp_time.tv_usec = pkt_header->ts.tv_usec + p->rmt_samp.value * 1000; + if (pw->samp_time.tv_usec > 1000000) { + pw->samp_time.tv_sec = pkt_header->ts.tv_sec + pw->samp_time.tv_usec / 1000000; + pw->samp_time.tv_usec = pw->samp_time.tv_usec % 1000000; + } + } + } +#endif /* ENABLE_REMOTE */ + + /* + * XXX A bpf_hdr matches a pcap_pkthdr. + */ + (*callback)(user, (struct pcap_pkthdr*)bp, datap); + bp += Packet_WORDALIGN(caplen + hdrlen); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->bp = bp; + p->cc = (int) (ep - bp); + return (n); + } + } else { + /* + * Skip this packet. + */ + bp += Packet_WORDALIGN(caplen + hdrlen); + } + } +#undef bhp + p->cc = 0; + return (n); +} + +#ifdef HAVE_DAG_API +static int +pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_win *pw = p->priv; + PACKET Packet; + u_char *dp = NULL; + int packet_len = 0, caplen = 0; + struct pcap_pkthdr pcap_header; + u_char *endofbuf; + int n = 0; + dag_record_t *header; + unsigned erf_record_len; + ULONGLONG ts; + int cc; + unsigned swt; + unsigned dfp = pw->adapter->DagFastProcess; + + cc = p->cc; + if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ + { + /* + * Get new packets from the network. + * + * The PACKET structure had a bunch of extra stuff for + * Windows 9x/Me, but the only interesting data in it + * in the versions of Windows that we support is just + * a copy of p->buffer, a copy of p->buflen, and the + * actual number of bytes read returned from + * PacketReceivePacket(), none of which has to be + * retained from call to call, so we just keep one on + * the stack. + */ + PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); + if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); + return (-1); + } + + cc = Packet.ulBytesReceived; + if(cc == 0) + /* The timeout has expired but we no packets arrived */ + return (0); + header = (dag_record_t*)pw->adapter->DagBuffer; + } + else + header = (dag_record_t*)p->bp; + + endofbuf = (char*)header + cc; + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(cnt)) + cnt = INT_MAX; + + /* + * Cycle through the packets + */ + do + { + erf_record_len = SWAPS(header->rlen); + if((char*)header + erf_record_len > endofbuf) + break; + + /* Increase the number of captured packets */ + p->stat.ps_recv++; + + /* Find the beginning of the packet */ + dp = ((u_char *)header) + dag_record_size; + + /* Determine actual packet len */ + switch(header->type) + { + case TYPE_ATM: + packet_len = ATM_SNAPLEN; + caplen = ATM_SNAPLEN; + dp += 4; + + break; + + case TYPE_ETH: + swt = SWAPS(header->wlen); + packet_len = swt - (pw->dag_fcs_bits); + caplen = erf_record_len - dag_record_size - 2; + if (caplen > packet_len) + { + caplen = packet_len; + } + dp += 2; + + break; + + case TYPE_HDLC_POS: + swt = SWAPS(header->wlen); + packet_len = swt - (pw->dag_fcs_bits); + caplen = erf_record_len - dag_record_size; + if (caplen > packet_len) + { + caplen = packet_len; + } + + break; + } + + if(caplen > p->snapshot) + caplen = p->snapshot; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) + { + if (n == 0) + { + p->break_loop = 0; + return (-2); + } + else + { + p->bp = (char*)header; + p->cc = endofbuf - (char*)header; + return (n); + } + } + + if(!dfp) + { + /* convert between timestamp formats */ + ts = header->ts; + pcap_header.ts.tv_sec = (int)(ts >> 32); + ts = (ts & 0xffffffffi64) * 1000000; + ts += 0x80000000; /* rounding */ + pcap_header.ts.tv_usec = (int)(ts >> 32); + if (pcap_header.ts.tv_usec >= 1000000) { + pcap_header.ts.tv_usec -= 1000000; + pcap_header.ts.tv_sec++; + } + } + + /* No underlying filtering system. We need to filter on our own */ + if (p->fcode.bf_insns) + { + if (pcapint_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) + { + /* Move to next packet */ + header = (dag_record_t*)((char*)header + erf_record_len); + continue; + } + } + + /* Fill the header for the user supplied callback function */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Call the callback function */ + (*callback)(user, &pcap_header, dp); + + /* Move to next packet */ + header = (dag_record_t*)((char*)header + erf_record_len); + + /* Stop if the number of packets requested by user has been reached*/ + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) + { + p->bp = (char*)header; + p->cc = endofbuf - (char*)header; + return (n); + } + } + while((u_char*)header < endofbuf); + + return (1); +} +#endif /* HAVE_DAG_API */ + +/* Send a packet to the network */ +static int +pcap_inject_npf(pcap_t *p, const void *buf, int size) +{ + struct pcap_win *pw = p->priv; + PACKET pkt; + + PacketInitPacket(&pkt, (PVOID)buf, size); + if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "send error: PacketSendPacket failed"); + return (-1); + } + + /* + * We assume it all got sent if "PacketSendPacket()" succeeded. + * "pcap_inject()" is expected to return the number of bytes + * sent. + */ + return (size); +} + +static void +pcap_cleanup_npf(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + + if (pw->adapter != NULL) { + PacketCloseAdapter(pw->adapter); + pw->adapter = NULL; + } + if (pw->rfmon_selfstart) + { + PacketSetMonitorMode(p->opt.device, 0); + } + pcapint_cleanup_live_common(p); +} + +static void +pcap_breakloop_npf(pcap_t *p) +{ + pcapint_breakloop_common(p); + struct pcap_win *pw = p->priv; + + /* XXX - what if this fails? */ + SetEvent(PacketGetReadEvent(pw->adapter)); +} + +static int +pcap_activate_npf(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + NetType type; + int res; + int status = 0; + struct bpf_insn total_insn; + struct bpf_program total_prog; + + if (p->opt.rfmon) { + /* + * Monitor mode is supported on Windows Vista and later. + */ + if (PacketGetMonitorMode(p->opt.device) == 1) + { + pw->rfmon_selfstart = 0; + } + else + { + if ((res = PacketSetMonitorMode(p->opt.device, 1)) != 1) + { + pw->rfmon_selfstart = 0; + // Monitor mode is not supported. + if (res == 0) + { + return PCAP_ERROR_RFMON_NOTSUP; + } + else + { + return PCAP_ERROR; + } + } + else + { + pw->rfmon_selfstart = 1; + } + } + } + + /* Init Winsock if it hasn't already been initialized */ + pcap_wsockinit(); + + pw->adapter = PacketOpenAdapter(p->opt.device); + + if (pw->adapter == NULL) + { + DWORD errcode = GetLastError(); + + /* + * What error did we get when trying to open the adapter? + */ + switch (errcode) { + + case ERROR_BAD_UNIT: + /* + * There's no such device. + * There's nothing to add, so clear the error + * message. + */ + p->errbuf[0] = '\0'; + return (PCAP_ERROR_NO_SUCH_DEVICE); + + case ERROR_ACCESS_DENIED: + /* + * There is, but we don't have permission to + * use it. + * + * XXX - we currently get ERROR_BAD_UNIT if the + * user says "no" to the UAC prompt. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The helper program for \"Admin-only Mode\" must be allowed to make changes to your device"); + return (PCAP_ERROR_PERM_DENIED); + + default: + /* + * Unknown - report details. + */ + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + errcode, "Error opening adapter"); + if (pw->rfmon_selfstart) + { + PacketSetMonitorMode(p->opt.device, 0); + } + return (PCAP_ERROR); + } + } + + /*get network type*/ + if(PacketGetNetType (pw->adapter,&type) == FALSE) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot determine the network type"); + goto bad; + } + + /*Set the linktype*/ + switch (type.LinkType) + { + /* + * NDIS-defined medium types. + */ + case NdisMedium802_3: + p->linktype = DLT_EN10MB; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) + { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + break; + + case NdisMedium802_5: + /* + * Token Ring. + */ + p->linktype = DLT_IEEE802; + break; + + case NdisMediumFddi: + p->linktype = DLT_FDDI; + break; + + case NdisMediumWan: + p->linktype = DLT_EN10MB; + break; + + case NdisMediumArcnetRaw: + p->linktype = DLT_ARCNET; + break; + + case NdisMediumArcnet878_2: + p->linktype = DLT_ARCNET; + break; + + case NdisMediumAtm: + p->linktype = DLT_ATM_RFC1483; + break; + + case NdisMediumWirelessWan: + p->linktype = DLT_RAW; + break; + + case NdisMediumIP: + p->linktype = DLT_RAW; + break; + + /* + * Npcap-defined medium types. + */ + case NdisMediumNull: + p->linktype = DLT_NULL; + break; + + case NdisMediumCHDLC: + p->linktype = DLT_CHDLC; + break; + + case NdisMediumPPPSerial: + p->linktype = DLT_PPP_SERIAL; + break; + + case NdisMediumBare80211: + p->linktype = DLT_IEEE802_11; + break; + + case NdisMediumRadio80211: + p->linktype = DLT_IEEE802_11_RADIO; + break; + + case NdisMediumPpi: + p->linktype = DLT_PPI; + break; + + default: + /* + * An unknown medium type is assumed to supply Ethernet + * headers; if not, the user will have to report it, + * so that the medium type and link-layer header type + * can be determined. If we were to fail here, we + * might get the link-layer type in the error, but + * the user wouldn't get a capture, so we wouldn't + * be able to determine the link-layer type; we report + * a warning with the link-layer type, so at least + * some programs will report the warning. + */ + p->linktype = DLT_EN10MB; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Unknown NdisMedium value %d, defaulting to DLT_EN10MB", + type.LinkType); + status = PCAP_WARNING; + break; + } + +#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES + /* + * Set the timestamp type. + * (Yes, we require PacketGetTimestampModes(), not just + * PacketSetTimestampMode(). If we have the former, we + * have the latter, unless somebody's using a version + * of Npcap that they've hacked to provide the former + * but not the latter; if they've done that, either + * they're confused or they're trolling us.) + */ + switch (p->opt.tstamp_type) { + + case PCAP_TSTAMP_HOST_HIPREC_UNSYNCED: + /* + * Better than low-res, but *not* synchronized with + * the OS clock. + */ + if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_SINGLE_SYNCHRONIZATION)) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_SINGLE_SYNCHRONIZATION"); + goto bad; + } + break; + + case PCAP_TSTAMP_HOST_LOWPREC: + /* + * Low-res, but synchronized with the OS clock. + */ + if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME)) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME"); + goto bad; + } + break; + + case PCAP_TSTAMP_HOST_HIPREC: + /* + * High-res, and synchronized with the OS clock. + */ + if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE)) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE"); + goto bad; + } + break; + + case PCAP_TSTAMP_HOST: + /* + * XXX - do whatever the default is, for now. + * Set to the highest resolution that's synchronized + * with the system clock? + */ + break; + } +#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */ + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + /* Set promiscuous mode */ + if (p->opt.promisc) + { + /* + * For future reference, in case we ever want to query + * whether an adapter supports promiscuous mode, that + * would be done on Windows by querying the value + * of the OID_GEN_SUPPORTED_PACKET_FILTERS OID. + */ + if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) + { + DWORD errcode = GetLastError(); + + /* + * Suppress spurious error generated by non-compliant + * MS Surface mobile adapters that appear to + * return NDIS_STATUS_NOT_SUPPORTED for attempts + * to set the hardware filter. + * + * It appears to be reporting NDIS_STATUS_NOT_SUPPORTED, + * but with the NT status value "Customer" bit set; + * the Npcap NPF driver sets that bit in some cases. + * + * If we knew that this meant "promiscuous mode + * isn't supported", we could add a "promiscuous + * mode isn't supported" error code and return + * that, but: + * + * 1) we don't know that it means that + * rather than meaning "we reject attempts + * to set the filter, even though the NDIS + * specifications say you shouldn't do that" + * + * and + * + * 2) other interface types that don't + * support promiscuous mode, at least + * on UN*Xes, just silently ignore + * attempts to set promiscuous mode + * + * and rejecting it with an error could disrupt + * attempts to capture, as many programs (tcpdump, + * *shark) default to promiscuous mode. + * + * Alternatively, we could return the "promiscuous + * mode not supported" *warning* value, so that + * correct code will either ignore it or report + * it and continue capturing. (This may require + * a pcap_init() flag to request that return + * value, so that old incorrect programs that + * assume a non-zero return from pcap_activate() + * is an error don't break.) + * + * We check here for ERROR_NOT_SUPPORTED, which + * is what NDIS_STATUS_NOT_SUPPORTED (which is + * the same value as the NTSTATUS value + * STATUS_NOT_SUPPORTED) gets mapped to, as + * well as NDIS_STATUS_NOT_SUPPORTED with the + * "Customer" bit set. + */ + if (errcode != ERROR_NOT_SUPPORTED && + errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED)) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, errcode, + "failed to set hardware filter to promiscuous mode"); + goto bad; + } + } + } + else + { + /* + * NDIS_PACKET_TYPE_ALL_LOCAL selects "All packets sent by + * installed protocols and all packets indicated by the NIC", + * but if no protocol drivers (like TCP/IP) are installed, + * NDIS_PACKET_TYPE_DIRECTED, NDIS_PACKET_TYPE_BROADCAST, + * and NDIS_PACKET_TYPE_MULTICAST are needed to capture + * incoming frames. + */ + if (PacketSetHwFilter(pw->adapter, + NDIS_PACKET_TYPE_ALL_LOCAL | + NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_MULTICAST) == FALSE) + { + DWORD errcode = GetLastError(); + + /* + * Suppress spurious error generated by non-compliant + * MS Surface mobile adapters. + */ + if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED)) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, errcode, + "failed to set hardware filter to non-promiscuous mode"); + goto bad; + } + } + } + + /* Set the buffer size */ + p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; + + if(!(pw->adapter->Flags & INFO_FLAG_DAG_CARD)) + { + /* + * Traditional Adapter + */ + /* + * If the buffer size wasn't explicitly set, default to + * WIN32_DEFAULT_KERNEL_BUFFER_SIZE. + */ + if (p->opt.buffer_size == 0) + p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; + + if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); + goto bad; + } + + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) + { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + + if (p->opt.immediate) + { + /* tell the driver to copy the buffer as soon as data arrives */ + if(PacketSetMinToCopy(pw->adapter,0)==FALSE) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); + goto bad; + } + } + else + { + /* tell the driver to copy the buffer only if it contains at least 16K */ + if(PacketSetMinToCopy(pw->adapter,16000)==FALSE) + { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); + goto bad; + } + } + } else { + /* + * Dag Card + */ +#ifdef HAVE_DAG_API + /* + * We have DAG support. + */ + LONG status; + HKEY dagkey; + DWORD lptype; + DWORD lpcbdata; + int postype = 0; + char keyname[512]; + + snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", + "SYSTEM\\CurrentControlSet\\Services\\DAG", + strstr(_strlwr(p->opt.device), "dag")); + do + { + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); + if(status != ERROR_SUCCESS) + break; + + status = RegQueryValueEx(dagkey, + "PosType", + NULL, + &lptype, + (char*)&postype, + &lpcbdata); + + if(status != ERROR_SUCCESS) + { + postype = 0; + } + + RegCloseKey(dagkey); + } + while(FALSE); + + + p->snapshot = PacketSetSnapLen(pw->adapter, p->snapshot); + + /* Set the length of the FCS associated to any packet. This value + * will be subtracted to the packet length */ + pw->dag_fcs_bits = pw->adapter->DagFcsLen; +#else /* HAVE_DAG_API */ + /* + * No DAG support. + */ + goto bad; +#endif /* HAVE_DAG_API */ + } + + /* + * If there's no filter program installed, there's + * no indication to the kernel of what the snapshot + * length should be, so no snapshotting is done. + * + * Therefore, when we open the device, we install + * an "accept everything" filter with the specified + * snapshot length. + */ + total_insn.code = (u_short)(BPF_RET | BPF_K); + total_insn.jt = 0; + total_insn.jf = 0; + total_insn.k = p->snapshot; + + total_prog.bf_len = 1; + total_prog.bf_insns = &total_insn; + if (!PacketSetBpf(pw->adapter, &total_prog)) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketSetBpf"); + status = PCAP_ERROR; + goto bad; + } + + PacketSetReadTimeout(pw->adapter, p->opt.timeout); + + /* disable loopback capture if requested */ + if (p->opt.nocapture_local) + { + if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK)) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Unable to disable the capture of loopback packets."); + goto bad; + } + } + +#ifdef HAVE_DAG_API + if(pw->adapter->Flags & INFO_FLAG_DAG_CARD) + { + /* install dag specific handlers for read and setfilter */ + p->read_op = pcap_read_win32_dag; + p->setfilter_op = pcap_setfilter_win32_dag; + } + else + { +#endif /* HAVE_DAG_API */ + /* install traditional npf handlers for read and setfilter */ + p->read_op = pcap_read_npf; + p->setfilter_op = pcap_setfilter_npf; +#ifdef HAVE_DAG_API + } +#endif /* HAVE_DAG_API */ + p->setdirection_op = NULL; /* Not implemented. */ + /* XXX - can this be implemented on some versions of Windows? */ + p->inject_op = pcap_inject_npf; + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcap_getnonblock_npf; + p->setnonblock_op = pcap_setnonblock_npf; + p->stats_op = pcap_stats_npf; + p->breakloop_op = pcap_breakloop_npf; + p->stats_ex_op = pcap_stats_ex_npf; + p->setbuff_op = pcap_setbuff_npf; + p->setmode_op = pcap_setmode_npf; + p->setmintocopy_op = pcap_setmintocopy_npf; + p->getevent_op = pcap_getevent_npf; + p->oid_get_request_op = pcap_oid_get_request_npf; + p->oid_set_request_op = pcap_oid_set_request_npf; + p->sendqueue_transmit_op = pcap_sendqueue_transmit_npf; + p->setuserbuffer_op = pcap_setuserbuffer_npf; + p->live_dump_op = pcap_live_dump_npf; + p->live_dump_ended_op = pcap_live_dump_ended_npf; + p->get_airpcap_handle_op = pcap_get_airpcap_handle_npf; + p->cleanup_op = pcap_cleanup_npf; + + /* + * XXX - this is only done because WinPcap supported + * pcap_fileno() returning the hFile HANDLE from the + * ADAPTER structure. We make no general guarantees + * that the caller can do anything useful with it. + * + * (Not that we make any general guarantee of that + * sort on UN*X, either, anymore, given that not + * all capture devices are regular OS network + * interfaces.) + */ + p->handle = pw->adapter->hFile; + + return (status); +bad: + pcap_cleanup_npf(p); + return (PCAP_ERROR); +} + +/* +* Check if rfmon mode is supported on the pcap_t for Windows systems. +*/ +static int +pcap_can_set_rfmon_npf(pcap_t *p) +{ + return (PacketIsMonitorModeSupported(p->opt.device) == 1); +} + +/* + * Get a list of time stamp types. + */ +#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES +static int +get_ts_types(const char *device, pcap_t *p, char *ebuf) +{ + char *device_copy = NULL; + ADAPTER *adapter = NULL; + ULONG num_ts_modes; + /* Npcap 1.00 driver is buggy and will write 16 bytes regardless of + * buffer size. Using a sufficient stack buffer avoids overflow and + * avoids a heap allocation in most (currently all) cases. + */ + ULONG ts_modes[4]; + BOOL ret; + DWORD error = ERROR_SUCCESS; + ULONG *modes = NULL; + int status = 0; + + do { + /* + * First, find out how many time stamp modes we have. + * To do that, we have to open the adapter. + * + * XXX - PacketOpenAdapter() takes a non-const pointer + * as an argument, so we make a copy of the argument and + * pass that to it. + */ + device_copy = strdup(device); + if (device_copy == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); + status = -1; + break; + } + + adapter = PacketOpenAdapter(device_copy); + if (adapter == NULL) + { + error = GetLastError(); + /* + * If we can't open the device now, we won't be + * able to later, either. + * + * If the error is something that indicates + * that the device doesn't exist, or that they + * don't have permission to open the device - or + * perhaps that they don't have permission to get + * a list of devices, if PacketOpenAdapter() does + * that - the user will find that out when they try + * to activate the device; just return an empty + * list of time stamp types. + * + * Treating either of those as errors will, for + * example, cause "tcpdump -i " to fail, + * because it first tries to pass the interface + * name to pcap_create() and pcap_activate(), + * in order to handle OSes where interfaces can + * have names that are just numbers (stand up + * and say hello, Linux!), and, if pcap_activate() + * fails with a "no such device" error, checks + * whether the interface name is a valid number + * and, if so, tries to use it as an index in + * the list of interfaces. + * + * That means pcap_create() must succeed even + * for interfaces that don't exist, with the + * failure occurring at pcap_activate() time. + */ + if (error == ERROR_BAD_UNIT || + error == ERROR_ACCESS_DENIED) { + p->tstamp_type_count = 0; + p->tstamp_type_list = NULL; + status = 0; + } else { + pcapint_fmt_errmsg_for_win32_err(ebuf, + PCAP_ERRBUF_SIZE, error, + "Error opening adapter"); + status = -1; + } + break; + } + + /* + * Get the total number of time stamp modes. + * + * The buffer for PacketGetTimestampModes() is + * a sequence of 1 or more ULONGs. What's + * passed to PacketGetTimestampModes() should have + * the total number of ULONGs in the first ULONG; + * what's returned *from* PacketGetTimestampModes() + * has the total number of time stamp modes in + * the first ULONG. + * + * Yes, that means if there are N time stamp + * modes, the first ULONG should be set to N+1 + * on input, and will be set to N on output. + * + * We first make a call to PacketGetTimestampModes() + * with a pointer to a single ULONG set to 1; the + * call should fail with ERROR_MORE_DATA (unless + * there are *no* modes, but that should never + * happen), and that ULONG should be set to the + * number of modes. + */ + ts_modes[0] = sizeof(ts_modes) / sizeof(ULONG); + ret = PacketGetTimestampModes(adapter, ts_modes); + if (!ret) { + /* + * OK, it failed. Did it fail with + * ERROR_MORE_DATA? + */ + error = GetLastError(); + if (error != ERROR_MORE_DATA) { + /* + * No, did it fail with ERROR_INVALID_FUNCTION? + */ + if (error == ERROR_INVALID_FUNCTION) { + /* + * This is probably due to + * the driver with which Packet.dll + * communicates being older, or + * being a WinPcap driver, so + * that it doesn't support + * BIOCGTIMESTAMPMODES. + * + * Tell the user to try uninstalling + * Npcap - and WinPcap if installed - + * and re-installing it, to flush + * out all older drivers. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "PacketGetTimestampModes() failed with ERROR_INVALID_FUNCTION; try uninstalling Npcap, and WinPcap if installed, and re-installing it from npcap.com"); + status = -1; + break; + } + + /* + * No, some other error. Fail. + */ + pcapint_fmt_errmsg_for_win32_err(ebuf, + PCAP_ERRBUF_SIZE, error, + "Error calling PacketGetTimestampModes"); + status = -1; + break; + } + + /* + * Yes, so we now know how many types to fetch. + * + * The buffer needs to have one ULONG for the + * count and num_ts_modes ULONGs for the + * num_ts_modes time stamp types. + */ + num_ts_modes = ts_modes[0]; + modes = (ULONG *)malloc((1 + num_ts_modes) * sizeof(ULONG)); + if (modes == NULL) { + /* Out of memory. */ + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); + status = -1; + break; + } + modes[0] = 1 + num_ts_modes; + if (!PacketGetTimestampModes(adapter, modes)) { + pcapint_fmt_errmsg_for_win32_err(ebuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketGetTimestampModes"); + status = -1; + break; + } + if (modes[0] != num_ts_modes) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "First PacketGetTimestampModes() call gives %lu modes, second call gives %lu modes", + num_ts_modes, modes[0]); + status = -1; + break; + } + } + else { + modes = ts_modes; + num_ts_modes = ts_modes[0]; + } + + /* If the driver reports no modes supported *and* + * ERROR_MORE_DATA, something is seriously wrong. + * We *could* ignore the error and continue without supporting + * settable timestamp modes, but that would hide a bug. + */ + if (modes[0] == 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "PacketGetTimestampModes() reports 0 modes supported."); + status = -1; + break; + } + + /* + * Allocate a buffer big enough for + * PCAP_TSTAMP_HOST (default) plus + * the explicitly specified modes. + */ + p->tstamp_type_list = malloc((1 + num_ts_modes) * sizeof(u_int)); + if (p->tstamp_type_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc"); + status = -1; + break; + } + u_int num_ts_types = 0; + p->tstamp_type_list[num_ts_types] = + PCAP_TSTAMP_HOST; + num_ts_types++; + for (ULONG i = 0; i < num_ts_modes; i++) { + switch (modes[i + 1]) { + + case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION: + /* + * Better than low-res, + * but *not* synchronized + * with the OS clock. + */ + p->tstamp_type_list[num_ts_types] = + PCAP_TSTAMP_HOST_HIPREC_UNSYNCED; + num_ts_types++; + break; + + case TIMESTAMPMODE_QUERYSYSTEMTIME: + /* + * Low-res, but synchronized + * with the OS clock. + */ + p->tstamp_type_list[num_ts_types] = + PCAP_TSTAMP_HOST_LOWPREC; + num_ts_types++; + break; + + case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE: + /* + * High-res, and synchronized + * with the OS clock. + */ + p->tstamp_type_list[num_ts_types] = + PCAP_TSTAMP_HOST_HIPREC; + num_ts_types++; + break; + + default: + /* + * Unknown, so we can't + * report it. + */ + break; + } + } + p->tstamp_type_count = num_ts_types; + } while (0); + + /* Clean up temporary allocations */ + if (device_copy != NULL) { + free(device_copy); + } + if (modes != NULL && modes != ts_modes) { + free(modes); + } + if (adapter != NULL) { + PacketCloseAdapter(adapter); + } + + return status; +} +#else /* HAVE_PACKET_GET_TIMESTAMP_MODES */ +static int +get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_) +{ + /* + * Nothing to fetch, so it always "succeeds". + */ + return 0; +} +#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */ + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_win); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_npf; + p->can_set_rfmon_op = pcap_can_set_rfmon_npf; + + if (get_ts_types(device, p, ebuf) == -1) { + pcap_close(p); + return (NULL); + } + return (p); +} + +static int +pcap_setfilter_npf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_win *pw = p->priv; + + if(PacketSetBpf(pw->adapter,fp)==FALSE){ + /* + * Kernel filter not installed. + * + * XXX - we don't know whether this failed because: + * + * the kernel rejected the filter program as invalid, + * in which case we should fall back on userland + * filtering; + * + * the kernel rejected the filter program as too big, + * in which case we should again fall back on + * userland filtering; + * + * there was some other problem, in which case we + * should probably report an error. + * + * For NPF devices, the Win32 status will be + * STATUS_INVALID_DEVICE_REQUEST for invalid + * filters, but I don't know what it'd be for + * other problems, and for some other devices + * it might not be set at all. + * + * So we just fall back on userland filtering in + * all cases. + */ + + /* + * pcapint_install_bpf_program() validates the program. + * + * XXX - what if we already have a filter in the kernel? + */ + if (pcapint_install_bpf_program(p, fp) < 0) + return (-1); + pw->filtering_in_kernel = 0; /* filtering in userland */ + return (0); + } + + /* + * It worked. + */ + pw->filtering_in_kernel = 1; /* filtering in the kernel */ + + /* + * Discard any previously-received packets, as they might have + * passed whatever filter was formerly in effect, but might + * not pass this filter (BIOCSETF discards packets buffered + * in the kernel, so you can lose packets in any case). + */ + p->cc = 0; + return (0); +} + +/* + * We filter at user level, since the kernel driver doesn't process the packets + */ +static int +pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { + + if(!fp) + { + pcapint_strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); + return (-1); + } + + /* Install a user level filter */ + if (pcapint_install_bpf_program(p, fp) < 0) + return (-1); + + return (0); +} + +static int +pcap_getnonblock_npf(pcap_t *p) +{ + struct pcap_win *pw = p->priv; + + /* + * XXX - if there were a PacketGetReadTimeout() call, we + * would use it, and return 1 if the timeout is -1 + * and 0 otherwise. + */ + return (pw->nonblock); +} + +static int +pcap_setnonblock_npf(pcap_t *p, int nonblock) +{ + struct pcap_win *pw = p->priv; + int newtimeout; + + if (nonblock) { + /* + * Set the packet buffer timeout to -1 for non-blocking + * mode. + */ + newtimeout = -1; + } else { + /* + * Restore the timeout set when the device was opened. + * (Note that this may be -1, in which case we're not + * really leaving non-blocking mode. However, although + * the timeout argument to pcap_set_timeout() and + * pcap_open_live() is an int, you're not supposed to + * supply a negative value, so that "shouldn't happen".) + */ + newtimeout = p->opt.timeout; + } + if (!PacketSetReadTimeout(pw->adapter, newtimeout)) { + pcapint_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketSetReadTimeout"); + return (-1); + } + pw->nonblock = (newtimeout == -1); + return (0); +} + +static int +pcap_add_if_npf(pcap_if_list_t *devlistp, char *name, bpf_u_int32 flags, + const char *description, char *errbuf) +{ + pcap_if_t *curdev; + npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; + LONG if_addr_size; + int res = 0; + + if_addr_size = MAX_NETWORK_ADDRESSES; + + /* + * Add an entry for this interface, with no addresses. + */ + curdev = pcapint_add_dev(devlistp, name, flags, description, errbuf); + if (curdev == NULL) { + /* + * Failure. + */ + return (-1); + } + + /* + * Get the list of addresses for the interface. + */ + if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { + /* + * Failure. + * + * We don't return an error, because this can happen with + * NdisWan interfaces, and we want to supply them even + * if we can't supply their addresses. + * + * We return an entry with an empty address list. + */ + return (0); + } + + /* + * Now add the addresses. + */ + while (if_addr_size-- > 0) { + /* + * "curdev" is an entry for this interface; add an entry for + * this address to its list of addresses. + */ + res = pcapint_add_addr_to_dev(curdev, + (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, + sizeof (struct sockaddr_storage), + (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, + sizeof (struct sockaddr_storage), + (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, + sizeof (struct sockaddr_storage), + NULL, + 0, + errbuf); + if (res == -1) { + /* + * Failure. + */ + break; + } + } + + return (res); +} + +static int +get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) +{ + char *name_copy; + ADAPTER *adapter; + int status; + size_t len; + NDIS_HARDWARE_STATUS hardware_status; +#ifdef OID_GEN_PHYSICAL_MEDIUM + NDIS_PHYSICAL_MEDIUM phys_medium; + bpf_u_int32 gen_physical_medium_oids[] = { + #ifdef OID_GEN_PHYSICAL_MEDIUM_EX + OID_GEN_PHYSICAL_MEDIUM_EX, + #endif + OID_GEN_PHYSICAL_MEDIUM + }; +#define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0]) + size_t i; +#endif /* OID_GEN_PHYSICAL_MEDIUM */ +#ifdef OID_GEN_LINK_STATE + NDIS_LINK_STATE link_state; +#endif + int connect_status; + + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback interface, so the connection status doesn't + * apply. and it's not wireless (or wired, for that + * matter...). We presume it's up and running. + */ + *flags |= PCAP_IF_UP | PCAP_IF_RUNNING | PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + + /* + * We need to open the adapter to get this information. + * + * XXX - PacketOpenAdapter() takes a non-const pointer + * as an argument, so we make a copy of the argument and + * pass that to it. + */ + name_copy = strdup(name); + adapter = PacketOpenAdapter(name_copy); + free(name_copy); + if (adapter == NULL) { + /* + * Give up; if they try to open this device, it'll fail. + */ + return (0); + } + +#ifdef HAVE_AIRPCAP_API + /* + * Airpcap.sys do not support the below 'OID_GEN_x' values. + * Just set these flags (and none of the '*flags' entered with). + */ + if (PacketGetAirPcapHandle(adapter)) { + /* + * Must be "up" and "running" if the above if succeeded. + */ + *flags = PCAP_IF_UP | PCAP_IF_RUNNING; + + /* + * An airpcap device is a wireless device (duh!) + */ + *flags |= PCAP_IF_WIRELESS; + + /* + * A "network association state" makes no sense for airpcap. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + PacketCloseAdapter(adapter); + return (0); + } +#endif + + /* + * Get the hardware status, and derive "up" and "running" from + * that. + */ + len = sizeof (hardware_status); + status = oid_get_request(adapter, OID_GEN_HARDWARE_STATUS, + &hardware_status, &len, errbuf); + if (status == 0) { + switch (hardware_status) { + + case NdisHardwareStatusReady: + /* + * "Available and capable of sending and receiving + * data over the wire", so up and running. + */ + *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; + break; + + case NdisHardwareStatusInitializing: + case NdisHardwareStatusReset: + /* + * "Initializing" or "Resetting", so up, but + * not running. + */ + *flags |= PCAP_IF_UP; + break; + + case NdisHardwareStatusClosing: + case NdisHardwareStatusNotReady: + /* + * "Closing" or "Not ready", so neither up nor + * running. + */ + break; + + default: + /* + * Unknown. + */ + break; + } + } else { + /* + * Can't get the hardware status, so assume both up and + * running. + */ + *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; + } + + /* + * Get the network type. + */ +#ifdef OID_GEN_PHYSICAL_MEDIUM + /* + * Try the OIDs we have for this, in order. + */ + for (i = 0; i < N_GEN_PHYSICAL_MEDIUM_OIDS; i++) { + len = sizeof (phys_medium); + status = oid_get_request(adapter, gen_physical_medium_oids[i], + &phys_medium, &len, errbuf); + if (status == 0) { + /* + * Success. + */ + break; + } + /* + * Failed. We can't determine whether it failed + * because that particular OID isn't supported + * or because some other problem occurred, so we + * just drive on and try the next OID. + */ + } + if (status == 0) { + /* + * We got the physical medium. + * + * XXX - we might want to check for NdisPhysicalMediumWiMax + * and NdisPhysicalMediumNative802_15_4 being + * part of the enum, and check for those in the "wireless" + * case. + */ +DIAG_OFF_ENUM_SWITCH + switch (phys_medium) { + + case NdisPhysicalMediumWirelessLan: + case NdisPhysicalMediumWirelessWan: + case NdisPhysicalMediumNative802_11: + case NdisPhysicalMediumBluetooth: + case NdisPhysicalMediumUWB: + case NdisPhysicalMediumIrda: + /* + * Wireless. + */ + *flags |= PCAP_IF_WIRELESS; + break; + + default: + /* + * Not wireless or unknown + */ + break; + } +DIAG_ON_ENUM_SWITCH + } +#endif + + /* + * Get the connection status. + */ +#ifdef OID_GEN_LINK_STATE + len = sizeof(link_state); + status = oid_get_request(adapter, OID_GEN_LINK_STATE, &link_state, + &len, errbuf); + if (status == 0) { + /* + * NOTE: this also gives us the receive and transmit + * link state. + */ + switch (link_state.MediaConnectState) { + + case MediaConnectStateConnected: + /* + * It's connected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; + break; + + case MediaConnectStateDisconnected: + /* + * It's disconnected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + break; + + case MediaConnectStateUnknown: + default: + /* + * It's unknown whether it's connected or not. + */ + break; + } + } +#else + /* + * OID_GEN_LINK_STATE isn't supported because it's not in our SDK. + */ + status = -1; +#endif + if (status == -1) { + /* + * OK, OID_GEN_LINK_STATE didn't work, try + * OID_GEN_MEDIA_CONNECT_STATUS. + */ + status = oid_get_request(adapter, OID_GEN_MEDIA_CONNECT_STATUS, + &connect_status, &len, errbuf); + if (status == 0) { + switch (connect_status) { + + case NdisMediaStateConnected: + /* + * It's connected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; + break; + + case NdisMediaStateDisconnected: + /* + * It's disconnected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + break; + } + } + } + PacketCloseAdapter(adapter); + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + int ret = 0; + const char *desc; + char *AdaptersName; + ULONG NameLength; + char *name; + + /* + * Find out how big a buffer we need. + * + * This call should always return FALSE; if the error is + * ERROR_INSUFFICIENT_BUFFER, NameLength will be set to + * the size of the buffer we need, otherwise there's a + * problem, and NameLength should be set to 0. + * + * It shouldn't require NameLength to be set, but, + * at least as of WinPcap 4.1.3, it checks whether + * NameLength is big enough before it checks for a + * NULL buffer argument, so, while it'll still do + * the right thing if NameLength is uninitialized and + * whatever junk happens to be there is big enough + * (because the pointer argument will be null), it's + * still reading an uninitialized variable. + */ + NameLength = 0; + if (!PacketGetAdapterNames(NULL, &NameLength)) + { + DWORD last_error = GetLastError(); + + if (last_error != ERROR_INSUFFICIENT_BUFFER) + { + pcapint_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + last_error, "PacketGetAdapterNames"); + return (-1); + } + } + + if (NameLength <= 0) + return 0; + AdaptersName = (char*) malloc(NameLength); + if (AdaptersName == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); + return (-1); + } + + if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { + pcapint_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); + free(AdaptersName); + return (-1); + } + + /* + * "PacketGetAdapterNames()" returned a list of + * null-terminated ASCII interface name strings, + * terminated by a null string, followed by a list + * of null-terminated ASCII interface description + * strings, terminated by a null string. + * This means there are two ASCII nulls at the end + * of the first list. + * + * Find the end of the first list; that's the + * beginning of the second list. + */ + desc = &AdaptersName[0]; + while (*desc != '\0' || *(desc + 1) != '\0') + desc++; + + /* + * Found it - "desc" points to the first of the two + * nulls at the end of the list of names, so the + * first byte of the list of descriptions is two bytes + * after it. + */ + desc += 2; + + /* + * Loop over the elements in the first list. + */ + name = &AdaptersName[0]; + while (*name != '\0') { + bpf_u_int32 flags = 0; + +#ifdef HAVE_AIRPCAP_API + /* + * Is this an AirPcap device? + * If so, ignore it; it'll get added later, by the + * AirPcap code. + */ + if (device_is_airpcap(name, errbuf) == 1) { + name += strlen(name) + 1; + desc += strlen(desc) + 1; + continue; + } +#endif + +#ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER + /* + * Is this a loopback interface? + */ + if (PacketIsLoopbackAdapter(name)) { + /* Yes */ + flags |= PCAP_IF_LOOPBACK; + } +#endif + /* + * Get additional flags. + */ + if (get_if_flags(name, &flags, errbuf) == -1) { + /* + * Failure. + */ + ret = -1; + break; + } + + /* + * Add an entry for this interface. + */ + if (pcap_add_if_npf(devlistp, name, flags, desc, + errbuf) == -1) { + /* + * Failure. + */ + ret = -1; + break; + } + name += strlen(name) + 1; + desc += strlen(desc) + 1; + } + + free(AdaptersName); + return (ret); +} + +/* + * Return the name of a network interface attached to the system, or NULL + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + * + * In the best of all possible worlds, this would be the same as on + * UN*X, but there may be software that expects this to return a + * full list of devices after the first device. + */ +#define ADAPTERSNAME_LEN 8192 +char * +pcap_lookupdev(char *errbuf) +{ + DWORD dwVersion; + DWORD dwWindowsMajorVersion; + + /* + * We disable this in "new API" mode, because 1) in WinPcap/Npcap, + * it may return UTF-16 strings, for backwards-compatibility + * reasons, and we're also disabling the hack to make that work, + * for not-going-past-the-end-of-a-string reasons, and 2) we + * want its behavior to be consistent. + * + * In addition, it's not thread-safe, so we've marked it as + * deprecated. + */ + if (pcapint_new_api) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()"); + return (NULL); + } + +/* disable MSVC's GetVersion() deprecated warning here */ +DIAG_OFF_DEPRECATION + dwVersion = GetVersion(); /* get the OS version */ +DIAG_ON_DEPRECATION + dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + + if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { + /* + * Windows 95, 98, ME. + */ + ULONG NameLength = ADAPTERSNAME_LEN; + static char AdaptersName[ADAPTERSNAME_LEN]; + + if (PacketGetAdapterNames(AdaptersName,&NameLength) ) + return (AdaptersName); + else + return NULL; + } else { + /* + * Windows NT (NT 4.0 and later). + * Convert the names to Unicode for backward compatibility. + */ + ULONG NameLength = ADAPTERSNAME_LEN; + static WCHAR AdaptersName[ADAPTERSNAME_LEN]; + size_t BufferSpaceLeft; + char *tAstr; + WCHAR *Unameptr; + char *Adescptr; + size_t namelen, i; + WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR)); + int NAdapts = 0; + + if(TAdaptersName == NULL) + { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); + return NULL; + } + + if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) + { + pcapint_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); + free(TAdaptersName); + return NULL; + } + + + BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR); + tAstr = (char*)TAdaptersName; + Unameptr = AdaptersName; + + /* + * Convert the device names to Unicode into AdapterName. + */ + do { + /* + * Length of the name, including the terminating + * NUL. + */ + namelen = strlen(tAstr) + 1; + + /* + * Do we have room for the name in the Unicode + * buffer? + */ + if (BufferSpaceLeft < namelen * sizeof(WCHAR)) { + /* + * No. + */ + goto quit; + } + BufferSpaceLeft -= namelen * sizeof(WCHAR); + + /* + * Copy the name, converting ASCII to Unicode. + * namelen includes the NUL, so we copy it as + * well. + */ + for (i = 0; i < namelen; i++) + *Unameptr++ = *tAstr++; + + /* + * Count this adapter. + */ + NAdapts++; + } while (namelen != 1); + + /* + * Copy the descriptions, but don't convert them from + * ASCII to Unicode. + */ + Adescptr = (char *)Unameptr; + while(NAdapts--) + { + size_t desclen; + + desclen = strlen(tAstr) + 1; + + /* + * Do we have room for the name in the Unicode + * buffer? + */ + if (BufferSpaceLeft < desclen) { + /* + * No. + */ + goto quit; + } + + /* + * Just copy the ASCII string. + * namelen includes the NUL, so we copy it as + * well. + */ + memcpy(Adescptr, tAstr, desclen); + Adescptr += desclen; + tAstr += desclen; + BufferSpaceLeft -= desclen; + } + + quit: + free(TAdaptersName); + return (char *)(AdaptersName); + } +} + +/* + * We can't use the same code that we use on UN*X, as that's doing + * UN*X-specific calls. + * + * We don't just fetch the entire list of devices, search for the + * particular device, and use its first IPv4 address, as that's too + * much work to get just one device's netmask. + */ +int +pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, + char *errbuf) +{ + /* + * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() + * in order to skip non IPv4 (i.e. IPv6 addresses) + */ + npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; + LONG if_addr_size = MAX_NETWORK_ADDRESSES; + struct sockaddr_in *t_addr; + LONG i; + + if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { + *netp = *maskp = 0; + return (0); + } + + for(i = 0; i < if_addr_size; i++) + { + if(if_addrs[i].IPAddress.ss_family == AF_INET) + { + t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress); + *netp = t_addr->sin_addr.S_un.S_addr; + t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); + *maskp = t_addr->sin_addr.S_un.S_addr; + + *netp &= *maskp; + return (0); + } + + } + + *netp = *maskp = 0; + return (0); +} + +static const char *pcap_lib_version_string; + +#ifdef HAVE_VERSION_H +/* + * libpcap being built for Windows, as part of a WinPcap/Npcap source + * tree. Include version.h from that source tree to get the WinPcap/Npcap + * version. + * + * XXX - it'd be nice if we could somehow generate the WinPcap/Npcap version + * number when building as part of WinPcap/Npcap. (It'd be nice to do so + * for the packet.dll version number as well.) + */ +#include "../../version.h" + +static const char pcap_version_string[] = + WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING ", based on " PCAP_VERSION_STRING; + +const char * +pcap_lib_version(void) +{ + if (pcap_lib_version_string == NULL) { + /* + * Generate the version string. + */ + const char *packet_version_string = PacketGetVersion(); + + if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) { + /* + * WinPcap/Npcap version string and packet.dll version + * string are the same; just report the WinPcap/Npcap + * version. + */ + pcap_lib_version_string = pcap_version_string; + } else { + /* + * WinPcap/Npcap version string and packet.dll version + * string are different; that shouldn't be the + * case (the two libraries should come from the + * same version of WinPcap/Npcap), so we report both + * versions. + */ + char *full_pcap_version_string; + + if (pcapint_asprintf(&full_pcap_version_string, + WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING " (packet.dll version %s), based on " PCAP_VERSION_STRING, + packet_version_string) != -1) { + /* Success */ + pcap_lib_version_string = full_pcap_version_string; + } + } + } + return (pcap_lib_version_string); +} + +#else /* HAVE_VERSION_H */ + +/* + * libpcap being built for Windows, not as part of a WinPcap/Npcap source + * tree. + */ +const char * +pcap_lib_version(void) +{ + if (pcap_lib_version_string == NULL) { + /* + * Generate the version string. Report the packet.dll + * version. + */ + char *full_pcap_version_string; + + if (pcapint_asprintf(&full_pcap_version_string, + PCAP_VERSION_STRING " (packet.dll version %s)", + PacketGetVersion()) != -1) { + /* Success */ + pcap_lib_version_string = full_pcap_version_string; + } + } + return (pcap_lib_version_string); +} +#endif /* HAVE_VERSION_H */ diff --git a/src/libpcap-1.10.5/pcap-null.c b/src/libpcap-1.10.5/pcap-null.c new file mode 100644 index 0000000000..f0e35ec8b9 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-null.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include + +#include "pcap-int.h" + +static char nosup[] = "live packet capture not supported on this system"; + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + (void)pcapint_strlcpy(ebuf, nosup, PCAP_ERRBUF_SIZE); + return (NULL); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf _U_) +{ + /* + * There are no interfaces on which we can capture. + */ + return (0); +} + +#ifdef _WIN32 +int +pcap_lookupnet(const char *device _U_, bpf_u_int32 *netp _U_, + bpf_u_int32 *maskp _U_, char *errbuf) +{ + (void)pcapint_strlcpy(errbuf, nosup, PCAP_ERRBUF_SIZE); + return (-1); +} +#endif + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-pf.c b/src/libpcap-1.10.5/pcap-pf.c new file mode 100644 index 0000000000..cdad98821c --- /dev/null +++ b/src/libpcap-1.10.5/pcap-pf.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * packet filter subroutines for tcpdump + * Extraction/creation by Jeffrey Mogul, DECWRL + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +struct mbuf; +struct rtentry; +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we need various BPF ioctls from it. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * FDDI packets are padded to make everything line up on a nice boundary. + */ +#define PCAP_FDDIPAD 3 + +/* + * Private data for capturing on Ultrix and DEC OSF/1^WDigital UNIX^W^W + * Tru64 UNIX packetfilter devices. + */ +struct pcap_pf { + int filtering_in_kernel; /* using kernel filter */ + u_long TotPkts; /* can't overflow for 79 hrs on ether */ + u_long TotAccepted; /* count accepted by filter */ + u_long TotDrops; /* count of dropped packets */ + long TotMissed; /* missed by i/f during this run */ + long OrigMissed; /* missed by i/f before this run */ +}; + +static int pcap_setfilter_pf(pcap_t *, struct bpf_program *); + +/* + * BUFSPACE is the size in bytes of the packet read buffer. Most tcpdump + * applications aren't going to need more than 200 bytes of packet header + * and the read shouldn't return more packets than packetfilter's internal + * queue limit (bounded at 256). + */ +#define BUFSPACE (200 * 256) + +static int +pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_pf *pf = pc->priv; + register u_char *p, *bp; + register int cc, n, buflen, inc; + register struct enstamp *sp; + struct enstamp stamp; + register u_int pad; + + again: + cc = pc->cc; + if (cc == 0) { + cc = read(pc->fd, (char *)pc->buffer + pc->offset, pc->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + if (errno == EINVAL && + lseek(pc->fd, 0L, SEEK_CUR) + pc->bufsize < 0) { + /* + * Due to a kernel bug, after 2^31 bytes, + * the kernel file offset overflows and + * read fails with EINVAL. The lseek() + * to 0 will fix things. + */ + (void)lseek(pc->fd, 0L, SEEK_SET); + goto again; + } + pcapint_fmt_errmsg_for_errno(pc->errbuf, + sizeof(pc->errbuf), errno, "pf read"); + return (-1); + } + bp = (u_char *)pc->buffer + pc->offset; + } else + bp = pc->bp; + /* + * Loop through each packet. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ + n = 0; + pad = pc->fddipad; + while (cc > 0) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (pc->break_loop) { + if (n == 0) { + pc->break_loop = 0; + return (-2); + } else { + pc->cc = cc; + pc->bp = bp; + return (n); + } + } + if (cc < sizeof(*sp)) { + snprintf(pc->errbuf, sizeof(pc->errbuf), + "pf short read (%d)", cc); + return (-1); + } + if ((long)bp & 3) { + sp = &stamp; + memcpy((char *)sp, (char *)bp, sizeof(*sp)); + } else + sp = (struct enstamp *)bp; + if (sp->ens_stamplen != sizeof(*sp)) { + snprintf(pc->errbuf, sizeof(pc->errbuf), + "pf short stamplen (%d)", + sp->ens_stamplen); + return (-1); + } + + p = bp + sp->ens_stamplen; + buflen = sp->ens_count; + if (buflen > pc->snapshot) + buflen = pc->snapshot; + + /* Calculate inc before possible pad update */ + inc = ENALIGN(buflen + sp->ens_stamplen); + cc -= inc; + bp += inc; + pf->TotPkts++; + pf->TotDrops += sp->ens_dropped; + pf->TotMissed = sp->ens_ifoverflows; + if (pf->OrigMissed < 0) + pf->OrigMissed = pf->TotMissed; + + /* + * Short-circuit evaluation: if using BPF filter + * in kernel, no need to do it now - we already know + * the packet passed the filter. + * + * Note: the filter code was generated assuming + * that pc->fddipad was the amount of padding + * before the header, as that's what's required + * in the kernel, so we run the filter before + * skipping that padding. + */ + if (pf->filtering_in_kernel || + pcapint_filter(pc->fcode.bf_insns, p, sp->ens_count, buflen)) { + struct pcap_pkthdr h; + pf->TotAccepted++; + h.ts = sp->ens_tstamp; + h.len = sp->ens_count - pad; + p += pad; + buflen -= pad; + h.caplen = buflen; + (*callback)(user, &h, p); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + pc->cc = cc; + pc->bp = bp; + return (n); + } + } + } + pc->cc = 0; + return (n); +} + +static int +pcap_inject_pf(pcap_t *p, const void *buf, int size) +{ + int ret; + + ret = write(p->fd, buf, size); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + return (ret); +} + +static int +pcap_stats_pf(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_pf *pf = p->priv; + + /* + * If packet filtering is being done in the kernel: + * + * "ps_recv" counts only packets that passed the filter. + * This does not include packets dropped because we + * ran out of buffer space. (XXX - perhaps it should, + * by adding "ps_drop" to "ps_recv", for compatibility + * with some other platforms. On the other hand, on + * some platforms "ps_recv" counts only packets that + * passed the filter, and on others it counts packets + * that didn't pass the filter....) + * + * "ps_drop" counts packets that passed the kernel filter + * (if any) but were dropped because the input queue was + * full. + * + * "ps_ifdrop" counts packets dropped by the network + * interface (regardless of whether they would have passed + * the input filter, of course). + * + * If packet filtering is not being done in the kernel: + * + * "ps_recv" counts only packets that passed the filter. + * + * "ps_drop" counts packets that were dropped because the + * input queue was full, regardless of whether they passed + * the userland filter. + * + * "ps_ifdrop" counts packets dropped by the network + * interface (regardless of whether they would have passed + * the input filter, of course). + * + * These statistics don't include packets not yet read from + * the kernel by libpcap, but they may include packets not + * yet read from libpcap by the application. + */ + ps->ps_recv = pf->TotAccepted; + ps->ps_drop = pf->TotDrops; + ps->ps_ifdrop = pf->TotMissed - pf->OrigMissed; + return (0); +} + +/* + * We include the OS's , not our "pcap/bpf.h", so we probably + * don't get DLT_DOCSIS defined. + */ +#ifndef DLT_DOCSIS +#define DLT_DOCSIS 143 +#endif + +static int +pcap_activate_pf(pcap_t *p) +{ + struct pcap_pf *pf = p->priv; + short enmode; + int backlog = -1; /* request the most */ + struct enfilter Filter; + struct endevp devparams; + int err; + + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + * + * XXX - we assume here that "pfopen()" does not, in fact, modify + * its argument, even though it takes a "char *" rather than a + * "const char *" as its first argument. That appears to be + * the case, at least on Digital UNIX 4.0. + * + * XXX - is there an error that means "no such device"? Is + * there one that means "that device doesn't support pf"? + */ + p->fd = pfopen(p->opt.device, O_RDWR); + if (p->fd == -1 && errno == EACCES) + p->fd = pfopen(p->opt.device, O_RDONLY); + if (p->fd < 0) { + if (errno == EACCES) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "pf open: %s: Permission denied\n" +"your system may not be properly configured; see the packetfilter(4) man page", + p->opt.device); + err = PCAP_ERROR_PERM_DENIED; + } else { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "pf open: %s", p->opt.device); + err = PCAP_ERROR; + } + goto bad; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + pf->OrigMissed = -1; + enmode = ENTSTAMP|ENNONEXCL; + if (!p->opt.immediate) + enmode |= ENBATCH; + if (p->opt.promisc) + enmode |= ENPROMISC; + if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCMBIS"); + err = PCAP_ERROR; + goto bad; + } +#ifdef ENCOPYALL + /* Try to set COPYALL mode so that we see packets to ourself */ + enmode = ENCOPYALL; + (void)ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode);/* OK if this fails */ +#endif + /* set the backlog */ + if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCSETW"); + err = PCAP_ERROR; + goto bad; + } + /* discover interface type */ + if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCDEVP"); + err = PCAP_ERROR; + goto bad; + } + /* HACK: to compile prior to Ultrix 4.2 */ +#ifndef ENDT_FDDI +#define ENDT_FDDI 4 +#endif + switch (devparams.end_dev_type) { + + case ENDT_10MB: + p->linktype = DLT_EN10MB; + p->offset = 2; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + err = PCAP_ERROR; + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + break; + + case ENDT_FDDI: + p->linktype = DLT_FDDI; + break; + +#ifdef ENDT_SLIP + case ENDT_SLIP: + p->linktype = DLT_SLIP; + break; +#endif + +#ifdef ENDT_PPP + case ENDT_PPP: + p->linktype = DLT_PPP; + break; +#endif + +#ifdef ENDT_LOOPBACK + case ENDT_LOOPBACK: + /* + * It appears to use Ethernet framing, at least on + * Digital UNIX 4.0. + */ + p->linktype = DLT_EN10MB; + p->offset = 2; + break; +#endif + +#ifdef ENDT_TRN + case ENDT_TRN: + p->linktype = DLT_IEEE802; + break; +#endif + + default: + /* + * XXX - what about ENDT_IEEE802? The pfilt.h header + * file calls this "IEEE 802 networks (non-Ethernet)", + * but that doesn't specify a specific link layer type; + * it could be 802.4, or 802.5 (except that 802.5 is + * ENDT_TRN), or 802.6, or 802.11, or.... That's why + * DLT_IEEE802 was hijacked to mean Token Ring in various + * BSDs, and why we went along with that hijacking. + * + * XXX - what about ENDT_HDLC and ENDT_NULL? + * Presumably, as ENDT_OTHER is just "Miscellaneous + * framing", there's not much we can do, as that + * doesn't specify a particular type of header. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "unknown data-link type %u", devparams.end_dev_type); + err = PCAP_ERROR; + goto bad; + } + /* set truncation */ + if (p->linktype == DLT_FDDI) { + p->fddipad = PCAP_FDDIPAD; + + /* packetfilter includes the padding in the snapshot */ + p->snapshot += PCAP_FDDIPAD; + } else + p->fddipad = 0; + if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCTRUNCATE"); + err = PCAP_ERROR; + goto bad; + } + /* accept all packets */ + memset(&Filter, 0, sizeof(Filter)); + Filter.enf_Priority = 37; /* anything > 2 */ + Filter.enf_FilterLen = 0; /* means "always true" */ + if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCSETF"); + err = PCAP_ERROR; + goto bad; + } + + if (p->opt.timeout != 0) { + struct timeval timeout; + timeout.tv_sec = p->opt.timeout / 1000; + timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "EIOCSRTIMEOUT"); + err = PCAP_ERROR; + goto bad; + } + } + + p->bufsize = BUFSPACE; + p->buffer = malloc(p->bufsize + p->offset); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + err = PCAP_ERROR; + goto bad; + } + + /* + * "select()" and "poll()" work on packetfilter devices. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_pf; + p->inject_op = pcap_inject_pf; + p->setfilter_op = pcap_setfilter_pf; + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_pf; + + return (0); + bad: + pcapint_cleanup_live_common(p); + return (err); +} + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_pf); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_pf; + return (p); +} + +/* + * XXX - is there an error from pfopen() that means "no such device"? + * Is there one that means "that device doesn't support pf"? + */ +static int +can_be_bound(const char *name _U_) +{ + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do other than mark loopback devices as "the + * connected/disconnected status doesn't apply". + * + * XXX - is there a way to find out whether an adapter has + * something plugged into it? + */ + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound, + get_if_flags)); +} + +static int +pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp) +{ + struct pcap_pf *pf = p->priv; + struct bpf_version bv; + + /* + * See if BIOCVERSION works. If not, we assume the kernel doesn't + * support BPF-style filters (it's not documented in the bpf(7) + * or packetfilter(7) man pages, but the code used to fail if + * BIOCSETF worked but BIOCVERSION didn't, and I've seen it do + * kernel filtering in DU 4.0, so presumably BIOCVERSION works + * there, at least). + */ + if (ioctl(p->fd, BIOCVERSION, (caddr_t)&bv) >= 0) { + /* + * OK, we have the version of the BPF interpreter; + * is it the same major version as us, and the same + * or better minor version? + */ + if (bv.bv_major == BPF_MAJOR_VERSION && + bv.bv_minor >= BPF_MINOR_VERSION) { + /* + * Yes. Try to install the filter. + */ + if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + sizeof(p->errbuf), errno, "BIOCSETF"); + return (-1); + } + + /* + * OK, that succeeded. We're doing filtering in + * the kernel. (We assume we don't have a + * userland filter installed - that'd require + * a previous version check to have failed but + * this one to succeed.) + * + * XXX - this message should be supplied to the + * application as a warning of some sort, + * except that if it's a GUI application, it's + * not clear that it should be displayed in + * a window to annoy the user. + */ + fprintf(stderr, "tcpdump: Using kernel BPF filter\n"); + pf->filtering_in_kernel = 1; + + /* + * Discard any previously-received packets, + * as they might have passed whatever filter + * was formerly in effect, but might not pass + * this filter (BIOCSETF discards packets buffered + * in the kernel, so you can lose packets in any + * case). + */ + p->cc = 0; + return (0); + } + + /* + * We can't use the kernel's BPF interpreter; don't give + * up, just log a message and be inefficient. + * + * XXX - this should really be supplied to the application + * as a warning of some sort. + */ + fprintf(stderr, + "tcpdump: Requires BPF language %d.%d or higher; kernel is %d.%d\n", + BPF_MAJOR_VERSION, BPF_MINOR_VERSION, + bv.bv_major, bv.bv_minor); + } + + /* + * We couldn't do filtering in the kernel; do it in userland. + */ + if (pcapint_install_bpf_program(p, fp) < 0) + return (-1); + + /* + * XXX - this message should be supplied by the application as + * a warning of some sort. + */ + fprintf(stderr, "tcpdump: Filtering in user process\n"); + pf->filtering_in_kernel = 0; + return (0); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-rdmasniff.c b/src/libpcap-1.10.5/pcap-rdmasniff.c new file mode 100644 index 0000000000..fd6d6fa610 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-rdmasniff.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2017 Pure Storage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "pcap-int.h" +#include "pcap-rdmasniff.h" + +#include +#include +#include +#include /* for INT_MAX */ +#include + +#if !defined(IBV_FLOW_ATTR_SNIFFER) +#define IBV_FLOW_ATTR_SNIFFER 3 +#endif + +static const int RDMASNIFF_NUM_RECEIVES = 128; +static const int RDMASNIFF_RECEIVE_SIZE = 10000; + +struct pcap_rdmasniff { + struct ibv_device * rdma_device; + struct ibv_context * context; + struct ibv_comp_channel * channel; + struct ibv_pd * pd; + struct ibv_cq * cq; + struct ibv_qp * qp; + struct ibv_flow * flow; + struct ibv_mr * mr; + u_char * oneshot_buffer; + unsigned long port_num; + int cq_event; + u_int packets_recv; +}; + +static int +rdmasniff_stats(pcap_t *handle, struct pcap_stat *stat) +{ + struct pcap_rdmasniff *priv = handle->priv; + + stat->ps_recv = priv->packets_recv; + stat->ps_drop = 0; + stat->ps_ifdrop = 0; + + return 0; +} + +static void +rdmasniff_cleanup(pcap_t *handle) +{ + struct pcap_rdmasniff *priv = handle->priv; + + ibv_dereg_mr(priv->mr); + ibv_destroy_flow(priv->flow); + ibv_destroy_qp(priv->qp); + ibv_destroy_cq(priv->cq); + ibv_dealloc_pd(priv->pd); + ibv_destroy_comp_channel(priv->channel); + ibv_close_device(priv->context); + free(priv->oneshot_buffer); + + pcapint_cleanup_live_common(handle); +} + +static void +rdmasniff_post_recv(pcap_t *handle, uint64_t wr_id) +{ + struct pcap_rdmasniff *priv = handle->priv; + struct ibv_sge sg_entry; + struct ibv_recv_wr wr, *bad_wr; + + sg_entry.length = RDMASNIFF_RECEIVE_SIZE; + sg_entry.addr = (uintptr_t) handle->buffer + RDMASNIFF_RECEIVE_SIZE * wr_id; + sg_entry.lkey = priv->mr->lkey; + + wr.wr_id = wr_id; + wr.num_sge = 1; + wr.sg_list = &sg_entry; + wr.next = NULL; + + ibv_post_recv(priv->qp, &wr, &bad_wr); +} + +static int +rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_rdmasniff *priv = handle->priv; + struct ibv_cq *ev_cq; + void *ev_ctx; + struct ibv_wc wc; + struct pcap_pkthdr pkth; + u_char *pktd; + int count = 0; + + if (!priv->cq_event) { + while (ibv_get_cq_event(priv->channel, &ev_cq, &ev_ctx) < 0) { + if (errno != EINTR) { + return PCAP_ERROR; + } + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + ibv_ack_cq_events(priv->cq, 1); + ibv_req_notify_cq(priv->cq, 0); + priv->cq_event = 1; + } + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(max_packets)) + max_packets = INT_MAX; + + while (count < max_packets) { + if (ibv_poll_cq(priv->cq, 1, &wc) != 1) { + priv->cq_event = 0; + break; + } + + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "failed WC wr_id %" PRIu64 " status %d/%s\n", + wc.wr_id, + wc.status, ibv_wc_status_str(wc.status)); + continue; + } + + pkth.len = wc.byte_len; + pkth.caplen = min(pkth.len, (u_int)handle->snapshot); + gettimeofday(&pkth.ts, NULL); + + pktd = (u_char *) handle->buffer + wc.wr_id * RDMASNIFF_RECEIVE_SIZE; + + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) { + callback(user, &pkth, pktd); + ++priv->packets_recv; + ++count; + } + + rdmasniff_post_recv(handle, wc.wr_id); + + if (handle->break_loop) { + handle->break_loop = 0; + return PCAP_ERROR_BREAK; + } + } + + return count; +} + +static void +rdmasniff_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *) user; + pcap_t *handle = sp->pd; + struct pcap_rdmasniff *priv = handle->priv; + + *sp->hdr = *h; + memcpy(priv->oneshot_buffer, bytes, h->caplen); + *sp->pkt = priv->oneshot_buffer; +} + +static int +rdmasniff_activate(pcap_t *handle) +{ + struct pcap_rdmasniff *priv = handle->priv; + struct ibv_qp_init_attr qp_init_attr; + struct ibv_qp_attr qp_attr; + struct ibv_flow_attr flow_attr; + struct ibv_port_attr port_attr; + int i; + + priv->context = ibv_open_device(priv->rdma_device); + if (!priv->context) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to open device %s", handle->opt.device); + goto error; + } + + priv->pd = ibv_alloc_pd(priv->context); + if (!priv->pd) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to alloc PD for device %s", handle->opt.device); + goto error; + } + + priv->channel = ibv_create_comp_channel(priv->context); + if (!priv->channel) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to create comp channel for device %s", handle->opt.device); + goto error; + } + + priv->cq = ibv_create_cq(priv->context, RDMASNIFF_NUM_RECEIVES, + NULL, priv->channel, 0); + if (!priv->cq) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to create CQ for device %s", handle->opt.device); + goto error; + } + + ibv_req_notify_cq(priv->cq, 0); + + memset(&qp_init_attr, 0, sizeof qp_init_attr); + qp_init_attr.send_cq = qp_init_attr.recv_cq = priv->cq; + qp_init_attr.cap.max_recv_wr = RDMASNIFF_NUM_RECEIVES; + qp_init_attr.cap.max_recv_sge = 1; + qp_init_attr.qp_type = IBV_QPT_RAW_PACKET; + priv->qp = ibv_create_qp(priv->pd, &qp_init_attr); + if (!priv->qp) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to create QP for device %s", handle->opt.device); + goto error; + } + + memset(&qp_attr, 0, sizeof qp_attr); + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.port_num = priv->port_num; + if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE | IBV_QP_PORT)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to modify QP to INIT for device %s", handle->opt.device); + goto error; + } + + memset(&qp_attr, 0, sizeof qp_attr); + qp_attr.qp_state = IBV_QPS_RTR; + if (ibv_modify_qp(priv->qp, &qp_attr, IBV_QP_STATE)) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to modify QP to RTR for device %s", handle->opt.device); + goto error; + } + + memset(&flow_attr, 0, sizeof flow_attr); + flow_attr.type = IBV_FLOW_ATTR_SNIFFER; + flow_attr.size = sizeof flow_attr; + flow_attr.port = priv->port_num; + priv->flow = ibv_create_flow(priv->qp, &flow_attr); + if (!priv->flow) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to create flow for device %s", handle->opt.device); + goto error; + } + + handle->bufsize = RDMASNIFF_NUM_RECEIVES * RDMASNIFF_RECEIVE_SIZE; + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to allocate receive buffer for device %s", handle->opt.device); + goto error; + } + + priv->oneshot_buffer = malloc(RDMASNIFF_RECEIVE_SIZE); + if (!priv->oneshot_buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to allocate oneshot buffer for device %s", handle->opt.device); + goto error; + } + + priv->mr = ibv_reg_mr(priv->pd, handle->buffer, handle->bufsize, IBV_ACCESS_LOCAL_WRITE); + if (!priv->mr) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Failed to register MR for device %s", handle->opt.device); + goto error; + } + + + for (i = 0; i < RDMASNIFF_NUM_RECEIVES; ++i) { + rdmasniff_post_recv(handle, i); + } + + if (!ibv_query_port(priv->context, priv->port_num, &port_attr) && + port_attr.link_layer == IBV_LINK_LAYER_INFINIBAND) { + handle->linktype = DLT_INFINIBAND; + } else { + handle->linktype = DLT_EN10MB; + } + + if (handle->snapshot <= 0 || handle->snapshot > RDMASNIFF_RECEIVE_SIZE) + handle->snapshot = RDMASNIFF_RECEIVE_SIZE; + + handle->offset = 0; + handle->read_op = rdmasniff_read; + handle->stats_op = rdmasniff_stats; + handle->cleanup_op = rdmasniff_cleanup; + handle->setfilter_op = pcapint_install_bpf_program; + handle->setdirection_op = NULL; + handle->set_datalink_op = NULL; + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + handle->oneshot_callback = rdmasniff_oneshot; + handle->selectable_fd = priv->channel->fd; + + return 0; + +error: + if (priv->mr) { + ibv_dereg_mr(priv->mr); + } + + if (priv->flow) { + ibv_destroy_flow(priv->flow); + } + + if (priv->qp) { + ibv_destroy_qp(priv->qp); + } + + if (priv->cq) { + ibv_destroy_cq(priv->cq); + } + + if (priv->channel) { + ibv_destroy_comp_channel(priv->channel); + } + + if (priv->pd) { + ibv_dealloc_pd(priv->pd); + } + + if (priv->context) { + ibv_close_device(priv->context); + } + + if (priv->oneshot_buffer) { + free(priv->oneshot_buffer); + } + + return PCAP_ERROR; +} + +pcap_t * +rdmasniff_create(const char *device, char *ebuf, int *is_ours) +{ + struct pcap_rdmasniff *priv; + struct ibv_device **dev_list; + int numdev; + size_t namelen; + const char *port; + unsigned long port_num; + int i; + pcap_t *p = NULL; + + *is_ours = 0; + + dev_list = ibv_get_device_list(&numdev); + if (!dev_list) { + return NULL; + } + if (!numdev) { + ibv_free_device_list(dev_list); + return NULL; + } + + namelen = strlen(device); + + port = strchr(device, ':'); + if (port) { + port_num = strtoul(port + 1, NULL, 10); + if (port_num > 0) { + namelen = port - device; + } else { + port_num = 1; + } + } else { + port_num = 1; + } + + for (i = 0; i < numdev; ++i) { + if (strlen(dev_list[i]->name) == namelen && + !strncmp(device, dev_list[i]->name, namelen)) { + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_rdmasniff); + if (p) { + p->activate_op = rdmasniff_activate; + priv = p->priv; + priv->rdma_device = dev_list[i]; + priv->port_num = port_num; + } + break; + } + } + + ibv_free_device_list(dev_list); + return p; +} + +int +rdmasniff_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + struct ibv_device **dev_list; + int numdev; + int i; + int ret = 0; + + dev_list = ibv_get_device_list(&numdev); + if (!dev_list) { + return 0; + } + + for (i = 0; i < numdev; ++i) { + /* + * XXX - do the notions of "up", "running", or + * "connected" apply here? + */ + if (!pcapint_add_dev(devlistp, dev_list[i]->name, 0, "RDMA sniffer", err_str)) { + ret = -1; + break; + } + } + + ibv_free_device_list(dev_list); + return ret; +} diff --git a/src/libpcap-1.10.5/pcap-rdmasniff.h b/src/libpcap-1.10.5/pcap-rdmasniff.h new file mode 100644 index 0000000000..ff1f3c20d7 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-rdmasniff.h @@ -0,0 +1,2 @@ +pcap_t *rdmasniff_create(const char *device, char *ebuf, int *is_ours); +int rdmasniff_findalldevs(pcap_if_list_t *devlistp, char *err_str); diff --git a/src/libpcap-1.10.5/pcap-rpcap.c b/src/libpcap-1.10.5/pcap-rpcap.c new file mode 100644 index 0000000000..408d453f70 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-rpcap.c @@ -0,0 +1,3631 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "ftmacros.h" +#include "diag-control.h" + +#include /* for strlen(), ... */ +#include /* for malloc(), free(), ... */ +#include /* for functions with variable number of arguments */ +#include /* for the errno variable */ +#include /* for INT_MAX */ +#include "sockutils.h" +#include "pcap-int.h" +#include "pcap-util.h" +#include "rpcap-protocol.h" +#include "pcap-rpcap.h" + +#ifdef _WIN32 +#include "charconv.h" /* for utf_8_to_acp_truncated() */ +#endif + +#ifdef HAVE_OPENSSL +#include "sslutils.h" +#endif + +/* + * This file contains the pcap module for capturing from a remote machine's + * interfaces using the RPCAP protocol. + * + * WARNING: All the RPCAP functions that are allowed to return a buffer + * containing the error description can return max PCAP_ERRBUF_SIZE characters. + * However there is no guarantees that the string will be zero-terminated. + * Best practice is to define the errbuf variable as a char of size + * 'PCAP_ERRBUF_SIZE+1' and to insert manually a NULL character at the end + * of the buffer. This will guarantee that no buffer overflows occur even + * if we use the printf() to show the error on the screen. + * + * XXX - actually, null-terminating the error string is part of the + * contract for the pcap API; if there's any place in the pcap code + * that doesn't guarantee null-termination, even at the expense of + * cutting the message short, that's a bug and needs to be fixed. + */ + +#define PCAP_STATS_STANDARD 0 /* Used by pcap_stats_rpcap to see if we want standard or extended statistics */ +#ifdef _WIN32 +#define PCAP_STATS_EX 1 /* Used by pcap_stats_rpcap to see if we want standard or extended statistics */ +#endif + +/* + * \brief Keeps a list of all the opened connections in the active mode. + * + * This structure defines a linked list of items that are needed to keep the info required to + * manage the active mode. + * In other words, when a new connection in active mode starts, this structure is updated so that + * it reflects the list of active mode connections currently opened. + * This structure is required by findalldevs() and open_remote() to see if they have to open a new + * control connection toward the host, or they already have a control connection in place. + */ +struct activehosts +{ + struct sockaddr_storage host; + PCAP_SOCKET sockctrl; + SSL *ssl; + uint8 protocol_version; + int byte_swapped; + struct activehosts *next; +}; + +/* Keeps a list of all the opened connections in the active mode. */ +static struct activehosts *activeHosts; + +/* + * Keeps the main socket identifier when we want to accept a new remote + * connection (active mode only). + * See the documentation of pcap_remoteact_accept() and + * pcap_remoteact_cleanup() for more details. + */ +static PCAP_SOCKET sockmain; +static SSL *ssl_main; + +/* + * Private data for capturing remotely using the rpcap protocol. + */ +struct pcap_rpcap { + /* + * This is '1' if we're the network client; it is needed by several + * functions (such as pcap_setfilter()) to know whether they have + * to use the socket or have to open the local adapter. + */ + int rmt_clientside; + + PCAP_SOCKET rmt_sockctrl; /* socket ID of the socket used for the control connection */ + PCAP_SOCKET rmt_sockdata; /* socket ID of the socket used for the data connection */ + SSL *ctrl_ssl, *data_ssl; /* optional transport of rmt_sockctrl and rmt_sockdata via TLS */ + int rmt_flags; /* we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture() */ + int rmt_capstarted; /* 'true' if the capture is already started (needed to know if we have to call the pcap_startcapture() */ + char *currentfilter; /* Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on. */ + + uint8 protocol_version; /* negotiated protocol version */ + uint8 uses_ssl; /* User asked for rpcaps scheme */ + int byte_swapped; /* Server byte order is swapped from ours */ + + unsigned int TotNetDrops; /* keeps the number of packets that have been dropped by the network */ + + /* + * This keeps the number of packets that have been received by the + * application. + * + * Packets dropped by the kernel buffer are not counted in this + * variable. It is always equal to (TotAccepted - TotDrops), + * except for the case of remote capture, in which we have also + * packets in flight, i.e. that have been transmitted by the remote + * host, but that have not been received (yet) from the client. + * In this case, (TotAccepted - TotDrops - TotNetDrops) gives a + * wrong result, since this number does not corresponds always to + * the number of packet received by the application. For this reason, + * in the remote capture we need another variable that takes into + * account of the number of packets actually received by the + * application. + */ + unsigned int TotCapt; + + struct pcap_stat stat; + /* XXX */ + struct pcap *next; /* list of open pcaps that need stuff cleared on close */ +}; + +/**************************************************** + * * + * Locally defined functions * + * * + ****************************************************/ +static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int mode); +static int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog); +static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog); +static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog); +static void pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter); +static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog); +static int pcap_setsampling_remote(pcap_t *fp); +static int pcap_startcapture_remote(pcap_t *fp); +static int rpcap_recv_msg_header(PCAP_SOCKET sock, SSL *, struct rpcap_header *header, char *errbuf); +static int rpcap_check_msg_ver(PCAP_SOCKET sock, SSL *, uint8 expected_ver, struct rpcap_header *header, char *errbuf); +static int rpcap_check_msg_type(PCAP_SOCKET sock, SSL *, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf); +static int rpcap_process_msg_header(PCAP_SOCKET sock, SSL *, uint8 ver, uint8 request_type, struct rpcap_header *header, char *errbuf); +static int rpcap_recv(PCAP_SOCKET sock, SSL *, void *buffer, size_t toread, uint32 *plen, char *errbuf); +static void rpcap_msg_err(PCAP_SOCKET sockctrl, SSL *, uint32 plen, char *remote_errbuf); +static int rpcap_discard(PCAP_SOCKET sock, SSL *, uint32 len, char *errbuf); +static int rpcap_read_packet_msg(struct pcap_rpcap const *, pcap_t *p, size_t size); + +/**************************************************** + * * + * Function bodies * + * * + ****************************************************/ + +/* + * This function translates (i.e. de-serializes) a 'rpcap_sockaddr' + * structure from the network byte order to a 'sockaddr_in" or + * 'sockaddr_in6' structure in the host byte order. + * + * It accepts an 'rpcap_sockaddr' structure as it is received from the + * network, and checks the address family field against various values + * to see whether it looks like an IPv4 address, an IPv6 address, or + * neither of those. It checks for multiple values in order to try + * to handle older rpcap daemons that sent the native OS's 'sockaddr_in' + * or 'sockaddr_in6' structures over the wire with some members + * byte-swapped, and to handle the fact that AF_INET6 has different + * values on different OSes. + * + * For IPv4 addresses, it converts the address family to host byte + * order from network byte order and puts it into the structure, + * sets the length if a sockaddr structure has a length, converts the + * port number to host byte order from network byte order and puts + * it into the structure, copies over the IPv4 address, and zeroes + * out the zero padding. + * + * For IPv6 addresses, it converts the address family to host byte + * order from network byte order and puts it into the structure, + * sets the length if a sockaddr structure has a length, converts the + * port number and flow information to host byte order from network + * byte order and puts them into the structure, copies over the IPv6 + * address, and converts the scope ID to host byte order from network + * byte order and puts it into the structure. + * + * The function will allocate the 'sockaddrout' variable according to the + * address family in use. In case the address does not belong to the + * AF_INET nor AF_INET6 families, 'sockaddrout' is not allocated and a + * NULL pointer is returned. This usually happens because that address + * does not exist on the other host, or is of an address family other + * than AF_INET or AF_INET6, so the RPCAP daemon sent a 'sockaddr_storage' + * structure containing all 'zero' values. + * + * Older RPCAPDs sent the addresses over the wire in the OS's native + * structure format. For most OSes, this looks like the over-the-wire + * format, but might have a different value for AF_INET6 than the value + * on the machine receiving the reply. For OSes with the newer BSD-style + * sockaddr structures, this has, instead of a 2-byte address family, + * a 1-byte structure length followed by a 1-byte address family. The + * RPCAPD code would put the address family in network byte order before + * sending it; that would set it to 0 on a little-endian machine, as + * htons() of any value between 1 and 255 would result in a value > 255, + * with its lower 8 bits zero, so putting that back into a 1-byte field + * would set it to 0. + * + * Therefore, for older RPCAPDs running on an OS with newer BSD-style + * sockaddr structures, the family field, if treated as a big-endian + * (network byte order) 16-bit field, would be: + * + * (length << 8) | family if sent by a big-endian machine + * (length << 8) if sent by a little-endian machine + * + * For current RPCAPDs, and for older RPCAPDs running on an OS with + * older BSD-style sockaddr structures, the family field, if treated + * as a big-endian 16-bit field, would just contain the family. + * + * \param sockaddrin: a 'rpcap_sockaddr' pointer to the variable that has + * to be de-serialized. + * + * \param sockaddrout: a 'sockaddr_storage' pointer to the variable that will contain + * the de-serialized data. The structure returned can be either a 'sockaddr_in' or 'sockaddr_in6'. + * This variable will be allocated automatically inside this function. + * + * \param errbuf: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) + * that will contain the error message (in case there is one). + * + * \return '0' if everything is fine, '-1' if some errors occurred. Basically, the error + * can be only the fact that the malloc() failed to allocate memory. + * The error message is returned in the 'errbuf' variable, while the deserialized address + * is returned into the 'sockaddrout' variable. + * + * \warning This function supports only AF_INET and AF_INET6 address families. + * + * \warning The sockaddrout (if not NULL) must be deallocated by the user. + */ + +/* + * Possible IPv4 family values other than the designated over-the-wire value, + * which is 2 (because everybody, except for Haiku uses 2 for AF_INET, + * and Haiku has probably never run the old rpcapd code that put address + * structures directly on the wire, rather than the new rpcapd code + * that serializes addresses, using 2 for AF_INET). + */ +#define SOCKADDR_IN_LEN 16 /* length of struct sockaddr_in */ +#define SOCKADDR_IN6_LEN 28 /* length of struct sockaddr_in6 */ +#define NEW_BSD_AF_INET_BE ((SOCKADDR_IN_LEN << 8) | 2) +#define NEW_BSD_AF_INET_LE (SOCKADDR_IN_LEN << 8) + +/* + * Possible IPv6 family values other than the designated over-the-wire value, + * which is 23 (because that's what Windows uses, and most RPCAP servers + * out there are probably running Windows, as WinPcap includes the server + * but few if any UN*Xes build and ship it). + * + * The new BSD sockaddr structure format was in place before 4.4-Lite, so + * all the free-software BSDs use it. + */ +#define NEW_BSD_AF_INET6_BSD_BE ((SOCKADDR_IN6_LEN << 8) | 24) /* NetBSD, OpenBSD, BSD/OS */ +#define NEW_BSD_AF_INET6_FREEBSD_BE ((SOCKADDR_IN6_LEN << 8) | 28) /* FreeBSD, DragonFly BSD */ +#define NEW_BSD_AF_INET6_DARWIN_BE ((SOCKADDR_IN6_LEN << 8) | 30) /* macOS, iOS, anything else Darwin-based */ +#define NEW_BSD_AF_INET6_LE (SOCKADDR_IN6_LEN << 8) +#define LINUX_AF_INET6 10 +#define HPUX_AF_INET6 22 +#define AIX_AF_INET6 24 +#define SOLARIS_AF_INET6 26 + +static int +rpcap_deseraddr(struct rpcap_sockaddr *sockaddrin, struct sockaddr **sockaddrout, char *errbuf) +{ + /* Warning: we support only AF_INET and AF_INET6 */ + switch (ntohs(sockaddrin->family)) + { + case RPCAP_AF_INET: + case NEW_BSD_AF_INET_BE: + case NEW_BSD_AF_INET_LE: + { + struct rpcap_sockaddr_in *sockaddrin_ipv4; + struct sockaddr_in *sockaddrout_ipv4; + + (*sockaddrout) = (struct sockaddr *) malloc(sizeof(struct sockaddr_in)); + if ((*sockaddrout) == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + return -1; + } + sockaddrin_ipv4 = (struct rpcap_sockaddr_in *) sockaddrin; + sockaddrout_ipv4 = (struct sockaddr_in *) (*sockaddrout); + sockaddrout_ipv4->sin_family = AF_INET; + sockaddrout_ipv4->sin_port = ntohs(sockaddrin_ipv4->port); + memcpy(&sockaddrout_ipv4->sin_addr, &sockaddrin_ipv4->addr, sizeof(sockaddrout_ipv4->sin_addr)); + memset(sockaddrout_ipv4->sin_zero, 0, sizeof(sockaddrout_ipv4->sin_zero)); + break; + } + +#ifdef AF_INET6 + case RPCAP_AF_INET6: + case NEW_BSD_AF_INET6_BSD_BE: + case NEW_BSD_AF_INET6_FREEBSD_BE: + case NEW_BSD_AF_INET6_DARWIN_BE: + case NEW_BSD_AF_INET6_LE: + case LINUX_AF_INET6: + case HPUX_AF_INET6: + case AIX_AF_INET6: + case SOLARIS_AF_INET6: + { + struct rpcap_sockaddr_in6 *sockaddrin_ipv6; + struct sockaddr_in6 *sockaddrout_ipv6; + + (*sockaddrout) = (struct sockaddr *) malloc(sizeof(struct sockaddr_in6)); + if ((*sockaddrout) == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + return -1; + } + sockaddrin_ipv6 = (struct rpcap_sockaddr_in6 *) sockaddrin; + sockaddrout_ipv6 = (struct sockaddr_in6 *) (*sockaddrout); + sockaddrout_ipv6->sin6_family = AF_INET6; + sockaddrout_ipv6->sin6_port = ntohs(sockaddrin_ipv6->port); + sockaddrout_ipv6->sin6_flowinfo = ntohl(sockaddrin_ipv6->flowinfo); + memcpy(&sockaddrout_ipv6->sin6_addr, &sockaddrin_ipv6->addr, sizeof(sockaddrout_ipv6->sin6_addr)); + sockaddrout_ipv6->sin6_scope_id = ntohl(sockaddrin_ipv6->scope_id); + break; + } +#endif + + default: + /* + * It is neither AF_INET nor AF_INET6 (or, if the OS doesn't + * support AF_INET6, it's not AF_INET). + */ + *sockaddrout = NULL; + break; + } + return 0; +} + +/* + * This function reads a packet from the network socket. It does not + * deliver the packet to a pcap_dispatch()/pcap_loop() callback (hence + * the "nocb" string into its name). + * + * This function is called by pcap_read_rpcap(). + * + * WARNING: By choice, this function does not make use of semaphores. A smarter + * implementation should put a semaphore into the data thread, and a signal will + * be raised as soon as there is data into the socket buffer. + * However this is complicated and it does not bring any advantages when reading + * from the network, in which network delays can be much more important than + * these optimizations. Therefore, we chose the following approach: + * - the 'timeout' chosen by the user is split in two (half on the server side, + * with the usual meaning, and half on the client side) + * - this function checks for packets; if there are no packets, it waits for + * timeout/2 and then it checks again. If packets are still missing, it returns, + * otherwise it reads packets. + */ +static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_char **pkt_data) +{ + struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */ + struct rpcap_header *header; /* general header according to the RPCAP format */ + struct rpcap_pkthdr *net_pkt_header; /* header of the packet, from the message */ + u_char *net_pkt_data; /* packet data from the message */ + uint32 plen; + int retval = 0; /* generic return value */ + int msglen; + + /* Structures needed for the select() call */ + struct timeval tv; /* maximum time the select() can block waiting for data */ + fd_set rfds; /* set of socket descriptors we have to check */ + + /* + * Define the packet buffer timeout, to be used in the select() + * 'timeout', in pcap_t, is in milliseconds; we have to convert it into sec and microsec + */ + tv.tv_sec = p->opt.timeout / 1000; + tv.tv_usec = (suseconds_t)((p->opt.timeout - tv.tv_sec * 1000) * 1000); + +#ifdef HAVE_OPENSSL + /* Check if we still have bytes available in the last decoded TLS record. + * If that's the case, we know SSL_read will not block. */ + retval = pr->data_ssl && SSL_pending(pr->data_ssl) > 0; +#endif + if (! retval) + { + /* Watch out sockdata to see if it has input */ + FD_ZERO(&rfds); + + /* + * 'fp->rmt_sockdata' has always to be set before calling the select(), + * since it is cleared by the select() + */ + FD_SET(pr->rmt_sockdata, &rfds); + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + retval = 1; +#else + retval = select((int) pr->rmt_sockdata + 1, &rfds, NULL, NULL, &tv); +#endif + + if (retval == -1) + { +#ifndef _WIN32 + if (errno == EINTR) + { + /* Interrupted. */ + return 0; + } +#endif + sock_geterrmsg(p->errbuf, PCAP_ERRBUF_SIZE, + "select() failed"); + return -1; + } + } + + /* There is no data waiting, so return '0' */ + if (retval == 0) + return 0; + + /* + * We have to define 'header' as a pointer to a larger buffer, + * because in case of UDP we have to read all the message within a single call + */ + header = (struct rpcap_header *) p->buffer; + net_pkt_header = (struct rpcap_pkthdr *) ((char *)p->buffer + sizeof(struct rpcap_header)); + net_pkt_data = (u_char *)p->buffer + sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr); + + if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) + { + /* Read the entire message from the network */ + msglen = sock_recv_dgram(pr->rmt_sockdata, pr->data_ssl, p->buffer, + p->bufsize, p->errbuf, PCAP_ERRBUF_SIZE); + if (msglen == -1) + { + /* Network error. */ + return -1; + } + if (msglen == -3) + { + /* Interrupted receive. */ + return 0; + } + if ((size_t)msglen < sizeof(struct rpcap_header)) + { + /* + * Message is shorter than an rpcap header. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "UDP packet message is shorter than an rpcap header"); + return -1; + } + plen = ntohl(header->plen); + if ((size_t)msglen < sizeof(struct rpcap_header) + plen) + { + /* + * Message is shorter than the header claims it + * is. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "UDP packet message is shorter than its rpcap header claims"); + return -1; + } + } + else + { + int status; + + if ((size_t)p->cc < sizeof(struct rpcap_header)) + { + /* + * We haven't read any of the packet header yet. + * The size we should get is the size of the + * packet header. + */ + status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header)); + if (status == -1) + { + /* Network error. */ + return -1; + } + if (status == -3) + { + /* Interrupted receive. */ + return 0; + } + } + + /* + * We have the header, so we know how long the + * message payload is. The size we should get + * is the size of the packet header plus the + * size of the payload. + */ + plen = ntohl(header->plen); + if (plen > p->bufsize - sizeof(struct rpcap_header)) + { + /* + * This is bigger than the largest + * record we'd expect. (We do it by + * subtracting in order to avoid an + * overflow.) + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Server sent us a message larger than the largest expected packet message"); + return -1; + } + status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen); + if (status == -1) + { + /* Network error. */ + return -1; + } + if (status == -3) + { + /* Interrupted receive. */ + return 0; + } + + /* + * We have the entire message; reset the buffer pointer + * and count, as the next read should start a new + * message. + */ + p->bp = p->buffer; + p->cc = 0; + } + + /* + * We have the entire message. + */ + header->plen = plen; + + /* + * Did the server specify the version we negotiated? + */ + if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->data_ssl, pr->protocol_version, + header, p->errbuf) == -1) + { + return 0; /* Return 'no packets received' */ + } + + /* + * Is this a RPCAP_MSG_PACKET message? + */ + if (header->type != RPCAP_MSG_PACKET) + { + return 0; /* Return 'no packets received' */ + } + + if (ntohl(net_pkt_header->caplen) > plen) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packet's captured data goes past the end of the received packet message."); + return -1; + } + + /* Fill in packet header */ + pkt_header->caplen = ntohl(net_pkt_header->caplen); + pkt_header->len = ntohl(net_pkt_header->len); + pkt_header->ts.tv_sec = ntohl(net_pkt_header->timestamp_sec); + pkt_header->ts.tv_usec = ntohl(net_pkt_header->timestamp_usec); + + /* Supply a pointer to the beginning of the packet data */ + *pkt_data = net_pkt_data; + + /* + * I don't update the counter of the packets dropped by the network since we're using TCP, + * therefore no packets are dropped. Just update the number of packets received correctly + */ + pr->TotCapt++; + + if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) + { + unsigned int npkt; + + /* We're using UDP, so we need to update the counter of the packets dropped by the network */ + npkt = ntohl(net_pkt_header->npkt); + + if (pr->TotCapt != npkt) + { + pr->TotNetDrops += (npkt - pr->TotCapt); + pr->TotCapt = npkt; + } + } + + /* Packet read successfully */ + return 1; +} + +/* + * This function reads a packet from the network socket. + * + * This function relies on the pcap_read_nocb_remote to deliver packets. The + * difference, here, is that as soon as a packet is read, it is delivered + * to the application by means of a callback function. + */ +static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */ + struct pcap_pkthdr pkt_header; + u_char *pkt_data; + int n = 0; + int ret; + + /* + * If this is client-side, and we haven't already started + * the capture, start it now. + */ + if (pr->rmt_clientside) + { + /* We are on an remote capture */ + if (!pr->rmt_capstarted) + { + /* + * The capture isn't started yet, so try to + * start it. + */ + if (pcap_startcapture_remote(p)) + return -1; + } + } + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(cnt)) + cnt = INT_MAX; + + while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) + { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return PCAP_ERROR_BREAK to indicate + * that we were told to break out of the loop. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + + /* + * Read some packets. + */ + ret = pcap_read_nocb_remote(p, &pkt_header, &pkt_data); + if (ret == 1) + { + /* + * We got a packet. + * + * Do whatever post-processing is necessary, hand + * it to the callback, and count it so we can + * return the count. + */ + pcapint_post_process(p->linktype, pr->byte_swapped, + &pkt_header, pkt_data); + (*callback)(user, &pkt_header, pkt_data); + n++; + } + else if (ret == -1) + { + /* Error. */ + return ret; + } + else + { + /* + * No packet; this could mean that we timed + * out, or that we got interrupted, or that + * we got a bad packet. + * + * Were we told to break out of the loop? + */ + if (p->break_loop) { + /* + * Yes. + */ + p->break_loop = 0; + return (PCAP_ERROR_BREAK); + } + /* No - return the number of packets we've processed. */ + return n; + } + } + return n; +} + +/* + * This function sends a CLOSE command to the capture server if we're in + * passive mode and an ENDCAP command to the capture server if we're in + * active mode. + * + * It is called when the user calls pcap_close(). It sends a command + * to our peer that says 'ok, let's stop capturing'. + * + * WARNING: Since we're closing the connection, we do not check for errors. + */ +static void pcap_cleanup_rpcap(pcap_t *fp) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + struct rpcap_header header; /* header of the RPCAP packet */ + struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */ + int active = 0; /* active mode or not? */ + + /* detect if we're in active mode */ + temp = activeHosts; + while (temp) + { + if (temp->sockctrl == pr->rmt_sockctrl) + { + active = 1; + break; + } + temp = temp->next; + } + + if (!active) + { + rpcap_createhdr(&header, pr->protocol_version, + RPCAP_MSG_CLOSE, 0, 0); + + /* + * Send the close request; don't report any errors, as + * we're closing this pcap_t, and have no place to report + * the error. No reply is sent to this message. + */ + (void)sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header, + sizeof(struct rpcap_header), NULL, 0); + } + else + { + rpcap_createhdr(&header, pr->protocol_version, + RPCAP_MSG_ENDCAP_REQ, 0, 0); + + /* + * Send the end capture request; don't report any errors, + * as we're closing this pcap_t, and have no place to + * report the error. + */ + if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header, + sizeof(struct rpcap_header), NULL, 0) == 0) + { + /* + * Wait for the answer; don't report any errors, + * as we're closing this pcap_t, and have no + * place to report the error. + */ + if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, + pr->protocol_version, RPCAP_MSG_ENDCAP_REQ, + &header, NULL) == 0) + { + (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, + header.plen, NULL); + } + } + } + + if (pr->rmt_sockdata) + { +#ifdef HAVE_OPENSSL + if (pr->data_ssl) + { + // Finish using the SSL handle for the data socket. + // This must be done *before* the socket is closed. + ssl_finish(pr->data_ssl); + pr->data_ssl = NULL; + } +#endif + sock_close(pr->rmt_sockdata, NULL, 0); + pr->rmt_sockdata = 0; + } + + if ((!active) && (pr->rmt_sockctrl)) + { +#ifdef HAVE_OPENSSL + if (pr->ctrl_ssl) + { + // Finish using the SSL handle for the control socket. + // This must be done *before* the socket is closed. + ssl_finish(pr->ctrl_ssl); + pr->ctrl_ssl = NULL; + } +#endif + sock_close(pr->rmt_sockctrl, NULL, 0); + } + + pr->rmt_sockctrl = 0; + pr->ctrl_ssl = NULL; + + if (pr->currentfilter) + { + free(pr->currentfilter); + pr->currentfilter = NULL; + } + + pcapint_cleanup_live_common(fp); + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); +} + +/* + * This function retrieves network statistics from our peer; + * it provides only the standard statistics. + */ +static int pcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_stat *retval; + + retval = rpcap_stats_rpcap(p, ps, PCAP_STATS_STANDARD); + + if (retval) + return 0; + else + return -1; +} + +#ifdef _WIN32 +/* + * This function retrieves network statistics from our peer; + * it provides the additional statistics supported by pcap_stats_ex(). + */ +static struct pcap_stat *pcap_stats_ex_rpcap(pcap_t *p, int *pcap_stat_size) +{ + *pcap_stat_size = sizeof (p->stat); + + /* PCAP_STATS_EX (third param) means 'extended pcap_stats()' */ + return (rpcap_stats_rpcap(p, &(p->stat), PCAP_STATS_EX)); +} +#endif + +/* + * This function retrieves network statistics from our peer. It + * is used by the two previous functions. + * + * It can be called in two modes: + * - PCAP_STATS_STANDARD: if we want just standard statistics (i.e., + * for pcap_stats()) + * - PCAP_STATS_EX: if we want extended statistics (i.e., for + * pcap_stats_ex()) + * + * This 'mode' parameter is needed because in pcap_stats() the variable that + * keeps the statistics is allocated by the user. On Windows, this structure + * has been extended in order to keep new stats. However, if the user has a + * smaller structure and it passes it to pcap_stats(), this function will + * try to fill in more data than the size of the structure, so that memory + * after the structure will be overwritten. + * + * So, we need to know it we have to copy just the standard fields, or the + * extended fields as well. + * + * In case we want to copy the extended fields as well, the problem of + * memory overflow no longer exists because the structure that's filled + * in is part of the pcap_t, so that it can be guaranteed to be large + * enough for the additional statistics. + * + * \param p: the pcap_t structure related to the current instance. + * + * \param ps: a pointer to a 'pcap_stat' structure, needed for compatibility + * with pcap_stat(), where the structure is allocated by the user. In case + * of pcap_stats_ex(), this structure and the function return value point + * to the same variable. + * + * \param mode: one of PCAP_STATS_STANDARD or PCAP_STATS_EX. + * + * \return The structure that keeps the statistics, or NULL in case of error. + * The error string is placed in the pcap_t structure. + */ +static struct pcap_stat *rpcap_stats_rpcap(pcap_t *p, struct pcap_stat *ps, int mode) +{ + struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */ + struct rpcap_header header; /* header of the RPCAP packet */ + struct rpcap_stats netstats; /* statistics sent on the network */ + uint32 plen; /* data remaining in the message */ + +#ifdef _WIN32 + if (mode != PCAP_STATS_STANDARD && mode != PCAP_STATS_EX) +#else + if (mode != PCAP_STATS_STANDARD) +#endif + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Invalid stats mode %d", mode); + return NULL; + } + + /* + * If the capture has not yet started, we cannot request statistics + * for the capture from our peer, so we return 0 for all statistics, + * as nothing's been seen yet. + */ + if (!pr->rmt_capstarted) + { + ps->ps_drop = 0; + ps->ps_ifdrop = 0; + ps->ps_recv = 0; +#ifdef _WIN32 + if (mode == PCAP_STATS_EX) + { + ps->ps_capt = 0; + ps->ps_sent = 0; + ps->ps_netdrop = 0; + } +#endif /* _WIN32 */ + + return ps; + } + + rpcap_createhdr(&header, pr->protocol_version, + RPCAP_MSG_STATS_REQ, 0, 0); + + /* Send the PCAP_STATS command */ + if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&header, + sizeof(struct rpcap_header), p->errbuf, PCAP_ERRBUF_SIZE) < 0) + return NULL; /* Unrecoverable network error */ + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version, + RPCAP_MSG_STATS_REQ, &header, p->errbuf) == -1) + return NULL; /* Error */ + + plen = header.plen; + + /* Read the reply body */ + if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&netstats, + sizeof(struct rpcap_stats), &plen, p->errbuf) == -1) + goto error; + + ps->ps_drop = ntohl(netstats.krnldrop); + ps->ps_ifdrop = ntohl(netstats.ifdrop); + ps->ps_recv = ntohl(netstats.ifrecv); +#ifdef _WIN32 + if (mode == PCAP_STATS_EX) + { + ps->ps_capt = pr->TotCapt; + ps->ps_netdrop = pr->TotNetDrops; + ps->ps_sent = ntohl(netstats.svrcapt); + } +#endif /* _WIN32 */ + + /* Discard the rest of the message. */ + if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, p->errbuf) == -1) + goto error_nodiscard; + + return ps; + +error: + /* + * Discard the rest of the message. + * We already reported an error; if this gets an error, just + * drive on. + */ + (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL); + +error_nodiscard: + return NULL; +} + +/* + * This function returns the entry in the list of active hosts for this + * active connection (active mode only), or NULL if there is no + * active connection or an error occurred. It is just for internal + * use. + * + * \param host: a string that keeps the host name of the host for which we + * want to get the socket ID for that active connection. + * + * \param error: a pointer to an int that is set to 1 if an error occurred + * and 0 otherwise. + * + * \param errbuf: a pointer to a user-allocated buffer (of size + * PCAP_ERRBUF_SIZE) that will contain the error message (in case + * there is one). + * + * \return the entry for this host in the list of active connections + * if found, NULL if it's not found or there's an error. + */ +static struct activehosts * +rpcap_remoteact_getsock(const char *host, int *error, char *errbuf) +{ + struct activehosts *temp; /* temp var needed to scan the host list chain */ + struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ + + /* retrieve the network address corresponding to 'host' */ + addrinfo = NULL; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + addrinfo = sock_initaddress(host, NULL, &hints, errbuf, + PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + { + *error = 1; + return NULL; + } + + temp = activeHosts; + + while (temp) + { + ai_next = addrinfo; + while (ai_next) + { + if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0) + { + *error = 0; + freeaddrinfo(addrinfo); + return temp; + } + + ai_next = ai_next->ai_next; + } + temp = temp->next; + } + + if (addrinfo) + freeaddrinfo(addrinfo); + + /* + * The host for which you want to get the socket ID does not have an + * active connection. + */ + *error = 0; + return NULL; +} + +/* + * This function starts a remote capture. + * + * This function is required since the RPCAP protocol decouples the 'open' + * from the 'start capture' functions. + * This function takes all the parameters needed (which have been stored + * into the pcap_t structure) and sends them to the server. + * + * \param fp: the pcap_t descriptor of the device currently open. + * + * \return '0' if everything is fine, '-1' otherwise. The error message + * (if one) is returned into the 'errbuf' field of the pcap_t structure. + */ +static int pcap_startcapture_remote(pcap_t *fp) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + uint16 portdata = 0; /* temp variable needed to keep the network port for the data connection */ + uint32 plen; + int active = 0; /* '1' if we're in active mode */ + struct activehosts *temp; /* temp var needed to scan the host list chain, to detect if we're in active mode */ + char host[INET6_ADDRSTRLEN + 1]; /* numeric name of the other host */ + + /* socket-related variables*/ + struct addrinfo hints; /* temp, needed to open a socket connection */ + struct addrinfo *addrinfo; /* temp, needed to open a socket connection */ + PCAP_SOCKET sockdata = 0; /* socket descriptor of the data connection */ + struct sockaddr_storage saddr; /* temp, needed to retrieve the network data port chosen on the local machine */ + socklen_t saddrlen; /* temp, needed to retrieve the network data port chosen on the local machine */ + int ai_family; /* temp, keeps the address family used by the control connection */ + struct sockaddr_in *sin4; + struct sockaddr_in6 *sin6; + + /* RPCAP-related variables*/ + struct rpcap_header header; /* header of the RPCAP packet */ + struct rpcap_startcapreq *startcapreq; /* start capture request message */ + struct rpcap_startcapreply startcapreply; /* start capture reply message */ + + /* Variables related to the buffer setting */ + int res; + socklen_t itemp; + int sockbufsize = 0; + uint32 server_sockbufsize; + + // Take the opportunity to clear pr->data_ssl before any goto error, + // as it seems p->priv is not zeroed after its malloced. + // XXX - it now should be, as it's allocated by pcap_alloc_pcap_t(), + // which does a calloc(). + pr->data_ssl = NULL; + + /* + * Let's check if sampling has been required. + * If so, let's set it first + */ + if (pcap_setsampling_remote(fp) != 0) + return -1; + + /* detect if we're in active mode */ + temp = activeHosts; + while (temp) + { + if (temp->sockctrl == pr->rmt_sockctrl) + { + active = 1; + break; + } + temp = temp->next; + } + + addrinfo = NULL; + + /* + * Gets the complete sockaddr structure used in the ctrl connection + * This is needed to get the address family of the control socket + * Tip: I cannot save the ai_family of the ctrl sock in the pcap_t struct, + * since the ctrl socket can already be open in case of active mode; + * so I would have to call getpeername() anyway + */ + saddrlen = sizeof(struct sockaddr_storage); + if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); + goto error_nodiscard; + } + ai_family = ((struct sockaddr_storage *) &saddr)->ss_family; + + /* Get the numeric address of the remote host we are connected to */ + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, host, + sizeof(host), NULL, 0, NI_NUMERICHOST)) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + goto error_nodiscard; + } + + /* + * Data connection is opened by the server toward the client if: + * - we're using TCP, and the user wants us to be in active mode + * - we're using UDP + */ + if ((active) || (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) + { + /* + * We have to create a new socket to receive packets + * We have to do that immediately, since we have to tell the other + * end which network port we picked up + */ + memset(&hints, 0, sizeof(struct addrinfo)); + /* TEMP addrinfo is NULL in case of active */ + hints.ai_family = ai_family; /* Use the same address family of the control socket */ + hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; /* Data connection is opened by the server toward the client */ + + /* Let's the server pick up a free network port for us */ + addrinfo = sock_initaddress(NULL, NULL, &hints, fp->errbuf, + PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + goto error_nodiscard; + + if ((sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, + 1 /* max 1 connection in queue */, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error_nodiscard; + + /* addrinfo is no longer used */ + freeaddrinfo(addrinfo); + addrinfo = NULL; + + /* get the complete sockaddr structure used in the data connection */ + saddrlen = sizeof(struct sockaddr_storage); + if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); + goto error_nodiscard; + } + + switch (saddr.ss_family) { + + case AF_INET: + sin4 = (struct sockaddr_in *)&saddr; + portdata = sin4->sin_port; + break; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&saddr; + portdata = sin6->sin6_port; + break; + + default: + snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Local address has unknown address family %u", + saddr.ss_family); + goto error_nodiscard; + } + } + + /* + * Now it's time to start playing with the RPCAP protocol + * RPCAP start capture command: create the request message + */ + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + goto error_nodiscard; + + rpcap_createhdr((struct rpcap_header *) sendbuf, + pr->protocol_version, RPCAP_MSG_STARTCAP_REQ, 0, + sizeof(struct rpcap_startcapreq) + sizeof(struct rpcap_filter) + fp->fcode.bf_len * sizeof(struct rpcap_filterbpf_insn)); + + /* Fill the structure needed to open an adapter remotely */ + startcapreq = (struct rpcap_startcapreq *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreq), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + goto error_nodiscard; + + memset(startcapreq, 0, sizeof(struct rpcap_startcapreq)); + + /* By default, apply half the timeout on one side, half of the other */ + fp->opt.timeout = fp->opt.timeout / 2; + startcapreq->read_timeout = htonl(fp->opt.timeout); + + /* portdata on the openreq is meaningful only if we're in active mode */ + if ((active) || (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) + { + startcapreq->portdata = portdata; + } + + startcapreq->snaplen = htonl(fp->snapshot); + startcapreq->flags = 0; + + if (pr->rmt_flags & PCAP_OPENFLAG_PROMISCUOUS) + startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_PROMISC; + if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) + startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_DGRAM; + if (active) + startcapreq->flags |= RPCAP_STARTCAPREQ_FLAG_SERVEROPEN; + + startcapreq->flags = htons(startcapreq->flags); + + /* Pack the capture filter */ + if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, &fp->fcode)) + goto error_nodiscard; + + if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf, + PCAP_ERRBUF_SIZE) < 0) + goto error_nodiscard; + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version, + RPCAP_MSG_STARTCAP_REQ, &header, fp->errbuf) == -1) + goto error_nodiscard; + + plen = header.plen; + + if (rpcap_recv(pr->rmt_sockctrl, pr->ctrl_ssl, (char *)&startcapreply, + sizeof(struct rpcap_startcapreply), &plen, fp->errbuf) == -1) + goto error; + + /* + * In case of UDP data stream, the connection is always opened by the daemon + * So, this case is already covered by the code above. + * Now, we have still to handle TCP connections, because: + * - if we're in active mode, we have to wait for a remote connection + * - if we're in passive more, we have to start a connection + * + * We have to do he job in two steps because in case we're opening a TCP connection, we have + * to tell the port we're using to the remote side; in case we're accepting a TCP + * connection, we have to wait this info from the remote side. + */ + if (!(pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) + { + if (!active) + { + char portstring[PCAP_BUF_SIZE]; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = ai_family; /* Use the same address family of the control socket */ + hints.ai_socktype = (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP) ? SOCK_DGRAM : SOCK_STREAM; + snprintf(portstring, PCAP_BUF_SIZE, "%d", ntohs(startcapreply.portdata)); + + /* Let's the server pick up a free network port for us */ + addrinfo = sock_initaddress(host, portstring, &hints, + fp->errbuf, PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + goto error; + + if ((sockdata = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, fp->errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error; + + /* addrinfo is no longer used */ + freeaddrinfo(addrinfo); + addrinfo = NULL; + } + else + { + PCAP_SOCKET socktemp; /* We need another socket, since we're going to accept() a connection */ + + /* Connection creation */ + saddrlen = sizeof(struct sockaddr_storage); + + socktemp = accept(sockdata, (struct sockaddr *) &saddr, &saddrlen); + + if (socktemp == INVALID_SOCKET) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "accept() failed"); + goto error; + } + + /* Now that I accepted the connection, the server socket is no longer needed */ + sock_close(sockdata, fp->errbuf, PCAP_ERRBUF_SIZE); + sockdata = socktemp; + } + } + + /* Let's save the socket of the data connection */ + pr->rmt_sockdata = sockdata; + +#ifdef HAVE_OPENSSL + if (pr->uses_ssl) + { + pr->data_ssl = ssl_promotion(0, sockdata, fp->errbuf, PCAP_ERRBUF_SIZE); + if (! pr->data_ssl) goto error; + } +#endif + + /* + * Set the size of the socket buffer for the data socket. + * It has the same size as the local capture buffer used + * on the other side of the connection. + */ + server_sockbufsize = ntohl(startcapreply.bufsize); + + /* Let's get the actual size of the socket buffer */ + itemp = sizeof(sockbufsize); + + res = getsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &itemp); + if (res == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "pcap_startcapture_remote(): getsockopt() failed"); + goto error; + } + + /* + * Warning: on some kernels (e.g. Linux), the size of the user + * buffer does not take into account the pcap_header and such, + * and it is set equal to the snaplen. + * + * In my view, this is wrong (the meaning of the bufsize became + * a bit strange). So, here bufsize is the whole size of the + * user buffer. In case the bufsize returned is too small, + * let's adjust it accordingly. + */ + if (server_sockbufsize <= (u_int) fp->snapshot) + server_sockbufsize += sizeof(struct pcap_pkthdr); + + /* if the current socket buffer is smaller than the desired one */ + if ((u_int) sockbufsize < server_sockbufsize) + { + /* + * Loop until the buffer size is OK or the original + * socket buffer size is larger than this one. + */ + for (;;) + { + res = setsockopt(sockdata, SOL_SOCKET, SO_RCVBUF, + (char *)&(server_sockbufsize), + sizeof(server_sockbufsize)); + + if (res == 0) + break; + + /* + * If something goes wrong, halve the buffer size + * (checking that it does not become smaller than + * the current one). + */ + server_sockbufsize /= 2; + + if ((u_int) sockbufsize >= server_sockbufsize) + { + server_sockbufsize = sockbufsize; + break; + } + } + } + + /* + * Let's allocate the packet; this is required in order to put + * the packet somewhere when extracting data from the socket. + * Since buffering has already been done in the socket buffer, + * here we need just a buffer whose size is equal to the + * largest possible packet message for the snapshot size, + * namely the length of the message header plus the length + * of the packet header plus the snapshot length. + */ + fp->bufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + fp->snapshot; + + fp->buffer = (u_char *)malloc(fp->bufsize); + if (fp->buffer == NULL) + { + pcapint_fmt_errmsg_for_errno(fp->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto error; + } + + /* + * The buffer is currently empty. + */ + fp->bp = fp->buffer; + fp->cc = 0; + + /* Discard the rest of the message. */ + if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, fp->errbuf) == -1) + goto error_nodiscard; + + /* + * In case the user does not want to capture RPCAP packets, let's update the filter + * We have to update it here (instead of sending it into the 'StartCapture' message + * because when we generate the 'start capture' we do not know (yet) all the ports + * we're currently using. + */ + if (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP) + { + struct bpf_program fcode; + + if (pcap_createfilter_norpcappkt(fp, &fcode) == -1) + goto error; + + /* We cannot use 'pcap_setfilter_rpcap' because formally the capture has not been started yet */ + /* (the 'pr->rmt_capstarted' variable will be updated some lines below) */ + if (pcap_updatefilter_remote(fp, &fcode) == -1) + goto error; + + pcap_freecode(&fcode); + } + + pr->rmt_capstarted = 1; + return 0; + +error: + /* + * When the connection has been established, we have to close it. So, at the + * beginning of this function, if an error occur we return immediately with + * a return NULL; when the connection is established, we have to come here + * ('goto error;') in order to close everything properly. + */ + + /* + * Discard the rest of the message. + * We already reported an error; if this gets an error, just + * drive on. + */ + (void)rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, plen, NULL); + +error_nodiscard: +#ifdef HAVE_OPENSSL + if (pr->data_ssl) + { + // Finish using the SSL handle for the data socket. + // This must be done *before* the socket is closed. + ssl_finish(pr->data_ssl); + pr->data_ssl = NULL; + } +#endif + + /* we can be here because sockdata said 'error' */ + if ((sockdata != 0) && (sockdata != INVALID_SOCKET)) + sock_close(sockdata, NULL, 0); + + if (!active) + { +#ifdef HAVE_OPENSSL + if (pr->ctrl_ssl) + { + // Finish using the SSL handle for the control socket. + // This must be done *before* the socket is closed. + ssl_finish(pr->ctrl_ssl); + pr->ctrl_ssl = NULL; + } +#endif + sock_close(pr->rmt_sockctrl, NULL, 0); + } + + if (addrinfo != NULL) + freeaddrinfo(addrinfo); + + /* + * We do not have to call pcap_close() here, because this function is always called + * by the user in case something bad happens + */ +#if 0 + if (fp) + { + pcap_close(fp); + fp= NULL; + } +#endif + + return -1; +} + +/* + * This function takes a bpf program and sends it to the other host. + * + * This function can be called in two cases: + * - pcap_startcapture_remote() is called (we have to send the filter + * along with the 'start capture' command) + * - we want to update the filter during a capture (i.e. pcap_setfilter() + * after the capture has been started) + * + * This function serializes the filter into the sending buffer ('sendbuf', + * passed as a parameter) and return back. It does not send anything on + * the network. + * + * \param fp: the pcap_t descriptor of the device currently opened. + * + * \param sendbuf: the buffer on which the serialized data has to copied. + * + * \param sendbufidx: it is used to return the amount of bytes copied into the buffer. + * + * \param prog: the bpf program we have to copy. + * + * \return '0' if everything is fine, '-1' otherwise. The error message (if one) + * is returned into the 'errbuf' field of the pcap_t structure. + */ +static int pcap_pack_bpffilter(pcap_t *fp, char *sendbuf, int *sendbufidx, struct bpf_program *prog) +{ + struct rpcap_filter *filter; + struct rpcap_filterbpf_insn *insn; + struct bpf_insn *bf_insn; + struct bpf_program fake_prog; /* To be used just in case the user forgot to set a filter */ + unsigned int i; + + if (prog->bf_len == 0) /* No filters have been specified; so, let's apply a "fake" filter */ + { + if (pcap_compile(fp, &fake_prog, NULL /* buffer */, 1, 0) == -1) + return -1; + + prog = &fake_prog; + } + + filter = (struct rpcap_filter *) sendbuf; + + if (sock_bufferize(NULL, sizeof(struct rpcap_filter), NULL, sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + filter->filtertype = htons(RPCAP_UPDATEFILTER_BPF); + filter->nitems = htonl((int32)prog->bf_len); + + if (sock_bufferize(NULL, prog->bf_len * sizeof(struct rpcap_filterbpf_insn), + NULL, sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + insn = (struct rpcap_filterbpf_insn *) (filter + 1); + bf_insn = prog->bf_insns; + + for (i = 0; i < prog->bf_len; i++) + { + insn->code = htons(bf_insn->code); + insn->jf = bf_insn->jf; + insn->jt = bf_insn->jt; + insn->k = htonl(bf_insn->k); + + insn++; + bf_insn++; + } + + return 0; +} + +/* + * This function updates a filter on a remote host. + * + * It is called when the user wants to update a filter. + * In case we're capturing from the network, it sends the filter to our + * peer. + * This function is *not* called automatically when the user calls + * pcap_setfilter(). + * There will be two cases: + * - the capture has been started: in this case, pcap_setfilter_rpcap() + * calls pcap_updatefilter_remote() + * - the capture has not started yet: in this case, pcap_setfilter_rpcap() + * stores the filter into the pcap_t structure, and then the filter is + * sent with pcap_startcap(). + * + * WARNING This function *does not* clear the packet currently into the + * buffers. Therefore, the user has to expect to receive some packets + * that are related to the previous filter. If you want to discard all + * the packets before applying a new filter, you have to close the + * current capture session and start a new one. + * + * XXX - we really should have pcap_setfilter() always discard packets + * received with the old filter, and have a separate pcap_setfilter_noflush() + * function that doesn't discard any packets. + */ +static int pcap_updatefilter_remote(pcap_t *fp, struct bpf_program *prog) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + struct rpcap_header header; /* To keep the reply message */ + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + rpcap_createhdr((struct rpcap_header *) sendbuf, + pr->protocol_version, RPCAP_MSG_UPDATEFILTER_REQ, 0, + sizeof(struct rpcap_filter) + prog->bf_len * sizeof(struct rpcap_filterbpf_insn)); + + if (pcap_pack_bpffilter(fp, &sendbuf[sendbufidx], &sendbufidx, prog)) + return -1; + + if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf, + PCAP_ERRBUF_SIZE) < 0) + return -1; + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version, + RPCAP_MSG_UPDATEFILTER_REQ, &header, fp->errbuf) == -1) + return -1; + + /* + * It shouldn't have any contents; discard it if it does. + */ + if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1) + return -1; + + return 0; +} + +static void +pcap_save_current_filter_rpcap(pcap_t *fp, const char *filter) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + + /* + * Check if: + * - We are on an remote capture + * - we do not want to capture RPCAP traffic + * + * If so, we have to save the current filter, because we have to + * add some piece of stuff later + */ + if (pr->rmt_clientside && + (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP)) + { + if (pr->currentfilter) + free(pr->currentfilter); + + if (filter == NULL) + filter = ""; + + pr->currentfilter = strdup(filter); + } +} + +/* + * This function sends a filter to a remote host. + * + * This function is called when the user wants to set a filter. + * It sends the filter to our peer. + * This function is called automatically when the user calls pcap_setfilter(). + * + * Parameters and return values are exactly the same of pcap_setfilter(). + */ +static int pcap_setfilter_rpcap(pcap_t *fp, struct bpf_program *prog) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + + if (!pr->rmt_capstarted) + { + /* copy filter into the pcap_t structure */ + if (pcapint_install_bpf_program(fp, prog) == -1) + return -1; + return 0; + } + + /* we have to update a filter during run-time */ + if (pcap_updatefilter_remote(fp, prog)) + return -1; + + return 0; +} + +/* + * This function updates the current filter in order not to capture rpcap + * packets. + * + * This function is called *only* when the user wants exclude RPCAP packets + * related to the current session from the captured packets. + * + * \return '0' if everything is fine, '-1' otherwise. The error message (if one) + * is returned into the 'errbuf' field of the pcap_t structure. + */ +static int pcap_createfilter_norpcappkt(pcap_t *fp, struct bpf_program *prog) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + int RetVal = 0; + + /* We do not want to capture our RPCAP traffic. So, let's update the filter */ + if (pr->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP) + { + struct sockaddr_storage saddr; /* temp, needed to retrieve the network data port chosen on the local machine */ + socklen_t saddrlen; /* temp, needed to retrieve the network data port chosen on the local machine */ + char myaddress[128]; + char myctrlport[128]; + char mydataport[128]; + char peeraddress[128]; + char peerctrlport[128]; + char *newfilter; + + /* Get the name/port of our peer */ + saddrlen = sizeof(struct sockaddr_storage); + if (getpeername(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); + return -1; + } + + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peeraddress, + sizeof(peeraddress), peerctrlport, sizeof(peerctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + return -1; + } + + /* We cannot check the data port, because this is available only in case of TCP sockets */ + /* Get the name/port of the current host */ + if (getsockname(pr->rmt_sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); + return -1; + } + + /* Get the local port the system picked up */ + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, myaddress, + sizeof(myaddress), myctrlport, sizeof(myctrlport), NI_NUMERICHOST | NI_NUMERICSERV)) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + return -1; + } + + /* Let's now check the data port */ + if (getsockname(pr->rmt_sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); + return -1; + } + + /* Get the local port the system picked up */ + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, 0, mydataport, sizeof(mydataport), NI_NUMERICSERV)) + { + sock_geterrmsg(fp->errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + return -1; + } + + if (pr->currentfilter && pr->currentfilter[0] != '\0') + { + /* + * We have a current filter; add items to it to + * filter out this rpcap session. + */ + if (pcapint_asprintf(&newfilter, + "(%s) and not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", + pr->currentfilter, myaddress, peeraddress, + myctrlport, peerctrlport, myaddress, peeraddress, + mydataport) == -1) + { + /* Failed. */ + snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Can't allocate memory for new filter"); + return -1; + } + } + else + { + /* + * We have no current filter; construct a filter to + * filter out this rpcap session. + */ + if (pcapint_asprintf(&newfilter, + "not (host %s and host %s and port %s and port %s) and not (host %s and host %s and port %s)", + myaddress, peeraddress, myctrlport, peerctrlport, + myaddress, peeraddress, mydataport) == -1) + { + /* Failed. */ + snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Can't allocate memory for new filter"); + return -1; + } + } + + /* + * This is only an hack to prevent the save_current_filter + * routine, which will be called when we call pcap_compile(), + * from saving the modified filter. + */ + pr->rmt_clientside = 0; + + if (pcap_compile(fp, prog, newfilter, 1, 0) == -1) + RetVal = -1; + + /* Undo the hack. */ + pr->rmt_clientside = 1; + + free(newfilter); + } + + return RetVal; +} + +/* + * This function sets sampling parameters in the remote host. + * + * It is called when the user wants to set activate sampling on the + * remote host. + * + * Sampling parameters are defined into the 'pcap_t' structure. + * + * \param p: the pcap_t descriptor of the device currently opened. + * + * \return '0' if everything is OK, '-1' is something goes wrong. The + * error message is returned in the 'errbuf' member of the pcap_t structure. + */ +static int pcap_setsampling_remote(pcap_t *fp) +{ + struct pcap_rpcap *pr = fp->priv; /* structure used when doing a remote live capture */ + char sendbuf[RPCAP_NETBUF_SIZE];/* temporary buffer in which data to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + struct rpcap_header header; /* To keep the reply message */ + struct rpcap_sampling *sampling_pars; /* Structure that is needed to send sampling parameters to the remote host */ + + /* If no sampling is requested, return 'ok' */ + if (fp->rmt_samp.method == PCAP_SAMP_NOSAMP) + return 0; + + /* + * Check for sampling parameters that don't fit in a message. + * We'll let the server complain about invalid parameters + * that do fit into the message. + */ + if (fp->rmt_samp.method < 0 || fp->rmt_samp.method > 255) { + snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Invalid sampling method %d", fp->rmt_samp.method); + return -1; + } + if (fp->rmt_samp.value < 0 || fp->rmt_samp.value > 65535) { + snprintf(fp->errbuf, PCAP_ERRBUF_SIZE, + "Invalid sampling value %d", fp->rmt_samp.value); + return -1; + } + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + rpcap_createhdr((struct rpcap_header *) sendbuf, + pr->protocol_version, RPCAP_MSG_SETSAMPLING_REQ, 0, + sizeof(struct rpcap_sampling)); + + /* Fill the structure needed to open an adapter remotely */ + sampling_pars = (struct rpcap_sampling *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_sampling), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + memset(sampling_pars, 0, sizeof(struct rpcap_sampling)); + + sampling_pars->method = (uint8)fp->rmt_samp.method; + sampling_pars->value = (uint16)htonl(fp->rmt_samp.value); + + if (sock_send(pr->rmt_sockctrl, pr->ctrl_ssl, sendbuf, sendbufidx, fp->errbuf, + PCAP_ERRBUF_SIZE) < 0) + return -1; + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(pr->rmt_sockctrl, pr->ctrl_ssl, pr->protocol_version, + RPCAP_MSG_SETSAMPLING_REQ, &header, fp->errbuf) == -1) + return -1; + + /* + * It shouldn't have any contents; discard it if it does. + */ + if (rpcap_discard(pr->rmt_sockctrl, pr->ctrl_ssl, header.plen, fp->errbuf) == -1) + return -1; + + return 0; +} + +/********************************************************* + * * + * Miscellaneous functions * + * * + *********************************************************/ + +/* + * This function performs authentication and protocol version + * negotiation. It is required in order to open the connection + * with the other end party. + * + * It sends authentication parameters on the control socket and + * reads the reply. If the reply is a success indication, it + * checks whether the reply includes minimum and maximum supported + * versions from the server; if not, it assumes both are 0, as + * that means it's an older server that doesn't return supported + * version numbers in authentication replies, so it only supports + * version 0. It then tries to determine the maximum version + * supported both by us and by the server. If it can find such a + * version, it sets us up to use that version; otherwise, it fails, + * indicating that there is no version supported by us and by the + * server. + * + * \param sock: the socket we are currently using. + * + * \param ver: pointer to variable to which to set the protocol version + * number we selected. + * + * \param byte_swapped: pointer to variable to which to set 1 if the + * byte order the server says it has is byte-swapped from ours, 0 + * otherwise (whether it's the same as ours or is unknown). + * + * \param auth: authentication parameters that have to be sent. + * + * \param errbuf: a pointer to a user-allocated buffer (of size + * PCAP_ERRBUF_SIZE) that will contain the error message (in case there + * is one). It could be a network problem or the fact that the authorization + * failed. + * + * \return '0' if everything is fine, '-1' for an error. For errors, + * an error message string is returned in the 'errbuf' variable. + */ +static int rpcap_doauth(PCAP_SOCKET sockctrl, SSL *ssl, uint8 *ver, + int *byte_swapped, struct pcap_rmtauth *auth, char *errbuf) +{ + char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data that has to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + uint16 length; /* length of the payload of this message */ + struct rpcap_auth *rpauth; + uint16 auth_type; + struct rpcap_header header; + size_t str_length; + uint32 plen; + struct rpcap_authreply authreply; /* authentication reply message */ + uint8 ourvers; + int has_byte_order; /* The server sent its version of the byte-order magic number */ + u_int their_byte_order_magic; /* Here's what it is */ + + if (auth) + { + switch (auth->type) + { + case RPCAP_RMTAUTH_NULL: + length = sizeof(struct rpcap_auth); + break; + + case RPCAP_RMTAUTH_PWD: + length = sizeof(struct rpcap_auth); + if (auth->username) + { + str_length = strlen(auth->username); + if (str_length > 65535) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "User name is too long (> 65535 bytes)"); + return -1; + } + length += (uint16)str_length; + } + if (auth->password) + { + str_length = strlen(auth->password); + if (str_length > 65535) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Password is too long (> 65535 bytes)"); + return -1; + } + length += (uint16)str_length; + } + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized."); + return -1; + } + + auth_type = (uint16)auth->type; + } + else + { + auth_type = RPCAP_RMTAUTH_NULL; + length = sizeof(struct rpcap_auth); + } + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + rpcap_createhdr((struct rpcap_header *) sendbuf, 0, + RPCAP_MSG_AUTH_REQ, 0, length); + + rpauth = (struct rpcap_auth *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_auth), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + memset(rpauth, 0, sizeof(struct rpcap_auth)); + + rpauth->type = htons(auth_type); + + if (auth_type == RPCAP_RMTAUTH_PWD) + { + if (auth->username) + rpauth->slen1 = (uint16)strlen(auth->username); + else + rpauth->slen1 = 0; + + if (sock_bufferize(auth->username, rpauth->slen1, sendbuf, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + if (auth->password) + rpauth->slen2 = (uint16)strlen(auth->password); + else + rpauth->slen2 = 0; + + if (sock_bufferize(auth->password, rpauth->slen2, sendbuf, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + rpauth->slen1 = htons(rpauth->slen1); + rpauth->slen2 = htons(rpauth->slen2); + } + + if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf, + PCAP_ERRBUF_SIZE) < 0) + return -1; + + /* Receive and process the reply message header */ + if (rpcap_process_msg_header(sockctrl, ssl, 0, RPCAP_MSG_AUTH_REQ, + &header, errbuf) == -1) + return -1; + + /* + * OK, it's an authentication reply, so we're logged in. + * + * Did it send any additional information? + */ + plen = header.plen; + if (plen != 0) + { + size_t reply_len; + + /* Yes - is it big enough to include version information? */ + if (plen < sizeof(struct rpcap_authreply_old)) + { + /* No - discard it and fail. */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Authentication reply from server is too short"); + (void)rpcap_discard(sockctrl, ssl, plen, NULL); + return -1; + } + + /* Yes - does it include server byte order information? */ + if (plen == sizeof(struct rpcap_authreply_old)) + { + /* No - just read the version information */ + has_byte_order = 0; + reply_len = sizeof(struct rpcap_authreply_old); + } + else if (plen >= sizeof(struct rpcap_authreply_old)) + { + /* Yes - read it all. */ + has_byte_order = 1; + reply_len = sizeof(struct rpcap_authreply); + } + else + { + /* + * Too long for old reply, too short for new reply. + * Discard it and fail. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Authentication reply from server is too short"); + (void)rpcap_discard(sockctrl, ssl, plen, NULL); + return -1; + } + + /* Read the reply body */ + if (rpcap_recv(sockctrl, ssl, (char *)&authreply, + reply_len, &plen, errbuf) == -1) + { + (void)rpcap_discard(sockctrl, ssl, plen, NULL); + return -1; + } + + /* Discard the rest of the message, if there is any. */ + if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1) + return -1; + + /* + * Check the minimum and maximum versions for sanity; + * the minimum must be <= the maximum. + */ + if (authreply.minvers > authreply.maxvers) + { + /* + * Bogus - give up on this server. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server's minimum supported protocol version is greater than its maximum supported protocol version"); + return -1; + } + + if (has_byte_order) + { + their_byte_order_magic = authreply.byte_order_magic; + } + else + { + /* + * The server didn't tell us what its byte + * order is; assume it's ours. + */ + their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC; + } + } + else + { + /* No - it supports only version 0. */ + authreply.minvers = 0; + authreply.maxvers = 0; + + /* + * And it didn't tell us what its byte order is; assume + * it's ours. + */ + has_byte_order = 0; + their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC; + } + + /* + * OK, let's start with the maximum version the server supports. + */ + ourvers = authreply.maxvers; + +#if RPCAP_MIN_VERSION != 0 + /* + * If that's less than the minimum version we support, we + * can't communicate. + */ + if (ourvers < RPCAP_MIN_VERSION) + goto novers; +#endif + + /* + * If that's greater than the maximum version we support, + * choose the maximum version we support. + */ + if (ourvers > RPCAP_MAX_VERSION) + { + ourvers = RPCAP_MAX_VERSION; + + /* + * If that's less than the minimum version they + * support, we can't communicate. + */ + if (ourvers < authreply.minvers) + goto novers; + } + + /* + * Is the server byte order the opposite of ours? + */ + if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC) + { + /* No, it's the same. */ + *byte_swapped = 0; + } + else if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC_SWAPPED) + { + /* Yes, it's the opposite of ours. */ + *byte_swapped = 1; + } + else + { + /* They sent us something bogus. */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server did not send us a valid byte order value"); + return -1; + } + + *ver = ourvers; + return 0; + +novers: + /* + * There is no version we both support; that is a fatal error. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The server doesn't support any protocol version that we support"); + return -1; +} + +/* We don't currently support non-blocking mode. */ +static int +pcap_getnonblock_rpcap(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for capturing remotely with rpcap"); + return (-1); +} + +static int +pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for capturing remotely with rpcap"); + return (-1); +} + +static int +rpcap_setup_session(const char *source, struct pcap_rmtauth *auth, + int *activep, PCAP_SOCKET *sockctrlp, uint8 *uses_sslp, SSL **sslp, + int rmt_flags, uint8 *protocol_versionp, int *byte_swappedp, + char *host, char *port, char *iface, char *errbuf) +{ + int type; + struct activehosts *activeconn; /* active connection, if there is one */ + int error; /* 1 if rpcap_remoteact_getsock got an error */ + + /* + * Determine the type of the source (NULL, file, local, remote). + * You must have a valid source string even if we're in active mode, + * because otherwise the call to the following function will fail. + */ + if (pcapint_parsesrcstr_ex(source, &type, host, port, iface, uses_sslp, + errbuf) == -1) + return -1; + + /* + * It must be remote. + */ + if (type != PCAP_SRC_IFREMOTE) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Non-remote interface passed to remote capture routine"); + return -1; + } + + /* + * We don't yet support DTLS, so if the user asks for a TLS + * connection and asks for data packets to be sent over UDP, + * we have to give up. + */ + if (*uses_sslp && (rmt_flags & PCAP_OPENFLAG_DATATX_UDP)) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "TLS not supported with UDP forward of remote packets"); + return -1; + } + + /* Warning: this call can be the first one called by the user. */ + /* For this reason, we have to initialize the Winsock support. */ + if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) + return -1; + + /* Check for active mode */ + activeconn = rpcap_remoteact_getsock(host, &error, errbuf); + if (activeconn != NULL) + { + *activep = 1; + *sockctrlp = activeconn->sockctrl; + *sslp = activeconn->ssl; + *protocol_versionp = activeconn->protocol_version; + *byte_swappedp = activeconn->byte_swapped; + } + else + { + *activep = 0; + struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */ + struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */ + + if (error) + { + /* + * Call failed. + */ + return -1; + } + + /* + * We're not in active mode; let's try to open a new + * control connection. + */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (port[0] == 0) + { + /* the user chose not to specify the port */ + addrinfo = sock_initaddress(host, RPCAP_DEFAULT_NETPORT, + &hints, errbuf, PCAP_ERRBUF_SIZE); + } + else + { + addrinfo = sock_initaddress(host, port, &hints, + errbuf, PCAP_ERRBUF_SIZE); + } + if (addrinfo == NULL) + return -1; + + if ((*sockctrlp = sock_open(host, addrinfo, SOCKOPEN_CLIENT, 0, + errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + freeaddrinfo(addrinfo); + return -1; + } + + /* addrinfo is no longer used */ + freeaddrinfo(addrinfo); + addrinfo = NULL; + + if (*uses_sslp) + { +#ifdef HAVE_OPENSSL + *sslp = ssl_promotion(0, *sockctrlp, errbuf, + PCAP_ERRBUF_SIZE); + if (!*sslp) + { + sock_close(*sockctrlp, NULL, 0); + return -1; + } +#else + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "No TLS support"); + sock_close(*sockctrlp, NULL, 0); + return -1; +#endif + } + + if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, + byte_swappedp, auth, errbuf) == -1) + { +#ifdef HAVE_OPENSSL + if (*sslp) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is + // closed. + ssl_finish(*sslp); + } +#endif + sock_close(*sockctrlp, NULL, 0); + return -1; + } + } + return 0; +} + +/* + * This function opens a remote adapter by opening an RPCAP connection and + * so on. + * + * It does the job of pcap_open_live() for a remote interface; it's called + * by pcap_open() for remote interfaces. + * + * We do not start the capture until pcap_startcapture_remote() is called. + * + * This is because, when doing a remote capture, we cannot start capturing + * data as soon as the 'open adapter' command is sent. Suppose the remote + * adapter is already overloaded; if we start a capture (which, by default, + * has a NULL filter) the new traffic can saturate the network. + * + * Instead, we want to "open" the adapter, then send a "start capture" + * command only when we're ready to start the capture. + * This function does this job: it sends an "open adapter" command + * (according to the RPCAP protocol), but it does not start the capture. + * + * Since the other libpcap functions do not share this way of life, we + * have to do some dirty things in order to make everything work. + * + * \param source: see pcap_open(). + * \param snaplen: see pcap_open(). + * \param flags: see pcap_open(). + * \param read_timeout: see pcap_open(). + * \param auth: see pcap_open(). + * \param errbuf: see pcap_open(). + * + * \return a pcap_t pointer in case of success, NULL otherwise. In case of + * success, the pcap_t pointer can be used as a parameter to the following + * calls (pcap_compile() and so on). In case of problems, errbuf contains + * a text explanation of error. + * + * WARNING: In case we call pcap_compile() and the capture has not yet + * been started, the filter will be saved into the pcap_t structure, + * and it will be sent to the other host later (when + * pcap_startcapture_remote() is called). + */ +pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf) +{ + pcap_t *fp; + char *source_str; + struct pcap_rpcap *pr; /* structure used when doing a remote live capture */ + char host[PCAP_BUF_SIZE], ctrlport[PCAP_BUF_SIZE], iface[PCAP_BUF_SIZE]; + PCAP_SOCKET sockctrl; + SSL *ssl = NULL; + uint8 protocol_version; /* negotiated protocol version */ + int byte_swapped; /* server is known to be byte-swapped */ + int active; + uint32 plen; + char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + + /* RPCAP-related variables */ + struct rpcap_header header; /* header of the RPCAP packet */ + struct rpcap_openreply openreply; /* open reply message */ + + fp = PCAP_CREATE_COMMON(errbuf, struct pcap_rpcap); + if (fp == NULL) + { + return NULL; + } + source_str = strdup(source); + if (source_str == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return NULL; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + * + * XXX - should we leave this up to the remote server to + * do? + */ + if (snaplen <= 0 || snaplen > MAXIMUM_SNAPLEN) + snaplen = MAXIMUM_SNAPLEN; + + fp->opt.device = source_str; + fp->snapshot = snaplen; + fp->opt.timeout = read_timeout; + pr = fp->priv; + pr->rmt_flags = flags; + + /* + * Attempt to set up the session with the server. + */ + if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl, + &pr->uses_ssl, &ssl, flags, &protocol_version, &byte_swapped, + host, ctrlport, iface, errbuf) == -1) + { + /* Session setup failed. */ + pcap_close(fp); + return NULL; + } + + /* All good so far, save the ssl handler */ + ssl_main = ssl; + + /* + * Now it's time to start playing with the RPCAP protocol + * RPCAP open command: create the request message + */ + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) + goto error_nodiscard; + + rpcap_createhdr((struct rpcap_header *) sendbuf, protocol_version, + RPCAP_MSG_OPEN_REQ, 0, (uint32) strlen(iface)); + + if (sock_bufferize(iface, (int) strlen(iface), sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) + goto error_nodiscard; + + if (sock_send(sockctrl, ssl, sendbuf, sendbufidx, errbuf, + PCAP_ERRBUF_SIZE) < 0) + goto error_nodiscard; + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(sockctrl, ssl, protocol_version, + RPCAP_MSG_OPEN_REQ, &header, errbuf) == -1) + goto error_nodiscard; + plen = header.plen; + + /* Read the reply body */ + if (rpcap_recv(sockctrl, ssl, (char *)&openreply, + sizeof(struct rpcap_openreply), &plen, errbuf) == -1) + goto error; + + /* Discard the rest of the message, if there is any. */ + if (rpcap_discard(sockctrl, ssl, plen, errbuf) == -1) + goto error_nodiscard; + + /* Set proper fields into the pcap_t struct */ + fp->linktype = ntohl(openreply.linktype); + pr->rmt_sockctrl = sockctrl; + pr->ctrl_ssl = ssl; + pr->protocol_version = protocol_version; + pr->byte_swapped = byte_swapped; + pr->rmt_clientside = 1; + + /* This code is duplicated from the end of this function */ + fp->read_op = pcap_read_rpcap; + fp->save_current_filter_op = pcap_save_current_filter_rpcap; + fp->setfilter_op = pcap_setfilter_rpcap; + fp->getnonblock_op = pcap_getnonblock_rpcap; + fp->setnonblock_op = pcap_setnonblock_rpcap; + fp->stats_op = pcap_stats_rpcap; +#ifdef _WIN32 + fp->stats_ex_op = pcap_stats_ex_rpcap; +#endif + fp->cleanup_op = pcap_cleanup_rpcap; + + fp->activated = 1; + return fp; + +error: + /* + * When the connection has been established, we have to close it. So, at the + * beginning of this function, if an error occur we return immediately with + * a return NULL; when the connection is established, we have to come here + * ('goto error;') in order to close everything properly. + */ + + /* + * Discard the rest of the message. + * We already reported an error; if this gets an error, just + * drive on. + */ + (void)rpcap_discard(sockctrl, pr->ctrl_ssl, plen, NULL); + +error_nodiscard: + if (!active) + { +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + } + + pcap_close(fp); + return NULL; +} + +/* String identifier to be used in the pcap_findalldevs_ex() */ +#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" +#define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof PCAP_TEXT_SOURCE_ADAPTER - 1) +/* String identifier to be used in the pcap_findalldevs_ex() */ +#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node" +#define PCAP_TEXT_SOURCE_ON_REMOTE_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_REMOTE_HOST - 1) + +static void +freeaddr(struct pcap_addr *addr) +{ + free(addr->addr); + free(addr->netmask); + free(addr->broadaddr); + free(addr->dstaddr); + free(addr); +} + +int +pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) +{ + uint8 protocol_version; /* protocol version */ + int byte_swapped; /* Server byte order is swapped from ours */ + PCAP_SOCKET sockctrl; /* socket descriptor of the control connection */ + SSL *ssl = NULL; /* optional SSL handler for sockctrl */ + uint32 plen; + struct rpcap_header header; /* structure that keeps the general header of the rpcap protocol */ + int i, j; /* temp variables */ + int nif; /* Number of interfaces listed */ + int active; /* 'true' if we the other end-party is in active mode */ + uint8 uses_ssl; + char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE]; + char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ + pcap_if_t *lastdev; /* Last device in the pcap_if_t list */ + pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */ + + /* List starts out empty. */ + (*alldevs) = NULL; + lastdev = NULL; + + /* + * Attempt to set up the session with the server. + */ + if (rpcap_setup_session(source, auth, &active, &sockctrl, &uses_ssl, + &ssl, 0, &protocol_version, &byte_swapped, host, port, NULL, + errbuf) == -1) + { + /* Session setup failed. */ + return -1; + } + + /* RPCAP findalldevs command */ + rpcap_createhdr(&header, protocol_version, RPCAP_MSG_FINDALLIF_REQ, + 0, 0); + + if (sock_send(sockctrl, ssl, (char *)&header, sizeof(struct rpcap_header), + errbuf, PCAP_ERRBUF_SIZE) < 0) + goto error_nodiscard; + + /* Receive and process the reply message header. */ + if (rpcap_process_msg_header(sockctrl, ssl, protocol_version, + RPCAP_MSG_FINDALLIF_REQ, &header, errbuf) == -1) + goto error_nodiscard; + + plen = header.plen; + + /* read the number of interfaces */ + nif = ntohs(header.value); + + /* loop until all interfaces have been received */ + for (i = 0; i < nif; i++) + { + struct rpcap_findalldevs_if findalldevs_if; + char tmpstring2[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ + struct pcap_addr *addr, *prevaddr; + + tmpstring2[PCAP_BUF_SIZE] = 0; + + /* receive the findalldevs structure from remote host */ + if (rpcap_recv(sockctrl, ssl, (char *)&findalldevs_if, + sizeof(struct rpcap_findalldevs_if), &plen, errbuf) == -1) + goto error; + + findalldevs_if.namelen = ntohs(findalldevs_if.namelen); + findalldevs_if.desclen = ntohs(findalldevs_if.desclen); + findalldevs_if.naddr = ntohs(findalldevs_if.naddr); + + /* allocate the main structure */ + dev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); + if (dev == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + goto error; + } + + /* Initialize the structure to 'zero' */ + memset(dev, 0, sizeof(pcap_if_t)); + + /* Append it to the list. */ + if (lastdev == NULL) + { + /* + * List is empty, so it's also the first device. + */ + *alldevs = dev; + } + else + { + /* + * Append after the last device. + */ + lastdev->next = dev; + } + /* It's now the last device. */ + lastdev = dev; + + /* allocate mem for name and description */ + if (findalldevs_if.namelen) + { + + if (findalldevs_if.namelen >= sizeof(tmpstring)) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long"); + goto error; + } + + /* Retrieve adapter name */ + if (rpcap_recv(sockctrl, ssl, tmpstring, + findalldevs_if.namelen, &plen, errbuf) == -1) + goto error; + + tmpstring[findalldevs_if.namelen] = 0; + + /* Create the new device identifier */ + if (pcapint_createsrcstr_ex(tmpstring2, PCAP_SRC_IFREMOTE, + host, port, tmpstring, uses_ssl, errbuf) == -1) + goto error; + + dev->name = strdup(tmpstring2); + if (dev->name == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + goto error; + } + } + + if (findalldevs_if.desclen) + { + if (findalldevs_if.desclen >= sizeof(tmpstring)) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long"); + goto error; + } + + /* Retrieve adapter description */ + if (rpcap_recv(sockctrl, ssl, tmpstring, + findalldevs_if.desclen, &plen, errbuf) == -1) + goto error; + + tmpstring[findalldevs_if.desclen] = 0; + + if (pcapint_asprintf(&dev->description, + "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, + tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host) == -1) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + goto error; + } + } + + dev->flags = ntohl(findalldevs_if.flags); + + prevaddr = NULL; + /* loop until all addresses have been received */ + for (j = 0; j < findalldevs_if.naddr; j++) + { + struct rpcap_findalldevs_ifaddr ifaddr; + + /* Retrieve the interface addresses */ + if (rpcap_recv(sockctrl, ssl, (char *)&ifaddr, + sizeof(struct rpcap_findalldevs_ifaddr), + &plen, errbuf) == -1) + goto error; + + /* + * Deserialize all the address components. + */ + addr = (struct pcap_addr *) malloc(sizeof(struct pcap_addr)); + if (addr == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + goto error; + } + addr->next = NULL; + addr->addr = NULL; + addr->netmask = NULL; + addr->broadaddr = NULL; + addr->dstaddr = NULL; + + if (rpcap_deseraddr(&ifaddr.addr, &addr->addr, + errbuf) == -1) + { + freeaddr(addr); + goto error; + } + if (rpcap_deseraddr(&ifaddr.netmask, &addr->netmask, + errbuf) == -1) + { + freeaddr(addr); + goto error; + } + if (rpcap_deseraddr(&ifaddr.broadaddr, &addr->broadaddr, + errbuf) == -1) + { + freeaddr(addr); + goto error; + } + if (rpcap_deseraddr(&ifaddr.dstaddr, &addr->dstaddr, + errbuf) == -1) + { + freeaddr(addr); + goto error; + } + + if ((addr->addr == NULL) && (addr->netmask == NULL) && + (addr->broadaddr == NULL) && (addr->dstaddr == NULL)) + { + /* + * None of the addresses are IPv4 or IPv6 + * addresses, so throw this entry away. + */ + free(addr); + } + else + { + /* + * Add this entry to the list. + */ + if (prevaddr == NULL) + { + dev->addresses = addr; + } + else + { + prevaddr->next = addr; + } + prevaddr = addr; + } + } + } + + /* Discard the rest of the message. */ + if (rpcap_discard(sockctrl, ssl, plen, errbuf) == 1) + goto error_nodiscard; + + /* Control connection has to be closed only in case the remote machine is in passive mode */ + if (!active) + { + /* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */ +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + } + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); + + return 0; + +error: + /* + * In case there has been an error, I don't want to overwrite it with a new one + * if the following call fails. I want to return always the original error. + * + * Take care: this connection can already be closed when we try to close it. + * This happens because a previous error in the rpcapd, which requested to + * closed the connection. In that case, we already recognized that into the + * rpspck_isheaderok() and we already acknowledged the closing. + * In that sense, this call is useless here (however it is needed in case + * the client generates the error). + * + * Checks if all the data has been read; if not, discard the data in excess + */ + (void) rpcap_discard(sockctrl, ssl, plen, NULL); + +error_nodiscard: + /* Control connection has to be closed only in case the remote machine is in passive mode */ + if (!active) + { +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + } + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); + + /* Free whatever interfaces we've allocated. */ + pcap_freealldevs(*alldevs); + + return -1; +} + +/* + * Active mode routines. + * + * The old libpcap API is somewhat ugly, and makes active mode difficult + * to implement; we provide some APIs for it that work only with rpcap. + */ + +PCAP_SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, int uses_ssl, char *errbuf) +{ + /* socket-related variables */ + struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */ + struct addrinfo *addrinfo; /* keeps the addrinfo chain; required to open a new socket */ + struct sockaddr_storage from; /* generic sockaddr_storage variable */ + socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */ + PCAP_SOCKET sockctrl; /* keeps the main socket identifier */ + SSL *ssl = NULL; /* Optional SSL handler for sockctrl */ + uint8 protocol_version; /* negotiated protocol version */ + int byte_swapped; /* 1 if server byte order is known to be the reverse of ours */ + struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */ + + *connectinghost = 0; /* just in case */ + + /* Prepare to open a new server socket */ + memset(&hints, 0, sizeof(struct addrinfo)); + /* WARNING Currently it supports only ONE socket family among ipv4 and IPv6 */ + hints.ai_family = AF_INET; /* PF_UNSPEC to have both IPv4 and IPv6 server */ + hints.ai_flags = AI_PASSIVE; /* Ready to a bind() socket */ + hints.ai_socktype = SOCK_STREAM; + + /* Warning: this call can be the first one called by the user. */ + /* For this reason, we have to initialize the Winsock support. */ + if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) + return (PCAP_SOCKET)-1; + + /* Do the work */ + if ((port == NULL) || (port[0] == 0)) + { + addrinfo = sock_initaddress(address, + RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, errbuf, + PCAP_ERRBUF_SIZE); + } + else + { + addrinfo = sock_initaddress(address, port, &hints, errbuf, + PCAP_ERRBUF_SIZE); + } + if (addrinfo == NULL) + { + return (PCAP_SOCKET)-2; + } + + if ((sockmain = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + freeaddrinfo(addrinfo); + return (PCAP_SOCKET)-2; + } + freeaddrinfo(addrinfo); + + /* Connection creation */ + fromlen = sizeof(struct sockaddr_storage); + + sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen); + + /* We're not using sock_close, since we do not want to send a shutdown */ + /* (which is not allowed on a non-connected socket) */ + closesocket(sockmain); + sockmain = 0; + + if (sockctrl == INVALID_SOCKET) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed"); + return (PCAP_SOCKET)-2; + } + + /* Promote to SSL early before any error message may be sent */ + if (uses_ssl) + { +#ifdef HAVE_OPENSSL + ssl = ssl_promotion(0, sockctrl, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-1; + } +#else + snprintf(errbuf, PCAP_ERRBUF_SIZE, "No TLS support"); + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-1; +#endif + } + + /* Get the numeric for of the name of the connecting host */ + if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST)) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-1; + } + + /* checks if the connecting host is among the ones allowed */ + if (sock_check_hostlist(hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0) + { + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-1; + } + + /* + * Send authentication to the remote machine. + */ + if (rpcap_doauth(sockctrl, ssl, &protocol_version, &byte_swapped, + auth, errbuf) == -1) + { + /* Unrecoverable error. */ + rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-3; + } + + /* Checks that this host does not already have a cntrl connection in place */ + + /* Initialize pointers */ + temp = activeHosts; + prev = NULL; + + while (temp) + { + /* This host already has an active connection in place, so I don't have to update the host list */ + if (sock_cmpaddr(&temp->host, &from) == 0) + return sockctrl; + + prev = temp; + temp = temp->next; + } + + /* The host does not exist in the list; so I have to update the list */ + if (prev) + { + prev->next = (struct activehosts *) malloc(sizeof(struct activehosts)); + temp = prev->next; + } + else + { + activeHosts = (struct activehosts *) malloc(sizeof(struct activehosts)); + temp = activeHosts; + } + + if (temp == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + rpcap_senderror(sockctrl, ssl, protocol_version, PCAP_ERR_REMOTEACCEPT, errbuf, NULL); +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + return (PCAP_SOCKET)-1; + } + + memcpy(&temp->host, &from, fromlen); + temp->sockctrl = sockctrl; + temp->ssl = ssl; + temp->protocol_version = protocol_version; + temp->byte_swapped = byte_swapped; + temp->next = NULL; + + return sockctrl; +} + +PCAP_SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf) +{ + return pcap_remoteact_accept_ex(address, port, hostlist, connectinghost, auth, 0, errbuf); +} + +int pcap_remoteact_close(const char *host, char *errbuf) +{ + struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */ + struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ + + temp = activeHosts; + prev = NULL; + + /* retrieve the network address corresponding to 'host' */ + addrinfo = NULL; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + addrinfo = sock_initaddress(host, NULL, &hints, errbuf, + PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + { + return -1; + } + + while (temp) + { + ai_next = addrinfo; + while (ai_next) + { + if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0) + { + struct rpcap_header header; + int status = 0; + + /* Close this connection */ + rpcap_createhdr(&header, temp->protocol_version, + RPCAP_MSG_CLOSE, 0, 0); + + /* + * Don't check for errors, since we're + * just cleaning up. + */ + if (sock_send(temp->sockctrl, temp->ssl, + (char *)&header, + sizeof(struct rpcap_header), errbuf, + PCAP_ERRBUF_SIZE) < 0) + { + /* + * Let that error be the one we + * report. + */ +#ifdef HAVE_OPENSSL + if (temp->ssl) + { + // Finish using the SSL handle + // for the socket. + // This must be done *before* + // the socket is closed. + ssl_finish(temp->ssl); + } +#endif + (void)sock_close(temp->sockctrl, NULL, + 0); + status = -1; + } + else + { +#ifdef HAVE_OPENSSL + if (temp->ssl) + { + // Finish using the SSL handle + // for the socket. + // This must be done *before* + // the socket is closed. + ssl_finish(temp->ssl); + } +#endif + if (sock_close(temp->sockctrl, errbuf, + PCAP_ERRBUF_SIZE) == -1) + status = -1; + } + + /* + * Remove the host from the list of active + * hosts. + */ + if (prev) + prev->next = temp->next; + else + activeHosts = temp->next; + + freeaddrinfo(addrinfo); + + free(temp); + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); + + return status; + } + + ai_next = ai_next->ai_next; + } + prev = temp; + temp = temp->next; + } + + if (addrinfo) + freeaddrinfo(addrinfo); + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); + + snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known"); + return -1; +} + +void pcap_remoteact_cleanup(void) +{ +# ifdef HAVE_OPENSSL + if (ssl_main) + { + // Finish using the SSL handle for the main active socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl_main); + ssl_main = NULL; + } +# endif + + /* Very dirty, but it works */ + if (sockmain) + { + closesocket(sockmain); + + /* To avoid inconsistencies in the number of sock_init() */ + sock_cleanup(); + } +} + +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf) +{ + struct activehosts *temp; /* temp var needed to scan the host list chain */ + size_t len; + char hoststr[RPCAP_HOSTLIST_SIZE + 1]; + + temp = activeHosts; + + len = 0; + *hostlist = 0; + + while (temp) + { + /*int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) */ + + /* Get the numeric form of the name of the connecting host */ + if (sock_getascii_addrport((struct sockaddr_storage *) &temp->host, hoststr, + RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1) + /* if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, */ + /* RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) ) */ + { + /* sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, */ + /* "getnameinfo() failed"); */ + return -1; + } + + len = len + strlen(hoststr) + 1 /* the separator */; + + if ((size < 0) || (len >= (size_t)size)) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep " + "the hostnames for all the active connections"); + return -1; + } + + pcapint_strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE); + hostlist[len - 1] = sep; + hostlist[len] = 0; + + temp = temp->next; + } + + return 0; +} + +/* + * Receive the header of a message. + */ +static int rpcap_recv_msg_header(PCAP_SOCKET sock, SSL *ssl, struct rpcap_header *header, char *errbuf) +{ + int nrecv; + + nrecv = sock_recv(sock, ssl, (char *) header, sizeof(struct rpcap_header), + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE); + if (nrecv == -1) + { + /* Network error. */ + return -1; + } + header->plen = ntohl(header->plen); + return 0; +} + +/* + * Make sure the protocol version of a received message is what we were + * expecting. + */ +static int rpcap_check_msg_ver(PCAP_SOCKET sock, SSL *ssl, uint8 expected_ver, struct rpcap_header *header, char *errbuf) +{ + /* + * Did the server specify the version we negotiated? + */ + if (header->ver != expected_ver) + { + /* + * Discard the rest of the message. + */ + if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1) + return -1; + + /* + * Tell our caller that it's not the negotiated version. + */ + if (errbuf != NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Server sent us a message with version %u when we were expecting %u", + header->ver, expected_ver); + } + return -1; + } + return 0; +} + +/* + * Check the message type of a received message, which should either be + * the expected message type or RPCAP_MSG_ERROR. + */ +static int rpcap_check_msg_type(PCAP_SOCKET sock, SSL *ssl, uint8 request_type, struct rpcap_header *header, uint16 *errcode, char *errbuf) +{ + const char *request_type_string; + const char *msg_type_string; + + /* + * What type of message is it? + */ + if (header->type == RPCAP_MSG_ERROR) + { + /* + * The server reported an error. + * Hand that error back to our caller. + */ + *errcode = ntohs(header->value); + rpcap_msg_err(sock, ssl, header->plen, errbuf); + return -1; + } + + *errcode = 0; + + /* + * For a given request type value, the expected reply type value + * is the request type value with ORed with RPCAP_MSG_IS_REPLY. + */ + if (header->type != (request_type | RPCAP_MSG_IS_REPLY)) + { + /* + * This isn't a reply to the request we sent. + */ + + /* + * Discard the rest of the message. + */ + if (rpcap_discard(sock, ssl, header->plen, errbuf) == -1) + return -1; + + /* + * Tell our caller about it. + */ + request_type_string = rpcap_msg_type_string(request_type); + msg_type_string = rpcap_msg_type_string(header->type); + if (errbuf != NULL) + { + if (request_type_string == NULL) + { + /* This should not happen. */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "rpcap_check_msg_type called for request message with type %u", + request_type); + return -1; + } + if (msg_type_string != NULL) + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s message received in response to a %s message", + msg_type_string, request_type_string); + else + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Message of unknown type %u message received in response to a %s request", + header->type, request_type_string); + } + return -1; + } + + return 0; +} + +/* + * Receive and process the header of a message. + */ +static int rpcap_process_msg_header(PCAP_SOCKET sock, SSL *ssl, uint8 expected_ver, uint8 request_type, struct rpcap_header *header, char *errbuf) +{ + uint16 errcode; + + if (rpcap_recv_msg_header(sock, ssl, header, errbuf) == -1) + { + /* Network error. */ + return -1; + } + + /* + * Did the server specify the version we negotiated? + */ + if (rpcap_check_msg_ver(sock, ssl, expected_ver, header, errbuf) == -1) + return -1; + + /* + * Check the message type. + */ + return rpcap_check_msg_type(sock, ssl, request_type, header, + &errcode, errbuf); +} + +/* + * Read data from a message. + * If we're trying to read more data that remains, puts an error + * message into errmsgbuf and returns -2. Otherwise, tries to read + * the data and, if that succeeds, subtracts the amount read from + * the number of bytes of data that remains. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int rpcap_recv(PCAP_SOCKET sock, SSL *ssl, void *buffer, size_t toread, uint32 *plen, char *errbuf) +{ + int nread; + + if (toread > *plen) + { + /* The server sent us a bad message */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Message payload is too short"); + return -1; + } + nread = sock_recv(sock, ssl, buffer, toread, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + return -1; + } + *plen -= nread; + return 0; +} + +/* + * This handles the RPCAP_MSG_ERROR message. + */ +static void rpcap_msg_err(PCAP_SOCKET sockctrl, SSL *ssl, uint32 plen, char *remote_errbuf) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + + if (plen >= PCAP_ERRBUF_SIZE) + { + /* + * Message is too long; just read as much of it as we + * can into the buffer provided, and discard the rest. + */ + if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + DIAG_OFF_FORMAT_TRUNCATION + snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf); + DIAG_ON_FORMAT_TRUNCATION + return; + } + + /* + * Null-terminate it. + */ + remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0'; + +#ifdef _WIN32 + /* + * If we're not in UTF-8 mode, convert it to the local + * code page. + */ + if (!pcapint_utf_8_mode) + utf_8_to_acp_truncated(remote_errbuf); +#endif + + /* + * Throw away the rest. + */ + (void)rpcap_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1), remote_errbuf); + } + else if (plen == 0) + { + /* Empty error string. */ + remote_errbuf[0] = '\0'; + } + else + { + if (sock_recv(sockctrl, ssl, remote_errbuf, plen, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + DIAG_OFF_FORMAT_TRUNCATION + snprintf(remote_errbuf, PCAP_ERRBUF_SIZE, "Read of error message from client failed: %s", errbuf); + DIAG_ON_FORMAT_TRUNCATION + return; + } + + /* + * Null-terminate it. + */ + remote_errbuf[plen] = '\0'; + } +} + +/* + * Discard data from a connection. + * Mostly used to discard wrong-sized messages. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int rpcap_discard(PCAP_SOCKET sock, SSL *ssl, uint32 len, char *errbuf) +{ + if (len != 0) + { + if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + return -1; + } + } + return 0; +} + +/* + * Read bytes into the pcap_t's buffer until we have the specified + * number of bytes read or we get an error or interrupt indication. + */ +static int rpcap_read_packet_msg(struct pcap_rpcap const *rp, pcap_t *p, size_t size) +{ + u_char *bp; + int cc; + int bytes_read; + + bp = p->bp; + cc = p->cc; + + /* + * Loop until we have the amount of data requested or we get + * an error or interrupt. + */ + while ((size_t)cc < size) + { + /* + * We haven't read all of the packet header yet. + * Read what remains, which could be all of it. + */ + bytes_read = sock_recv(rp->rmt_sockdata, rp->data_ssl, bp, size - cc, + SOCK_RECEIVEALL_NO|SOCK_EOF_IS_ERROR, p->errbuf, + PCAP_ERRBUF_SIZE); + + if (bytes_read == -1) + { + /* + * Network error. Update the read pointer and + * byte count, and return an error indication. + */ + p->bp = bp; + p->cc = cc; + return -1; + } + if (bytes_read == -3) + { + /* + * Interrupted receive. Update the read + * pointer and byte count, and return + * an interrupted indication. + */ + p->bp = bp; + p->cc = cc; + return -3; + } + if (bytes_read == 0) + { + /* + * EOF - server terminated the connection. + * Update the read pointer and byte count, and + * return an error indication. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The server terminated the connection."); + return -1; + } + bp += bytes_read; + cc += bytes_read; + } + p->bp = bp; + p->cc = cc; + return 0; +} diff --git a/src/libpcap-1.10.5/pcap-rpcap.h b/src/libpcap-1.10.5/pcap-rpcap.h new file mode 100644 index 0000000000..6ad6d98d6a --- /dev/null +++ b/src/libpcap-1.10.5/pcap-rpcap.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef pcap_rpcap_h +#define pcap_rpcap_h + +/* + * Internal interfaces for "pcap_open()". + */ +pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, + int read_timeout, struct pcap_rmtauth *auth, char *errbuf); + +/* + * Internal interfaces for "pcap_findalldevs_ex()". + */ +int pcap_findalldevs_ex_remote(const char *source, + struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); + +#endif diff --git a/src/libpcap-1.10.5/pcap-savefile.manfile.in b/src/libpcap-1.10.5/pcap-savefile.manfile.in new file mode 100644 index 0000000000..e903ba8150 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-savefile.manfile.in @@ -0,0 +1,183 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-SAVEFILE @MAN_FILE_FORMATS@ "16 Aug 2023" +.SH NAME +pcap-savefile \- libpcap savefile format +.SH DESCRIPTION +NOTE: applications and libraries should, if possible, use libpcap to +read savefiles, rather than having their own code to read savefiles. +If, in the future, a new file format is supported by libpcap, +applications and libraries using libpcap to read savefiles will be able +to read the new format of savefiles, but applications and libraries +using their own code to read savefiles will have to be changed to +support the new file format. +.PP +``Savefiles'' read and written by libpcap and applications using libpcap +start with a per-file header. The format of the per-file header is: +.RS +.TS +box; +c s +c | c +c s. +Magic number +_ +Major version Minor version +_ +Reserved1 +_ +Reserved2 +_ +Snapshot length +_ +Link-layer header type and additional information +.TE +.RE +.PP +The per-file header length is 24 octets. +.PP +All fields in the per-file header are in the byte order of the host +writing the file. Normally, the first field in the per-file header is a +4-byte magic number, with the value 0xa1b2c3d4. The magic number, when +read by a host with the same byte order as the host that wrote the file, +will have the value 0xa1b2c3d4, and, when read by a host with the +opposite byte order as the host that wrote the file, will have the value +0xd4c3b2a1. That allows software reading the file to determine whether +the byte order of the host that wrote the file is the same as the byte +order of the host on which the file is being read, and thus whether the +values in the per-file and per-packet headers need to be byte-swapped. +.PP +If the magic number has the value 0xa1b23c4d (with the two nibbles of +the two lower-order bytes of the magic number swapped), which would be +read as 0xa1b23c4d by a host with the same byte order as the host that +wrote the file and as 0x4d3cb2a1 by a host with the opposite byte order +as the host that wrote the file, the file format is the same as for +regular files, except that the time stamps for packets are given in +seconds and nanoseconds rather than seconds and microseconds. +.PP +Following this are: +.IP +A 2-byte file format major version number; the current version number is +2. +.IP +A 2-byte file format minor version number; the current version number is +4. +.IP +A 4-byte not used - SHOULD be filled with 0 by pcap file writers, and MUST +be ignored by pcap file readers. This value was documented by some older +implementations as "gmt to local correction" or "time zone offset". +Some older pcap file writers stored non-zero values in this field. +.IP +A 4-byte not used - SHOULD be filled with 0 by pcap file writers, and MUST +be ignored by pcap file readers. This value was documented by some older +implementations as "accuracy of timestamps". Some older pcap file +writers stored non-zero values in this field. +.IP +A 4-byte number giving the "snapshot length" of the capture; packets +longer than the snapshot length are truncated to the snapshot length, so +that, if the snapshot length is +.IR N , +only the first +.I N +bytes of a packet longer than +.I N +bytes will be saved in the capture. +.IP +A 4-byte number giving the link-layer header type for packets in the +capture and optional additional information. +.IP +This format of this field is: +.PP +.nf + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|FCS len|R|P| Reserved3 | Link-layer type | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +.fi +.IP +The field is shown as if it were in the byte order of the host reading +or writing the file, with bit 0 being the most-significant bit of the +field and bit 31 being the least-significant bit of the field. +.IP +Link-layer type (16 bits): +A 16-bit value giving the link-layer header type for packets in the file; +see +.BR pcap-linktype (@MAN_MISC_INFO@) +for the +.B LINKTYPE_ +values that can appear in this field. +.IP +Reserved3 (10 bits): +not used - MUST be set to zero by pcap writers, and MUST NOT be +interpreted by pcap readers; a reader SHOULD treat a non-zero value as +an error. +.IP +P (1 bit): +A bit that, if set, indicates that the Frame Check Sequence (FCS) +length value is present and, if not set, indicates that the FCS value is +not present. +.IP +R (1 bit): +not used - MUST be set to zero by pcap writers, and MUST NOT be +interpreted by pcap readers; a reader SHOULD treat a non-zero value as +an error. +.IP +FCS len (4 bits): +A 4-bit unsigned value giving the number of 16-bit (2-octet) words +of FCS that are appended to each packet, if the P bit is set; if the P +bit is not set, and the FCS length is not indicated by the link-layer +type value, the FCS length is unknown. The valid values of the FCS len +field are between 0 and 15; Ethernet, for example, would have an FCS +length value of 2, corresponding to a 4-octet FCS. +.PP +Following the per-file header are zero or more packets; each packet +begins with a per-packet header, which is immediately followed by the +raw packet data. The format of the per-packet header is: +.RS +.TS +box; +c. +Time stamp, seconds value +_ +Time stamp, microseconds or nanoseconds value +_ +Length of captured packet data +_ +Un-truncated length of the packet data +.TE +.RE +.PP +The per-packet header length is 16 octets. +.PP +All fields in the per-packet header are in the byte order of the host +writing the file. The per-packet header begins with a time stamp giving +the approximate time the packet was captured; the time stamp consists of +a 4-byte value, giving the time in seconds since January 1, 1970, +00:00:00 UTC, followed by a 4-byte value, giving the time in +microseconds or nanoseconds since that second, depending on the magic +number in the file header. Following that are a 4-byte value giving the +number of bytes of captured data that follow the per-packet header and a +4-byte value giving the number of bytes that would have been present had +the packet not been truncated by the snapshot length. The two lengths +will be equal if the number of bytes of packet data are less than or +equal to the snapshot length. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap-septel.c b/src/libpcap-1.10.5/pcap-septel.c new file mode 100644 index 0000000000..35f5ec54ad --- /dev/null +++ b/src/libpcap-1.10.5/pcap-septel.c @@ -0,0 +1,328 @@ +/* + * pcap-septel.c: Packet capture interface for Intel/Septel card. + * + * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY + * (+961 3 485243) + */ + +#include + +#include + +#include +#include +#include + +#include "pcap-int.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pcap-septel.h" + +static int septel_stats(pcap_t *p, struct pcap_stat *ps); +static int septel_getnonblock(pcap_t *p); +static int septel_setnonblock(pcap_t *p, int nonblock); + +/* + * Private data for capturing on Septel devices. + */ +struct pcap_septel { + struct pcap_stat stat; +} + +/* + * Read at most max_packets from the capture queue and call the callback + * for each of them. Returns the number of packets handled, -1 if an + * error occurred, or -2 if we were told to break out of the loop. + */ +static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { + + struct pcap_septel *ps = p->priv; + HDR *h; + MSG *m; + int processed = 0 ; + int t = 0 ; + + /* identifier for the message queue of the module(upe) from which we are capturing + * packets.These IDs are defined in system.txt . By default it is set to 0x2d + * so change it to 0xdd for technical reason and therefore the module id for upe becomes: + * LOCAL 0xdd * upe - Example user part task */ + unsigned int id = 0xdd; + + /* process the packets */ + do { + + unsigned short packet_len = 0; + int caplen = 0; + int counter = 0; + struct pcap_pkthdr pcap_header; + u_char *dp ; + + /* + * Has "pcap_breakloop()" been called? + */ +loop: + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that + * it has, and return -2 to indicate that + * we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + /*repeat until a packet is read + *a NULL message means : + * when no packet is in queue or all packets in queue already read */ + do { + /* receive packet in non-blocking mode + * GCT_grab is defined in the septel library software */ + h = GCT_grab(id); + + m = (MSG*)h; + /* a counter is added here to avoid an infinite loop + * that will cause our capture program GUI to freeze while waiting + * for a packet*/ + counter++ ; + + } + while ((m == NULL)&& (counter< 100)) ; + + if (m != NULL) { + + t = h->type ; + + /* catch only messages with type = 0xcf00 or 0x8f01 corresponding to ss7 messages*/ + /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND + * for 0x8f01? */ + if ((t != 0xcf00) && (t != 0x8f01)) { + relm(h); + goto loop ; + } + + /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */ + dp = get_param(m);/* get pointer to MSG parameter area (m->param) */ + packet_len = m->len; + caplen = p->snapshot ; + + + if (caplen > packet_len) { + + caplen = packet_len; + } + /* Run the packet filter if there is one. */ + if ((p->fcode.bf_insns == NULL) || pcapint_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { + + + /* get a time stamp , consisting of : + * + * pcap_header.ts.tv_sec: + * ---------------------- + * a UNIX format time-in-seconds when he packet was captured, + * i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT) + * + * pcap_header.ts.tv_usec : + * ------------------------ + * the number of microseconds since that second + * when the packet was captured + */ + + (void)gettimeofday(&pcap_header.ts, NULL); + + /* Fill in our own header data */ + pcap_header.caplen = caplen; + pcap_header.len = packet_len; + + /* Count the packet. */ + ps->stat.ps_recv++; + + /* Call the user supplied callback function */ + callback(user, &pcap_header, dp); + + processed++ ; + + } + /* after being processed the packet must be + *released in order to receive another one */ + relm(h); + }else + processed++; + + } + while (processed < cnt) ; + + return processed ; +} + + +static int +septel_inject(pcap_t *handle, const void *buf _U_, int size _U_) +{ + pcapint_strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Activate a handle for a live capture from the given Septel device. Always pass a NULL device + * The promisc flag is ignored because Septel cards have built-in tracing. + * The timeout is also ignored as it is not supported in hardware. + * + * See also pcap(3). + */ +static pcap_t *septel_activate(pcap_t* handle) { + /* Initialize some components of the pcap structure. */ + handle->linktype = DLT_MTP2; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + handle->bufsize = 0; + + /* + * "select()" and "poll()" don't work on Septel queues + */ + handle->selectable_fd = -1; + + handle->read_op = septel_read; + handle->inject_op = septel_inject; + handle->setfilter_op = pcapint_install_bpf_program; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = septel_getnonblock; + handle->setnonblock_op = septel_setnonblock; + handle->stats_op = septel_stats; + + return 0; +} + +pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) { + const char *cp; + pcap_t *p; + + /* Does this look like the Septel device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + if (strcmp(cp, "septel") != 0) { + /* Nope, it's not "septel" */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_septel); + if (p == NULL) + return NULL; + + p->activate_op = septel_activate; + /* + * Set these up front, so that, even if our client tries + * to set non-blocking mode before we're activated, or + * query the state of non-blocking mode, they get an error, + * rather than having the non-blocking mode option set + * for use later. + */ + p->getnonblock_op = septel_getnonblock; + p->setnonblock_op = septel_setnonblock; + return p; +} + +static int septel_stats(pcap_t *p, struct pcap_stat *ps) { + struct pcap_septel *handlep = p->priv; + /*handlep->stat.ps_recv = 0;*/ + /*handlep->stat.ps_drop = 0;*/ + + *ps = handlep->stat; + + return 0; +} + + +int +septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf) +{ + /* + * XXX - do the notions of "up", "running", or "connected" apply here? + */ + if (pcapint_add_dev(devlistp,"septel",0,"Intel/Septel device",errbuf) == NULL) + return -1; + return 0; +} + + +/* + * We don't support non-blocking mode. I'm not sure what we'd + * do to support it and, given that we don't support select()/ + * poll()/epoll_wait()/kevent() etc., it probably doesn't + * matter. + */ +static int +septel_getnonblock(pcap_t *p) +{ + fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); + return (-1); +} + +static int +septel_setnonblock(pcap_t *p, int nonblock _U_) +{ + fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); + return (-1); +} + +#ifdef SEPTEL_ONLY +/* + * This libpcap build supports only Septel cards, not regular network + * interfaces. + */ + +/* + * There are no regular interfaces, just Septel interfaces. + */ +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (0); +} + +/* + * Attempts to open a regular interface fail. + */ +pcap_t * +pcapint_create_interface(const char *device, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "This version of libpcap only supports Septel cards"); + return (NULL); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING " (Septel-only)"); +} +#endif diff --git a/src/libpcap-1.10.5/pcap-septel.h b/src/libpcap-1.10.5/pcap-septel.h new file mode 100644 index 0000000000..0e648b20c6 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-septel.h @@ -0,0 +1,13 @@ +/* + * pcap-septel.c: Packet capture interface for Intel Septel card + * + * The functionality of this code attempts to mimic that of pcap-linux as much + * as possible. This code is only needed when compiling in the Intel/Septel + * card code at the same time as another type of device. + * + * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY + * (+961 3 485343); + */ + +pcap_t *septel_create(const char *device, char *ebuf, int *is_ours); +int septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-sita.c b/src/libpcap-1.10.5/pcap-sita.c new file mode 100644 index 0000000000..8cee5740d3 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-sita.c @@ -0,0 +1,1080 @@ +/* + * pcap-sita.c: Packet capture interface additions for SITA ACN devices + * + * Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc + * + * License: BSD + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pcap-int.h" + +#include "pcap-sita.h" + + /* non-configurable manifests follow */ + +#define IOP_SNIFFER_PORT 49152 /* TCP port on the IOP used for 'distributed pcap' usage */ +#define MAX_LINE_SIZE 255 /* max size of a buffer/line in /etc/hosts we allow */ +#define MAX_CHASSIS 8 /* number of chassis in an ACN site */ +#define MAX_GEOSLOT 8 /* max number of access units in an ACN site */ + +#define FIND 0 +#define LIVE 1 + +typedef struct iface { + struct iface *next; /* a pointer to the next interface */ + char *name; /* this interface's name */ + char *IOPname; /* this interface's name on an IOP */ + uint32_t iftype; /* the type of interface (DLT values) */ +} iface_t; + +typedef struct unit { + char *ip; /* this unit's IP address (as extracted from /etc/hosts) */ + int fd; /* the connection to this unit (if it exists) */ + int find_fd; /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */ + int first_time; /* 0 = just opened via acn_open_live(), ie. the first time, NZ = nth time */ + struct sockaddr_in *serv_addr; /* the address control block for comms to this unit */ + int chassis; + int geoslot; + iface_t *iface; /* a pointer to a linked list of interface structures */ + char *imsg; /* a pointer to an inbound message */ + int len; /* the current size of the inbound message */ +} unit_t; + +/* + * Private data. + * Currently contains nothing. + */ +struct pcap_sita { + int dummy; +}; + +static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */ +static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */ +static int max_fs; + +pcap_if_t *acn_if_list; /* pcap's list of available interfaces */ + +static void dump_interface_list(void) { + pcap_if_t *iff; + pcap_addr_t *addr; + int longest_name_len = 0; + char *n, *d, *f; + int if_number = 0; + + iff = acn_if_list; + while (iff) { + if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name); + iff = iff->next; + } + iff = acn_if_list; + printf("Interface List:\n"); + while (iff) { + n = (iff->name) ? iff->name : ""; + d = (iff->description) ? iff->description : ""; + f = (iff->flags == PCAP_IF_LOOPBACK) ? "L" : ""; + printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d); + addr = iff->addresses; + while (addr) { + printf("%*s ", (5 + longest_name_len), ""); /* add some indentation */ + printf("%15s ", (addr->addr) ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr) : ""); + printf("%15s ", (addr->netmask) ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr) : ""); + printf("%15s ", (addr->broadaddr) ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr) : ""); + printf("%15s ", (addr->dstaddr) ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr) : ""); + printf("\n"); + addr = addr->next; + } + iff = iff->next; + } +} + +static void dump(unsigned char *ptr, int i, int indent) { + fprintf(stderr, "%*s", indent, " "); + for (; i > 0; i--) { + fprintf(stderr, "%2.2x ", *ptr++); + } + fprintf(stderr, "\n"); +} + +static void dump_interface_list_p(void) { + pcap_if_t *iff; + pcap_addr_t *addr; + int if_number = 0; + + iff = acn_if_list; + printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff); + while (iff) { + printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next); + dump((unsigned char *)iff, sizeof(pcap_if_t), 5); + addr = iff->addresses; + while (addr) { + printf(" %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next); + dump((unsigned char *)addr, sizeof(pcap_addr_t), 10); + addr = addr->next; + } + iff = iff->next; + } +} + +static void dump_unit_table(void) { + int chassis, geoslot; + iface_t *p; + + printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address"); + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) + printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip); + p = units[chassis][geoslot].iface; + while (p) { + char *n = (p->name) ? p->name : ""; + char *i = (p->IOPname) ? p->IOPname : ""; + p = p->next; + printf(" %12s -> %12s\n", i, n); + } + } + } +} + +static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) { + int c, s; + + for (c = 0; c <= MAX_CHASSIS; c++) { + for (s = 0; s <= MAX_GEOSLOT; s++) { + if (units[c][s].fd == fd || units[c][s].find_fd == fd) { + if (chassis) *chassis = c; + if (geoslot) *geoslot = s; + if (unit_ptr) *unit_ptr = &units[c][s]; + return 1; + } + } + } + return 0; +} + +static int read_client_nbytes(int fd, int count, unsigned char *buf) { + unit_t *u; + int chassis, geoslot; + int len; + + find_unit_by_fd(fd, &chassis, &geoslot, &u); + while (count) { + if ((len = recv(fd, buf, count, 0)) <= 0) return -1; /* read in whatever data was sent to us */ + count -= len; + buf += len; + } /* till we have everything we are looking for */ + return 0; +} + +static void empty_unit_iface(unit_t *u) { + iface_t *p, *cur; + + cur = u->iface; + while (cur) { /* loop over all the interface entries */ + if (cur->name) free(cur->name); /* throwing away the contents if they exist */ + if (cur->IOPname) free(cur->IOPname); + p = cur->next; + free(cur); /* then throw away the structure itself */ + cur = p; + } + u->iface = 0; /* and finally remember that there are no remaining structure */ +} + +static void empty_unit(int chassis, int geoslot) { + unit_t *u = &units[chassis][geoslot]; + + empty_unit_iface(u); + if (u->imsg) { /* then if an inbound message buffer exists */ + void *bigger_buffer; + + bigger_buffer = (char *)realloc(u->imsg, 1); /* and re-allocate the old large buffer into a new small one */ + if (bigger_buffer == NULL) { /* oops, realloc call failed */ + fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno); + return; + } + u->imsg = bigger_buffer; + } +} + +static void empty_unit_table(void) { + int chassis, geoslot; + + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) { + free(units[chassis][geoslot].ip); /* get rid of the malloc'ed space that holds the IP address */ + units[chassis][geoslot].ip = 0; /* then set the pointer to NULL */ + } + empty_unit(chassis, geoslot); + } + } +} + +static char *find_nth_interface_name(int n) { + int chassis, geoslot; + iface_t *p; + char *last_name = 0; + + if (n < 0) n = 0; /* ensure we are working with a valid number */ + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + if (units[chassis][geoslot].ip != NULL) { + p = units[chassis][geoslot].iface; + while (p) { /* and all interfaces... */ + if (p->IOPname) last_name = p->name; /* remembering the last name found */ + if (n-- == 0) return last_name; /* and if we hit the instance requested */ + p = p->next; + } + } + } + } + /* if we couldn't fine the selected entry */ + if (last_name) return last_name; /* ... but we did have at least one entry... return the last entry found */ + return ""; /* ... but if there wasn't any entry... return an empty string instead */ +} + +int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */ + FILE *fp; + char buf[MAX_LINE_SIZE]; + char *ptr, *ptr2; + int pos; + int chassis, geoslot; + unit_t *u; + + empty_unit_table(); + if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */ + return -1; + } + while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */ + + pos = strcspn(buf, "#\n\r"); /* find the first comment character or EOL */ + *(buf + pos) = '\0'; /* and clobber it and anything that follows it */ + + pos = strspn(buf, " \t"); /* then find the first non-white space */ + if (pos == strlen(buf)) /* if there is nothing but white space on the line */ + continue; /* ignore that empty line */ + ptr = buf + pos; /* and skip over any of that leading whitespace */ + + if ((ptr2 = strstr(ptr, "_I_")) == NULL) /* skip any lines that don't have names that look like they belong to IOPs */ + continue; + if (*(ptr2 + 4) != '_') /* and skip other lines that have names that don't look like ACN components */ + continue; + *(ptr + strcspn(ptr, " \t")) = '\0'; /* null terminate the IP address so its a standalone string */ + + chassis = *(ptr2 + 3) - '0'; /* extract the chassis number */ + geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */ + if (chassis < 1 || chassis > MAX_CHASSIS || + geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */ + continue; /* and ignore the entry */ + } + ptr2 = strdup(ptr); /* copy the IP address into our malloc'ed memory */ + if (ptr2 == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + continue; + } + u = &units[chassis][geoslot]; + u->ip = ptr2; /* and remember the whole shebang */ + u->chassis = chassis; + u->geoslot = geoslot; + } + fclose(fp); + if (*errbuf) return -1; + else return 0; +} + +static int open_with_IOP(unit_t *u, int flag) { + int sockfd; + char *ip; + + if (u->serv_addr == NULL) { + u->serv_addr = malloc(sizeof(struct sockaddr_in)); + + /* since we called malloc(), lets check to see if we actually got the memory */ + if (u->serv_addr == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno); + return 0; + } + + } + ip = u->ip; + /* bzero() is deprecated, replaced with memset() */ + memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in)); + u->serv_addr->sin_family = AF_INET; + u->serv_addr->sin_addr.s_addr = inet_addr(ip); + u->serv_addr->sin_port = htons(IOP_SNIFFER_PORT); + + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip); + return 0; + } + if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) { + fprintf(stderr, "pcap can't connect to IOP at %s\n", ip); + return 0; + } + if (flag == LIVE) u->fd = sockfd; + else u->find_fd = sockfd; + u->first_time = 0; + return sockfd; /* return the non-zero file descriptor as a 'success' indicator */ +} + +static void close_with_IOP(int chassis, int geoslot, int flag) { + int *id; + + if (flag == LIVE) id = &units[chassis][geoslot].fd; + else id = &units[chassis][geoslot].find_fd; + + if (*id) { /* this was the last time, so... if we are connected... */ + close(*id); /* disconnect us */ + *id = 0; /* and forget that the descriptor exists because we are not open */ + } +} + +static void pcap_cleanup_acn(pcap_t *handle) { + int chassis, geoslot; + unit_t *u; + + if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0) + return; + close_with_IOP(chassis, geoslot, LIVE); + if (u) + u->first_time = 0; + pcapint_cleanup_live_common(handle); +} + +static void send_to_fd(int fd, int len, unsigned char *str) { + int nwritten; + int chassis, geoslot; + + while (len > 0) { + if ((nwritten = write(fd, str, len)) <= 0) { + find_unit_by_fd(fd, &chassis, &geoslot, NULL); + if (units[chassis][geoslot].fd == fd) close_with_IOP(chassis, geoslot, LIVE); + else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND); + empty_unit(chassis, geoslot); + return; + } + len -= nwritten; + str += nwritten; + } +} + +static void acn_freealldevs(void) { + + pcap_if_t *iff, *next_iff; + pcap_addr_t *addr, *next_addr; + + for (iff = acn_if_list; iff != NULL; iff = next_iff) { + next_iff = iff->next; + for (addr = iff->addresses; addr != NULL; addr = next_addr) { + next_addr = addr->next; + if (addr->addr) free(addr->addr); + if (addr->netmask) free(addr->netmask); + if (addr->broadaddr) free(addr->broadaddr); + if (addr->dstaddr) free(addr->dstaddr); + free(addr); + } + if (iff->name) free(iff->name); + if (iff->description) free(iff->description); + free(iff); + } +} + +static void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) { + + snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot); +} + +static void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) { + int portnum; + + portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1; + snprintf(buf, bufsize, "%s_%d", proto, portnum); +} + +static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) { + iface_t *iface_ptr, *iface; + char buf[32]; + char *proto; + char *port; + int IOPportnum = 0; + + iface = malloc(sizeof(iface_t)); /* get memory for a structure */ + if (iface == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno); + return NULL; + } + memset((char *)iface, 0, sizeof(iface_t)); /* bzero is deprecated(), replaced with memset() */ + + iface->iftype = iftype; /* remember the interface type of this interface */ + + iface->IOPname = strdup(IOPname); /* copy it and stick it into the structure */ + if (iface->IOPname == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno); + return NULL; + } + + if (strncmp(IOPname, "lo", 2) == 0) { + IOPportnum = atoi(&IOPname[2]); + switch (iftype) { + case DLT_EN10MB: + nonUnified_IOP_port_name(buf, sizeof buf, "lo", u); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else if (strncmp(IOPname, "eth", 3) == 0) { + IOPportnum = atoi(&IOPname[3]); + switch (iftype) { + case DLT_EN10MB: + nonUnified_IOP_port_name(buf, sizeof buf, "eth", u); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else if (strncmp(IOPname, "wan", 3) == 0) { + IOPportnum = atoi(&IOPname[3]); + switch (iftype) { + case DLT_SITA: + unified_IOP_port_name(buf, sizeof buf, "wan", u, IOPportnum); + break; + default: + unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum); + break; + } + } else { + fprintf(stderr, "Error... invalid IOP name %s\n", IOPname); + return NULL; + } + + iface->name = strdup(buf); /* make a copy and stick it into the structure */ + if (iface->name == NULL) { /* oops, we didn't get the memory requested */ + fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno); + return NULL; + } + + if (u->iface == 0) { /* if this is the first name */ + u->iface = iface; /* stick this entry at the head of the list */ + } else { + iface_ptr = u->iface; + while (iface_ptr->next) { /* otherwise scan the list */ + iface_ptr = iface_ptr->next; /* till we're at the last entry */ + } + iface_ptr->next = iface; /* then tack this entry on the end of the list */ + } + return iface->name; +} + +static int if_sort(char *s1, char *s2) { + char *s1_p2, *s2_p2; + char str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE]; + int s1_p1_len, s2_p1_len; + int retval; + + if ((s1_p2 = strchr(s1, '_'))) { /* if an underscore is found... */ + s1_p1_len = s1_p2 - s1; /* the prefix length is the difference in pointers */ + s1_p2++; /* the suffix actually starts _after_ the underscore */ + } else { /* otherwise... */ + s1_p1_len = strlen(s1); /* the prefix length is the length of the string itself */ + s1_p2 = 0; /* and there is no suffix */ + } + if ((s2_p2 = strchr(s2, '_'))) { /* now do the same for the second string */ + s2_p1_len = s2_p2 - s2; + s2_p2++; + } else { + s2_p1_len = strlen(s2); + s2_p2 = 0; + } + strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1)); *(str1 + s1_p1_len) = 0; + strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2)); *(str2 + s2_p1_len) = 0; + retval = strcmp(str1, str2); + if (retval != 0) return retval; /* if they are not identical, then we can quit now and return the indication */ + return strcmp(s1_p2, s2_p2); /* otherwise we return the result of comparing the 2nd half of the string */ +} + +static void sort_if_table(void) { + pcap_if_t *p1, *p2, *prev, *temp; + int has_swapped; + + if (!acn_if_list) return; /* nothing to do if the list is empty */ + + while (1) { + p1 = acn_if_list; /* start at the head of the list */ + prev = 0; + has_swapped = 0; + while ((p2 = p1->next)) { + if (if_sort(p1->name, p2->name) > 0) { + if (prev) { /* we are swapping things that are _not_ at the head of the list */ + temp = p2->next; + prev->next = p2; + p2->next = p1; + p1->next = temp; + } else { /* special treatment if we are swapping with the head of the list */ + temp = p2->next; + acn_if_list= p2; + p2->next = p1; + p1->next = temp; + } + p1 = p2; + prev = p1; + has_swapped = 1; + } + prev = p1; + p1 = p1->next; + } + if (has_swapped == 0) + return; + } + return; +} + +static int process_client_data (char *errbuf) { /* returns: -1 = error, 0 = OK */ + int chassis, geoslot; + unit_t *u; + pcap_if_t *iff, *prev_iff; + pcap_addr_t *addr, *prev_addr; + char *ptr; + int address_count; + struct sockaddr_in *s; + char *newname; + bpf_u_int32 interfaceType; + unsigned char flags; + void *bigger_buffer; + + prev_iff = 0; + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { /* now loop over all the devices */ + u = &units[chassis][geoslot]; + empty_unit_iface(u); + ptr = u->imsg; /* point to the start of the msg for this IOP */ + while (ptr < (u->imsg + u->len)) { + if ((iff = malloc(sizeof(pcap_if_t))) == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, "malloc"); + return -1; + } + memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */ + if (acn_if_list == 0) acn_if_list = iff; /* remember the head of the list */ + if (prev_iff) prev_iff->next = iff; /* insert a forward link */ + + if (*ptr) { /* if there is a count for the name */ + if ((iff->name = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + return -1; + } + memcpy(iff->name, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ + *(iff->name + *ptr) = 0; /* and null terminate the string */ + ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ + } + ptr++; + + if (*ptr) { /* if there is a count for the description */ + if ((iff->description = malloc(*ptr + 1)) == NULL) { /* get that amount of space */ + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + return -1; + } + memcpy(iff->description, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */ + *(iff->description + *ptr) = 0; /* and null terminate the string */ + ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */ + } + ptr++; + + interfaceType = ntohl(*(bpf_u_int32 *)ptr); + ptr += 4; /* skip over the interface type */ + + flags = *ptr++; + if (flags) iff->flags = PCAP_IF_LOOPBACK; /* if this is a loopback style interface, lets mark it as such */ + + address_count = *ptr++; + + prev_addr = 0; + while (address_count--) { + if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + return -1; + } + memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */ + if (iff->addresses == 0) iff->addresses = addr; + if (prev_addr) prev_addr->next = addr; /* insert a forward link */ + if (*ptr) { /* if there is a count for the address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { /* get that amount of space */ + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */ + addr->addr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32 *)(ptr + 1); /* copy the address in */ + ptr += *ptr; /* now move the pointer forwards according to the specified length of the address */ + } + ptr++; /* then forwards one more for the 'length of the address' field */ + if (*ptr) { /* process any netmask */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->netmask = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + if (*ptr) { /* process any broadcast address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->broadaddr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + if (*ptr) { /* process any destination address */ + if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, + errno, "malloc"); + return -1; + } + /* bzero() is deprecated, replaced with memset() */ + memset((char *)s, 0, sizeof(struct sockaddr_in)); + + addr->dstaddr = (struct sockaddr *)s; + s->sin_family = AF_INET; + s->sin_addr.s_addr = *(bpf_u_int32*)(ptr + 1); + ptr += *ptr; + } + ptr++; + prev_addr = addr; + } + prev_iff = iff; + + newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */ + bigger_buffer = realloc(iff->name, strlen(newname) + 1); + if (bigger_buffer == NULL) { /* we now re-write the name stored in the interface list */ + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, "realloc"); + return -1; + } + iff->name = bigger_buffer; + strcpy(iff->name, newname); /* to this new name */ + } + } + } + return 0; +} + +static int read_client_data (int fd) { + unsigned char buf[256]; + int chassis, geoslot; + unit_t *u; + int len; + + find_unit_by_fd(fd, &chassis, &geoslot, &u); + + if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0; /* read in whatever data was sent to us */ + + if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL) /* extend the buffer for the new data */ + return 0; + memcpy((u->imsg + u->len), buf, len); /* append the new data */ + u->len += len; + return 1; +} + +static void wait_for_all_answers(void) { + int retval; + struct timeval tv; + int fd; + int chassis, geoslot; + + tv.tv_sec = 2; + tv.tv_usec = 0; + + while (1) { + int flag = 0; + fd_set working_set; + + for (fd = 0; fd <= max_fs; fd++) { /* scan the list of descriptors we may be listening to */ + if (FD_ISSET(fd, &readfds)) flag = 1; /* and see if there are any still set */ + } + if (flag == 0) return; /* we are done, when they are all gone */ + + memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */ + retval = select(max_fs + 1, &working_set, NULL, NULL, &tv); + if (retval == -1) { /* an error occurred !!!!! */ + return; + } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */ + printf("timeout\n"); + return; + } else { + for (fd = 0; fd <= max_fs; fd++) { /* scan the list of things to do, and do them */ + if (FD_ISSET(fd, &working_set)) { + if (read_client_data(fd) == 0) { /* if the socket has closed */ + FD_CLR(fd, &readfds); /* and descriptors we listen to for errors */ + find_unit_by_fd(fd, &chassis, &geoslot, NULL); + close_with_IOP(chassis, geoslot, FIND); /* and close out connection to him */ + } + } + } + } + } +} + +static char *get_error_response(int fd, char *errbuf) { /* return a pointer on error, NULL on no error */ + char byte; + int len = 0; + + while (1) { + recv(fd, &byte, 1, 0); /* read another byte in */ + if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) { /* and if there is still room in the buffer */ + *errbuf++ = byte; /* stick it in */ + *errbuf = '\0'; /* ensure the string is null terminated just in case we might exceed the buffer's size */ + } + if (byte == '\0') { + if (len > 1) { return errbuf; } + else { return NULL; } + } + } +} + +int acn_findalldevs(char *errbuf) { /* returns: -1 = error, 0 = OK */ + int chassis, geoslot; + unit_t *u; + + FD_ZERO(&readfds); + max_fs = 0; + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + u = &units[chassis][geoslot]; + if (u->ip && (open_with_IOP(u, FIND))) { /* connect to the remote IOP */ + send_to_fd(u->find_fd, 1, (unsigned char *)"\0"); + if (get_error_response(u->find_fd, errbuf)) + close_with_IOP(chassis, geoslot, FIND); + else { + if (u->find_fd > max_fs) + max_fs = u->find_fd; /* remember the highest number currently in use */ + FD_SET(u->find_fd, &readfds); /* we are going to want to read this guy's response to */ + u->len = 0; + send_to_fd(u->find_fd, 1, (unsigned char *)"Q"); /* this interface query request */ + } + } + } + } + wait_for_all_answers(); + if (process_client_data(errbuf)) + return -1; + sort_if_table(); + return 0; +} + +static int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) { + unsigned char buf[12]; + + send_to_fd(handle->fd, 1, (unsigned char *)"S"); /* send the get_stats command to the IOP */ + + if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1; /* try reading the required bytes */ + + ps->ps_recv = ntohl(*(uint32_t *)&buf[0]); /* break the buffer into its three 32 bit components */ + ps->ps_drop = ntohl(*(uint32_t *)&buf[4]); + ps->ps_ifdrop = ntohl(*(uint32_t *)&buf[8]); + + return 0; +} + +static int acn_open_live(const char *name, char *errbuf, int *linktype) { /* returns 0 on error, else returns the file descriptor */ + int chassis, geoslot; + unit_t *u; + iface_t *p; + pcap_if_list_t devlist; + + pcapint_platform_finddevs(&devlist, errbuf); + for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */ + for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { + u = &units[chassis][geoslot]; + if (u->ip != NULL) { + p = u->iface; + while (p) { /* and all interfaces... */ + if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) { /* and if we found the interface we want... */ + *linktype = p->iftype; + open_with_IOP(u, LIVE); /* start a connection with that IOP */ + send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname); /* send the IOP's interface name, and a terminating null */ + if (get_error_response(u->fd, errbuf)) { + return -1; + } + return u->fd; /* and return that open descriptor */ + } + p = p->next; + } + } + } + } + return -1; /* if the interface wasn't found, return an error */ +} + +static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) { + unsigned char buf[8]; + unit_t *u; + + //printf("acn_start_monitor()\n"); // fulko + find_unit_by_fd(fd, NULL, NULL, &u); + if (u->first_time == 0) { + buf[0] = 'M'; + *(uint32_t *)&buf[1] = htonl(snaplen); + buf[5] = timeout; + buf[6] = promiscuous; + buf[7] = direction; + //printf("acn_start_monitor() first time\n"); // fulko + send_to_fd(fd, 8, buf); /* send the start monitor command with its parameters to the IOP */ + u->first_time = 1; + } + //printf("acn_start_monitor() complete\n"); // fulko +} + +static int pcap_inject_acn(pcap_t *p, const void *buf _U_, int size _U_) { + pcapint_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters", + PCAP_ERRBUF_SIZE); + return (-1); +} + +static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) { + int fd = handle->fd; + int count; + struct bpf_insn *p; + uint16_t shortInt; + uint32_t longInt; + + send_to_fd(fd, 1, (unsigned char *)"F"); /* BPF filter follows command */ + count = bpf->bf_len; + longInt = htonl(count); + send_to_fd(fd, 4, (unsigned char *)&longInt); /* send the instruction sequence count */ + p = bpf->bf_insns; + while (count--) { /* followed by the list of instructions */ + shortInt = htons(p->code); + longInt = htonl(p->k); + send_to_fd(fd, 2, (unsigned char *)&shortInt); + send_to_fd(fd, 1, (unsigned char *)&p->jt); + send_to_fd(fd, 1, (unsigned char *)&p->jf); + send_to_fd(fd, 4, (unsigned char *)&longInt); + p++; + } + if (get_error_response(fd, NULL)) + return -1; + return 0; +} + +static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) { + struct timeval tv; + int retval, fd; + fd_set r_fds; + fd_set w_fds; + u_char *bp; + int len = 0; + int offset = 0; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + fd = handle->fd; + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + memcpy(&w_fds, &r_fds, sizeof(r_fds)); + bp = handle->bp; + while (count) { + retval = select(fd + 1, &w_fds, NULL, NULL, &tv); + if (retval == -1) { /* an error occurred !!!!! */ +// fprintf(stderr, "error during packet data read\n"); + return -1; /* but we need to return a good indication to prevent unnecessary popups */ + } else if (retval == 0) { /* timeout occurred, so process what we've got sofar and return */ +// fprintf(stderr, "timeout during packet data read\n"); + return -1; + } else { + if ((len = recv(fd, (bp + offset), count, 0)) <= 0) { +// fprintf(stderr, "premature exit during packet data rx\n"); + return -1; + } + count -= len; + offset += len; + } + } + return 0; +} + +static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { + #define HEADER_SIZE (4 * 4) + unsigned char packet_header[HEADER_SIZE]; + struct pcap_pkthdr pcap_header; + + //printf("pcap_read_acn()\n"); // fulko + acn_start_monitor(handle->fd, handle->snapshot, handle->opt.timeout, handle->opt.promisc, handle->direction); /* maybe tell him to start monitoring */ + //printf("pcap_read_acn() after start monitor\n"); // fulko + + handle->bp = packet_header; + if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0; /* try to read a packet header in so we can get the sizeof the packet data */ + + pcap_header.ts.tv_sec = ntohl(*(uint32_t *)&packet_header[0]); /* tv_sec */ + pcap_header.ts.tv_usec = ntohl(*(uint32_t *)&packet_header[4]); /* tv_usec */ + pcap_header.caplen = ntohl(*(uint32_t *)&packet_header[8]); /* caplen */ + pcap_header.len = ntohl(*(uint32_t *)&packet_header[12]); /* len */ + + handle->bp = (u_char *)handle->buffer + handle->offset; /* start off the receive pointer at the right spot */ + if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0; /* then try to read in the rest of the data */ + + callback(user, &pcap_header, handle->bp); /* call the user supplied callback function */ + return 1; +} + +static int pcap_activate_sita(pcap_t *handle) { + int fd; + + if (handle->opt.rfmon) { + /* + * No monitor mode on SITA devices (they're not Wi-Fi + * devices). + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* Initialize some components of the pcap structure. */ + + handle->inject_op = pcap_inject_acn; + handle->setfilter_op = pcap_setfilter_acn; + handle->setdirection_op = NULL; /* Not implemented */ + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + handle->cleanup_op = pcap_cleanup_acn; + handle->read_op = pcap_read_acn; + handle->stats_op = pcap_stats_acn; + + fd = acn_open_live(handle->opt.device, handle->errbuf, + &handle->linktype); + if (fd == -1) + return PCAP_ERROR; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + handle->fd = fd; + handle->bufsize = handle->snapshot; + + /* Allocate the buffer */ + + handle->buffer = malloc(handle->bufsize + handle->offset); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + pcap_cleanup_acn(handle); + return PCAP_ERROR; + } + + /* + * "handle->fd" is a socket, so "select()" and "poll()" + * should work on it. + */ + handle->selectable_fd = handle->fd; + + return 0; +} + +pcap_t *pcapint_create_interface(const char *device _U_, char *ebuf) { + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_sita); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_sita; + return (p); +} + +int pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { + + //printf("pcap_findalldevs()\n"); // fulko + + *alldevsp = 0; /* initialize the returned variables before we do anything */ + strcpy(errbuf, ""); + if (acn_parse_hosts_file(errbuf)) /* scan the hosts file for potential IOPs */ + { + //printf("pcap_findalldevs() returning BAD after parse_hosts\n"); // fulko + return -1; + } + //printf("pcap_findalldevs() got hostlist now finding devs\n"); // fulko + if (acn_findalldevs(errbuf)) /* then ask the IOPs for their monitorable devices */ + { + //printf("pcap_findalldevs() returning BAD after findalldevs\n"); // fulko + return -1; + } + devlistp->beginning = acn_if_list; + acn_if_list = 0; /* then forget our list head, because someone will call pcap_freealldevs() to empty the malloc'ed stuff */ + //printf("pcap_findalldevs() returning ZERO OK\n"); // fulko + return 0; +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return PCAP_VERSION_STRING " (SITA-only)"; +} diff --git a/src/libpcap-1.10.5/pcap-sita.h b/src/libpcap-1.10.5/pcap-sita.h new file mode 100644 index 0000000000..9c35c6ac1d --- /dev/null +++ b/src/libpcap-1.10.5/pcap-sita.h @@ -0,0 +1,8 @@ +/* + * pcap-sita.h: Packet capture interface for SITA WAN devices + * + * Authors: Fulko Hew (fulko.hew@sita.aero) (+1 905 6815570); + */ + +extern int acn_parse_hosts_file(char *errbuf); +extern int acn_findalldevs(char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-sita.html b/src/libpcap-1.10.5/pcap-sita.html new file mode 100644 index 0000000000..6afad09cec --- /dev/null +++ b/src/libpcap-1.10.5/pcap-sita.html @@ -0,0 +1,941 @@ + + + + + + + + +
+ A "Distributed Pcap" for
Remote Monitoring LANs & WANs

+ (Design Notes for the SITA ACN device)
+
+ Fulko Hew
SITA INC Canada, Inc.
Revised: October 2, 2007 +
+ + +

SUMMARY

+
    + Note: This document is part of the libpcap Git and was derived from 'pcap.3' (circa Aug/07). +

    + The ACN provides a customized/distributed version of this library that allows SMPs to + interact with the various IOPs within the site providing a standard mechanism + to capture LAN and WAN message traffic. +

    +

    + + + + + + + + + +
    SMPThe Supervisory Management Processor where Wireshark (or equivalent) + runs in conjunction with a libpcap front-end.
    IOPI/O Processors where the monitored ports exist in conjunction + with a custom device driver/libpcap back-end.
    +
    +

    + Each IOP will be capable of supporting multiple connections from an SMP + enabling monitoring of more than one interface at a time, each through + its own separate connection. The IOP is responsible to ensure and report + an error if any attempt is made to monitor the same interface more than once. +

    + There are three applications that will be supported by the ACN version of libpcap. + They each use a slightly different mode for looping/capturing and termination + as summarized in the following table: +

    +

    + + + + + + + + + + + + + + +
    Application Capture Termination
    wiresharkpcap_dispatch(all packets in one buffer of capture only)pcap_breakloop()
    tsharkpcap_dispatch(one buffer of capture only)Since a CTRL-C was used to terminate the application, pcap_breakloop() is never called.
    tcpdumppcap_loop(all packets in the next buffer, and loop forever)pcap_breakloop()
    +
    +

    + Note: In all cases, the termination of capturing is always (apparently) followed by + pcap_close(). Pcap_breakloop() is only used to stop/suspend looping/processing, + and upon close interpretation of the function definitions, it is possible to resume + capturing following a pcap_breakloop() without any re-initialization. +

    +

    ACN Limitations

    +
      +
    1. Monitoring of backup IOPs is not currently supported. +
    2. Ethernet interfaces cannot be monitored in promiscuous mode. +
    + +
+ +

ROUTINES

+
    + The following list of functions is the sub-set of Pcap functions that have been + altered/enhanced to support the ACN remote monitoring facility. The remainder of the Pcap + functions continue to perform their duties un-altered. Libpcap only supports this + mode of operation if it has been configured/compiled for SITA/ACN support. +

    +

      + pcap_findalldevs
      + pcap_freealldevs
      + pcap_open_live
      + pcap_close
      + pcap_setfilter
      + pcap_dispatch
      + pcap_loop
      + pcap_next
      + pcap_next_ex
      + pcap_stats
      +
    + + These subroutines have been modified for the ACN specific distributed and remote monitoring + ability perform the following basic functions. More detail is provided in the + "SMP/IOP Inter-Process Communication Protocol" section. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    pcap_open_live()Used to obtain a packet capture descriptor to look at packets on the network.
    + + + + + + +
    SMP -> IOP + The SMP will open a connection to the selected IOP on its 'sniffer' port + to ensure it is available. It sends a null terminated string identifying + the interface to be monitored. +
    IOP -> SMP + After any required processing is complete, the IOP will return a + null terminated string containing an error message if one occurred. + If no error occurred, a empty string is still returned. + Errors are: +
      +
    • "Interface (xxx) does not exist." +
    • "Interface (xxx) not configured." +
    • "Interface (xxx) already being monitored." +
    +
    pcap_findalldevs()It constructs a list of network devices that can be opened with pcap_open_live().
    + + + + + + + + + + + + + + + +
    SMP + It obtains a list of IOPs currently available (via /etc/hosts). +
    SMP -> IOP + The SMP will sequentially open a connection to each IOP on its 'sniffer' port to ensure + the IOP is available. + It sends a null terminated empty interface ID followed by the query request command. +
    IOP -> SMPThe IOP returns an error response and its list of devices. +
    SMP -> IOP + The SMP closes the TCP connection with each IOP. +
    SMP + The SMP adds the received information to its internal structure. +
    pcap_freealldevs()Used to free a list allocated by pcap_findalldevs().
    + + + +
    SMP + The SMP frees the structure it built as a result of the previous + invocation of pcap_findalldevs(). +
    pcap_dispatch()Used to collect and process packets.
    + + + + + + + + + + + + +
    SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
    IOP -> SMP + The IOP now sends a stream of captured data. +
    SMP + The SMP will read the reverse channel of the connection between the SMP and the + IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()' + until the select() call returns a 'no more data' indication. + It will the process (at most) the next 'cnt' packets and invoke the specified + callback function for each packet processed. +
    IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
    pcap_loop() + Is similar to pcap_dispatch() except it keeps reading packets until + the requested number of packets are processed or an error occurs. +
    + + + + + + + + + + + + +
    SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
    IOP -> SMP + The IOP now sends a stream of captured data. +
    SMP + The SMP continuously reads the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via 'p->read_op' + which is 'pcap_read_linux()' until 'cnt' packets have been received. + The specified callback function will be invoked for each packet received. +
    IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
    pcap_next() + It reads the next packet (by calling pcap_dispatch() with a count of 1) + and returns a pointer to the data in that packet. +
    + + + + + + + + + + + + +
    SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
    IOP -> SMP + The IOP now sends a stream of captured data. +
    SMP + The SMP reads only the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() + with a count of 1) and returns a pointer to that data by invoking an internal callback. +
    IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
    pcap_next_ex()Reads the next packet and returns a success/failure indication.
    + + + + + + + + + + + + +
    SMP -> IOP + On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(), + the SMP will pass down the monitor start command and various parameters the IOP should use. +
    IOP -> SMP + The IOP now sends a stream of captured data. +
    SMP + The SMP reads only the next packet from the reverse channel of the connection + between the SMP and the IOP that provides the captured data (via calling pcap_dispatch() + with a count of 1) and returns separate pointers to both the + packet header and packet data by invoking an internal callback. +
    IOP + The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP. +
    pcap_setfilter()Used to specify a filter program.
    + + + + + + +
    SMP -> IOP + The SMP sends a 'set filter' command followed by the BPF commands. +
    IOP -> SMP + The IOP returns a null terminated error string if it failed to accept the filter. + If no error occurred, then a NULL terminated empty string is returned instead. + Errors are: +
      +
    • "Invalid BPF." +
    • "Insufficient resources for BPF." +
    +
    pcap_stats()Fills in a pcap_stat struct with packet statistics.
    + + + + + + + + + +
    SMP -> IOP + The SMP sends a message to the IOP requesting its statistics. +
    IOP -> SMP + The IOP returns the statistics. +
    SMP + The SMP fills in the structure provided with the information retrieved from the IOP. +
    pcap_close()Closes the file and deallocates resources.
    + + + + + + +
    SMP -> IOP + The SMP closes the file descriptor, and if the descriptor is that of + the communication session with an IOP, it too is terminated. +
    IOP + If the IOP detects that its communication session with an SMP + has closed, it will terminate any monitoring in progress, + release any resources and close its end of the session. + It will not maintain persistence of any information or prior mode of operation. +
    +

+ +

+

SMP/IOP Inter-Process Communication Protocol

+ +
    +
  • Communications between an SMP and an IOP consists of a TCP session + between an ephemeral port on the SMP and the well known port of 49152 + (which is the first available port in the 'dynamic and/or private port' + range) on an IOP. +

  • Following a TCP open operation the IOP receives a null terminated + 'interface ID' string to determine the type of operation that follows: +

  • Every command received by an IOP implies a 'stop trace/stop forwarding' operation must + occur before executing the received command. +

  • A session is closed when the SMP closes the TCP session with the IOP. + Obviously monitoring and forwarding is also stopped at that time. + + Note: All multi-octet entities are sent in network neutral order. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    pcap_findalldevs()SMP -> IOPOpen socket (to each IOP), and sends: +

    + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID1A NULL to indicate an empty 'interface ID'.
    +

    IOP -> SMPSend its (possibly empty) NULL terminated error response string.
    SMP -> IOPSends the 'interface query request': +

    + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID1A 'Q' (indicating 'interface query request').
    +

    IOP -> SMPThe IOP returns a list of sequences of information as + defined by the return parameter of this function call (as shown in the following table). + Elements are specified by providing an unsigned byte preceding the actual data that contains length information. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Notes:Name/
    Purpose
    Size
    (in bytes)
    Description
     length1The number of octets in the name field that follows.
    Name1-255The name of the interface. The format of the name is an alphabetic string (indicating + the type of interface) followed by an optional numeric string (indicating the interface's + sequence number). + Sequence numbers (if needed) will begin at zero and progress monotonically upwards. + (i.e. 'eth0', 'lo', 'wan0', etc.) +

    + For an IOP, the alphabetic string will be one of: 'eth', 'wan', and 'lo' + for Ethernet, WAN ports and the IP loopback device respectively. + An IOP currently supports: 'eth0', 'eth1', 'lo', 'wan0' ... 'wan7'. +

    + Note: IOPs and ACNs will not currently support the concept of 'any' interface.

    length1The number of octets in the interface description field that follows.
    Interface Description0-255A description of the interface or it may be an empty string. (i.e. 'ALC')
    Interface Type4The type of interface as defined in the description for pcap_datalink() (in network neutral order).
    Loopback Flag11 = if the interface is a loopback interface, zero = otherwise.
    count1# of address entries that follow. + Each entry is a series of bytes in network neutral order. + See the parameter definition above for more details.
    Repeated 'count' number of times.length1The number of octets in the address field that follows.
    Address1-255The address of this interface (in network neutral order).
    length1The number of octets in the netmask field that follows.
    Network Mask0-255The network mask used on this interface (if applicable) (in network neutral order).
    length1The number of octets in the broadcast address field that follows.
    Broadcast Address0-255The broadcast address of this interface (if applicable) (in network neutral order).
    length1The number of octets in the destination address field that follows.
    Destination Address0-255The destination address of this interface (if applicable) (in network neutral order).
    +

    SMP -> IOPClose the socket.
    IOP -> SMPClose the socket.

    pcap_open_live()SMP -> IOPOpen socket, and sends: +

    + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    Interface ID'n''n' octets containing a NULL terminated interface name string.
    +

    IOP -> SMPSend its NULL terminated error response string.

    pcap_dispatch()
    pcap_loop()
    pcap_next()
    pcap_next_ex()
    SMP -> IOPOn the first invocation following a pcap_open_live() or pcap_breakloop() additional information is sent: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    command1'M' (indicating 'monitor start')
    snaplen4snaplen
    timeout1timeout value (in milliseconds)
    promiscuous1A flag indicating that the interface being monitored show operate + in promiscuous mode. [off(0) / on(NZ)]
    direction1A flag indicating the direction of traffic that should be captured [both(0) / in(1) / out(2)]
    +

    IOP -> SMPSends captured packets.

    pcap_setfilter()SMP -> IOPAt any time, the SMP can issue a set filter command which contains + an indicator, a count of the number of statements in the filter, + followed by the sequence of filter commands represented as a sequence + of C-style structures. +

    + + + + + + + + + + + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    command1'F' (indicating 'filter')
    count4The number of command in the Berkeley Packet Filter that follow.
    BPF program'n'8 bytes of each command (repeated 'n' times).
    + Each command consists of that C-style structure which contains: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    opcode2The command's opcode.
    'jt'1The 'jump if true' program counter offset.
    'jf'1The 'jump if false' program counter offset.
    'k'4The 'other' data field.
    +

    + Refer to the bpf(4) man page for more details. +

    +

    IOP -> SMPIn return the IOP will send its (possibly empty) NULL terminated error response string.

    pcap_stats()SMP -> IOPAt any time, the SMP can issue a 'retrieve statistics' command which contains:
    +

    + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    command1'S' (indicating 'request statistics')
    +

    IOP -> SMPIn return the IOP will send: +

    + + + + + + + + + + + + + + + + + + + + + +
    Name/
    Purpose
    Size
    (in bytes)
    Description
    ps_recv4The number of packets that passed the filter.
    ps_drop4The number of packets that were dropped because the input queue was full, + regardless of whether they passed the filter.
    ps_ifdrop4The number of packets dropped by the network interface + (regardless of whether they would have passed the input filter).
    +


    pcap_close()SMP -> IOPAt any time, the SMP can close the TCP session with the IOP.

    +

+ +

Interface ID Naming Convention

+
    + Each interface within an IOP will be referred to uniquely. Since an currently contains + 8 monitorable WAN ports and a monitorable Ethernet port, the naming convention is: +

    +

    + + + + + + + + + + + + +
    Interface # Type Name
    1 WAN wan0
    2 WAN wan1
    3 WAN wan2
    4 WAN wan3
    5 WAN wan4
    6 WAN wan5
    7 WAN wan6
    8 WAN wan7
    9 Ethernet eth0
    10 Ethernet eth1
    +
    +
+ +

Packet Trace Data Format

+
    + The format of the trace data that is sent to the SMP follows a portion of the libpcap file format + and is summarized here. This format specifies the generic requirements needed to + be able to decode packets, but does not cover ACN specifics such as custom MAC addressing + and WAN protocol support. +

    + + Although a libpcap file begins with a global header followed by zero or + more records for each captured packet, trace data sent to the SMP does NOT begin with a global header. + A trace sequence looks like this: +

    + + + + + + + + + + +
     [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data]  [Packet Header]  [Packet Data] ...
    + +

    Packet Header

    +
      + Each captured packet starts with a header that contains the following values + (in network neutral order): + + +
      + uint32 tv_sec;  /* timestamp seconds */
      + uint32 tv_usec; /* timestamp microseconds */
      + uint32 caplen;  /* number of octets in the following packet */
      + uint32 len;     /* original length of packet on the wire */
      +		
      +
      + + + + + + + + + + + + + + + + + +
      tv_secThe date and time when this packet was captured. + This value is in seconds since January 1, 1970 00:00:00 GMT; + this is also known as a UN*X time_t. You can use the ANSI C + time() function from time.h to get this value, + but you might use a more optimized way to get this timestamp value. +
      tv_usecThe microseconds when this packet was captured, as an offset to ts_sec. + Beware: this value must never reach 1 second (1,000,000), + in this case ts_sec must be increased instead!
      caplenThe number of bytes actually provided in the capture record. + This value should never become larger than len or the + snaplen value specified during the capture.
      lenThe length of the packet "on the wire" when it was captured. + If caplen and len differ, the actually + saved packet size was limited by the value of snaplen specified + during one of the capture directives such as pcap_dispatch().
      +
    + +

    Packet Data

    +
      + The actual packet data will immediately follow the packet header as a sequence of caplen octets. + Depending on the DLT encoding number assigned to the interface, the packet data will contain an additional + custom header used to convey WAN port related information. +
    + +

    ACN Custom Packet Header

    +
      + PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support + monitoring of its ports, however each of these facilities were focused on capturing + and displaying traffic from LAN interfaces. The SITA extensions to these facilities + are used to also provide the ability to capture, filter, and display information from + an ACN's WAN ports. +

      + Although each packet follows the standard libpcap format, since there are + two types of interfaces that can be monitored, the format of the data + packet varies slightly. +

      +

        +
      • For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format. +
      • For WAN devices, the packet contains a 5 byte header that precedes the actual captured data + described by the following table: +
      +

      +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      OctetNameMask/ValueDefinition
      0Control / Statusxxxxxxx0Transmitted by capture device(see 'Errors' octets)
      xxxxxxx1Received by capture device
      1xxxxxxxNo buffer was available during capture of previous packet.
      1Signalsxxxxxxx1 DSR asserted
      xxxxxx1x DTR asserted
      xxxxx1xx CTS asserted
      xxxx1xxx RTS asserted
      xxx1xxxx DCD asserted
      xx1xxxxx Undefined
      x1xxxxxx Undefined
      1xxxxxxx Undefined
      2Errors
      (octet 1)
        Tx Rx
      xxxxxxx1 Underrun Framing
      xxxxxx1x CTS Lost Parity
      xxxxx1xx UART Error Collision
      xxxx1xxx Re-Tx Limit Reached Long Frame
      xxx1xxxx Undefined Short Frame
      xx1xxxxx Undefined Undefined
      x1xxxxxx Undefined Undefined
      1xxxxxxx Undefined Undefined
      3Errors
      (octet 2)
        Tx Rx
      xxxxxxx1 Undefined Non-Octet Aligned
      xxxxxx1x Undefined Abort Received
      xxxxx1xx Undefined CD Lost
      xxxx1xxx Undefined Digital PLL Error
      xxx1xxxx Undefined Overrun
      xx1xxxxx Undefined Frame Length Violation
      x1xxxxxx Undefined CRC Error
      1xxxxxxx Undefined Break Received
      4Protocol +
      + + + + + + + + + + + + + +
      0x01 - LAPB (BOP)  
      0x02 - Ethernet 1
      0x03 - Async (Interrupt IO)  
      0x04 - Async (Block IO)  
      0x05 - IPARS  
      0x06 - UTS  
      0x07 - PPP (HDLC)  
      0x08 - SDLC  
      0x09 - Token Ring 1
      0x10 - I2C  
      0x11 - DPM Link  
      0x12 - Frame Relay (BOP)  
      +
      +

      + Note 1: + Ethernet and Token Ring frames will never be sent as DLT_SITA (with the 5 octet header), + but will be sent as their corresponding DLT types instead. +

      +
      +
    +

    +

+ diff --git a/src/libpcap-1.10.5/pcap-snf.c b/src/libpcap-1.10.5/pcap-snf.c new file mode 100644 index 0000000000..272f7df6c0 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-snf.c @@ -0,0 +1,615 @@ +#include + +#ifndef _WIN32 +#include +#endif /* !_WIN32 */ + +#include +#include +#include +#include /* for INT_MAX */ + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif /* !_WIN32 */ + +#include +#if SNF_VERSION_API >= 0x0003 +#define SNF_HAVE_INJECT_API +#endif + +#include "pcap-int.h" +#include "pcap-snf.h" + +/* + * Private data for capturing on SNF devices. + */ +struct pcap_snf { + snf_handle_t snf_handle; /* opaque device handle */ + snf_ring_t snf_ring; /* opaque device ring handle */ +#ifdef SNF_HAVE_INJECT_API + snf_inject_t snf_inj; /* inject handle, if inject is used */ +#endif + int snf_timeout; + int snf_boardnum; +}; + +static int +snf_set_datalink(pcap_t *p, int dlt) +{ + p->linktype = dlt; + return (0); +} + +static int +snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + struct snf_ring_stats stats; + struct pcap_snf *snfps = p->priv; + int rc; + + if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + rc, "snf_get_stats"); + return -1; + } + ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow; + ps->ps_drop = stats.ring_pkt_overflow; + ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad; + return 0; +} + +static void +snf_platform_cleanup(pcap_t *p) +{ + struct pcap_snf *ps = p->priv; + +#ifdef SNF_HAVE_INJECT_API + if (ps->snf_inj) + snf_inject_close(ps->snf_inj); +#endif + snf_ring_close(ps->snf_ring); + snf_close(ps->snf_handle); + pcapint_cleanup_live_common(p); +} + +static int +snf_getnonblock(pcap_t *p) +{ + struct pcap_snf *ps = p->priv; + + return (ps->snf_timeout == 0); +} + +static int +snf_setnonblock(pcap_t *p, int nonblock) +{ + struct pcap_snf *ps = p->priv; + + if (nonblock) + ps->snf_timeout = 0; + else { + if (p->opt.timeout <= 0) + ps->snf_timeout = -1; /* forever */ + else + ps->snf_timeout = p->opt.timeout; + } + return (0); +} + +#define _NSEC_PER_SEC 1000000000 + +static inline +struct timeval +snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) +{ + struct timeval tv; + long tv_nsec; + const static struct timeval zero_timeval; + + if (ts_nanosec == 0) + return zero_timeval; + + tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; + tv_nsec = (ts_nanosec % _NSEC_PER_SEC); + + /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ + if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) + tv.tv_usec = tv_nsec; + else + tv.tv_usec = tv_nsec / 1000; + + return tv; +} + +static int +snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snf *ps = p->priv; + struct pcap_pkthdr hdr; + int i, flags, err, caplen, n; + struct snf_recv_req req; + int nonblock, timeout; + + if (!p) + return -1; + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(cnt)) + cnt = INT_MAX; + + n = 0; + timeout = ps->snf_timeout; + while (n < cnt) { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + return (n); + } + } + + err = snf_ring_recv(ps->snf_ring, timeout, &req); + + if (err) { + if (err == EBUSY || err == EAGAIN) { + return (n); + } + else if (err == EINTR) { + timeout = 0; + continue; + } + else { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, err, "snf_read"); + return -1; + } + } + + caplen = req.length; + if (caplen > p->snapshot) + caplen = p->snapshot; + + if ((p->fcode.bf_insns == NULL) || + pcapint_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { + hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); + hdr.caplen = caplen; + hdr.len = req.length; + callback(user, &hdr, req.pkt_addr); + n++; + } + + /* After one successful packet is received, we won't block + * again for that timeout. */ + if (timeout != 0) + timeout = 0; + } + return (n); +} + +static int +snf_inject(pcap_t *p, const void *buf _U_, int size _U_) +{ +#ifdef SNF_HAVE_INJECT_API + struct pcap_snf *ps = p->priv; + int rc; + if (ps->snf_inj == NULL) { + rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); + if (rc) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + rc, "snf_inject_open"); + return (-1); + } + } + + rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); + if (!rc) { + return (size); + } + else { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + rc, "snf_inject_send"); + return (-1); + } +#else + pcapint_strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", + PCAP_ERRBUF_SIZE); + return (-1); +#endif +} + +static int +snf_activate(pcap_t* p) +{ + struct pcap_snf *ps = p->priv; + char *device = p->opt.device; + const char *nr = NULL; + int err; + int flags = -1, ring_id = -1; + + if (device == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); + return -1; + } + + /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. + * Since libpcap isn't thread-safe */ + if ((nr = getenv("SNF_FLAGS")) && *nr) + flags = strtol(nr, NULL, 0); + else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) + flags = SNF_F_PSHARED; + else + nr = NULL; + + + /* Allow pcap_set_buffer_size() to set dataring_size. + * Default is zero which allows setting from env SNF_DATARING_SIZE. + * pcap_set_buffer_size() is in bytes while snf_open() accepts values + * between 0 and 1048576 in Megabytes. Values in this range are + * mapped to 1MB. + */ + err = snf_open(ps->snf_boardnum, + 0, /* let SNF API parse SNF_NUM_RINGS, if set */ + NULL, /* default RSS, or use SNF_RSS_FLAGS env */ + (p->opt.buffer_size > 0 && p->opt.buffer_size < 1048576) ? 1048576 : p->opt.buffer_size, /* default to SNF_DATARING_SIZE from env */ + flags, /* may want pshared */ + &ps->snf_handle); + if (err != 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + err, "snf_open failed"); + return -1; + } + + if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { + ring_id = (int) strtol(nr, NULL, 0); + } + err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); + if (err != 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + err, "snf_ring_open_id(ring=%d) failed", ring_id); + return -1; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + if (p->opt.timeout <= 0) + ps->snf_timeout = -1; + else + ps->snf_timeout = p->opt.timeout; + + err = snf_start(ps->snf_handle); + if (err != 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + err, "snf_start failed"); + return -1; + } + + /* + * "select()" and "poll()" don't work on snf descriptors. + */ +#ifndef _WIN32 + p->selectable_fd = -1; +#endif /* !_WIN32 */ + p->linktype = DLT_EN10MB; + p->read_op = snf_read; + p->inject_op = snf_inject; + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = NULL; /* Not implemented.*/ + p->set_datalink_op = snf_set_datalink; + p->getnonblock_op = snf_getnonblock; + p->setnonblock_op = snf_setnonblock; + p->stats_op = snf_pcap_stats; + p->cleanup_op = snf_platform_cleanup; +#ifdef SNF_HAVE_INJECT_API + ps->snf_inj = NULL; +#endif + return 0; +} + +#define MAX_DESC_LENGTH 128 +int +snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf) +{ + pcap_if_t *dev; +#ifdef _WIN32 + struct sockaddr_in addr; +#endif + struct snf_ifaddrs *ifaddrs, *ifa; + char name[MAX_DESC_LENGTH]; + char desc[MAX_DESC_LENGTH]; + int ret, allports = 0, merge = 0; + const char *nr = NULL; + + if (snf_init(SNF_VERSION_API)) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_getifaddrs: snf_init failed"); + return (-1); + } + + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "snf_getifaddrs"); + return (-1); + } + if ((nr = getenv("SNF_FLAGS")) && *nr) { + errno = 0; + merge = strtol(nr, NULL, 0); + if (errno) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_getifaddrs: SNF_FLAGS is not a valid number"); + return (-1); + } + merge = merge & SNF_F_AGGREGATE_PORTMASK; + } + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->snf_ifa_next) { + /* + * Myricom SNF adapter ports may appear as regular + * network interfaces, which would already have been + * added to the list of adapters by pcapint_platform_finddevs() + * if this isn't an SNF-only version of libpcap. + * + * Our create routine intercepts pcap_create() calls for + * those interfaces and arranges that they will be + * opened using the SNF API instead. + * + * So if we already have an entry for the device, we + * don't add an additional entry for it, we just + * update the description for it, if any, to indicate + * which snfN device it is. Otherwise, we add an entry + * for it. + * + * In either case, if SNF_F_AGGREGATE_PORTMASK is set + * in SNF_FLAGS, we add this port to the bitmask + * of ports, which we use to generate a device + * we can use to capture on all ports. + * + * Generate the description string. If port aggregation + * is set, use 2^{port number} as the unit number, + * rather than {port number}. + * + * XXX - do entries in this list have IP addresses for + * the port? If so, should we add them to the + * entry for the device, if they're not already in the + * list of IP addresses for the device? + */ + (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom %ssnf%d", + merge ? "Merge Bitmask Port " : "", + merge ? 1 << ifa->snf_ifa_portnum : ifa->snf_ifa_portnum); + /* + * Add the port to the bitmask. + */ + if (merge) + allports |= 1 << ifa->snf_ifa_portnum; + /* + * See if there's already an entry for the device + * with the name ifa->snf_ifa_name. + */ + dev = pcapint_find_dev(devlistp, ifa->snf_ifa_name); + if (dev != NULL) { + /* + * Yes. Update its description. + */ + char *desc_str; + + desc_str = strdup(desc); + if (desc_str == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "snf_findalldevs strdup"); + return -1; + } + free(dev->description); + dev->description = desc_str; + } else { + /* + * No. Add an entry for it. + * + * XXX - is there a notion of "up" or "running", + * and can we determine whether something's + * plugged into the adapter and set + * PCAP_IF_CONNECTION_STATUS_CONNECTED or + * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? + */ + dev = pcapint_add_dev(devlistp, ifa->snf_ifa_name, 0, desc, + errbuf); + if (dev == NULL) + return -1; +#ifdef _WIN32 + /* + * On Windows, fill in IP# from device name + */ + ret = inet_pton(AF_INET, dev->name, &addr.sin_addr); + if (ret == 1) { + /* + * Successful conversion of device name + * to IPv4 address. + */ + addr.sin_family = AF_INET; + if (pcapint_add_addr_to_dev(dev, &addr, sizeof(addr), + NULL, 0, NULL, 0, NULL, 0, errbuf) == -1) + return -1; + } else if (ret == -1) { + /* + * Error. + */ + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "sinf_findalldevs inet_pton"); + return -1; + } +#endif _WIN32 + } + } + snf_freeifaddrs(ifaddrs); + /* + * Create a snfX entry if port aggregation is enabled + */ + if (merge) { + /* + * Add a new entry with all ports bitmask + */ + (void)snprintf(name,MAX_DESC_LENGTH,"snf%d",allports); + (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom Merge Bitmask All Ports snf%d", + allports); + /* + * XXX - is there any notion of "up" and "running" that + * would apply to this device, given that it handles + * multiple ports? + * + * Presumably, there's no notion of "connected" vs. + * "disconnected", as "is this plugged into a network?" + * would be a per-port property. + */ + if (pcapint_add_dev(devlistp, name, + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, desc, + errbuf) == NULL) + return (-1); + /* + * XXX - should we give it a list of addresses with all + * the addresses for all the ports? + */ + } + + return 0; +} + +pcap_t * +snf_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + int boardnum = -1; + struct snf_ifaddrs *ifaddrs, *ifa; + size_t devlen; + struct pcap_snf *ps; + + if (snf_init(SNF_VERSION_API)) { + /* Can't initialize the API, so no SNF devices */ + *is_ours = 0; + return NULL; + } + + /* + * Match a given interface name to our list of interface names, from + * which we can obtain the intended board number + */ + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) { + /* Can't get SNF addresses */ + *is_ours = 0; + return NULL; + } + devlen = strlen(device) + 1; + ifa = ifaddrs; + while (ifa) { + if (strncmp(device, ifa->snf_ifa_name, devlen) == 0) { + boardnum = ifa->snf_ifa_boardnum; + break; + } + ifa = ifa->snf_ifa_next; + } + snf_freeifaddrs(ifaddrs); + + if (ifa == NULL) { + /* + * If we can't find the device by name, support the name "snfX" + * and "snf10gX" where X is the board number. + */ + if (sscanf(device, "snf10g%d", &boardnum) != 1 && + sscanf(device, "snf%d", &boardnum) != 1) { + /* Nope, not a supported name */ + *is_ours = 0; + return NULL; + } + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_snf); + if (p == NULL) + return NULL; + ps = p->priv; + + /* + * We support microsecond and nanosecond time stamps. + */ + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, + "malloc"); + pcap_close(p); + return NULL; + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + p->tstamp_precision_count = 2; + + p->activate_op = snf_activate; + ps->snf_boardnum = boardnum; + return p; +} + +#ifdef SNF_ONLY +/* + * This libpcap build supports only SNF cards, not regular network + * interfaces.. + */ + +/* + * There are no regular interfaces, just SNF interfaces. + */ +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (0); +} + +/* + * Attempts to open a regular interface fail. + */ +pcap_t * +pcapint_create_interface(const char *device, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "This version of libpcap only supports SNF cards"); + return NULL; +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING " (SNF-only)"); +} +#endif diff --git a/src/libpcap-1.10.5/pcap-snf.h b/src/libpcap-1.10.5/pcap-snf.h new file mode 100644 index 0000000000..ffc64adf36 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-snf.h @@ -0,0 +1,2 @@ +pcap_t *snf_create(const char *, char *, int *); +int snf_findalldevs(pcap_if_list_t *devlistp, char *errbuf); diff --git a/src/libpcap-1.10.5/pcap-snit.c b/src/libpcap-1.10.5/pcap-snit.c new file mode 100644 index 0000000000..377f70bf37 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-snit.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Modifications made to accommodate the new SunOS4.0 NIT facility by + * Micky Liu, micky@cunixc.cc.columbia.edu, Columbia University in May, 1989. + * This module now handles the STREAMS based NIT. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * The chunk size for NIT. This is the amount of buffering + * done for read calls. + */ +#define CHUNKSIZE (2*1024) + +/* + * The total buffer space used by NIT. + */ +#define BUFSPACE (4*CHUNKSIZE) + +/* Forwards */ +static int nit_setflags(int, int, int, char *); + +/* + * Private data for capturing on STREAMS NIT devices. + */ +struct pcap_snit { + struct pcap_stat stat; +}; + +static int +pcap_stats_snit(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_snit *psn = p->priv; + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this does not include packets dropped because we ran out + * of buffer space. + * + * "ps_drop" counts packets dropped inside the "/dev/nit" + * device because of flow control requirements or resource + * exhaustion; it doesn't count packets dropped by the + * interface driver, or packets dropped upstream. As filtering + * is done in userland, it counts packets regardless of whether + * they would've passed the filter. + * + * These statistics don't include packets not yet read from the + * kernel by libpcap or packets not yet read from libpcap by the + * application. + */ + *ps = psn->stat; + return (0); +} + +static int +pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snit *psn = p->priv; + register int cc, n; + register u_char *bp, *cp, *ep; + register struct nit_bufhdr *hdrp; + register struct nit_iftime *ntp; + register struct nit_iflen *nlp; + register struct nit_ifdrops *ndp; + register int caplen; + + cc = p->cc; + if (cc == 0) { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + if (errno == EWOULDBLOCK) + return (0); + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "pcap_read"); + return (-1); + } + bp = (u_char *)p->buffer; + } else + bp = p->bp; + + /* + * loop through each snapshot in the chunk + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ + n = 0; + ep = bp + cc; + while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + + ++psn->stat.ps_recv; + cp = bp; + + /* get past NIT buffer */ + hdrp = (struct nit_bufhdr *)cp; + cp += sizeof(*hdrp); + + /* get past NIT timer */ + ntp = (struct nit_iftime *)cp; + cp += sizeof(*ntp); + + ndp = (struct nit_ifdrops *)cp; + psn->stat.ps_drop = ndp->nh_drops; + cp += sizeof *ndp; + + /* get past packet len */ + nlp = (struct nit_iflen *)cp; + cp += sizeof(*nlp); + + /* next snapshot */ + bp += hdrp->nhb_totlen; + + caplen = nlp->nh_pktlen; + if (caplen > p->snapshot) + caplen = p->snapshot; + + if (pcapint_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) { + struct pcap_pkthdr h; + h.ts = ntp->nh_timestamp; + h.len = nlp->nh_pktlen; + h.caplen = caplen; + (*callback)(user, &h, cp); + if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + } + p->cc = 0; + return (n); +} + +static int +pcap_inject_snit(pcap_t *p, const void *buf, int size) +{ + struct strbuf ctl, data; + + /* + * XXX - can we just do + * + ret = write(pd->f, buf, size); + */ + ctl.len = sizeof(*sa); /* XXX - what was this? */ + ctl.buf = (char *)sa; + data.buf = buf; + data.len = size; + ret = putmsg(p->fd, &ctl, &data); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + return (ret); +} + +static int +nit_setflags(pcap_t *p) +{ + bpf_u_int32 flags; + struct strioctl si; + u_int zero = 0; + struct timeval timeout; + + if (p->opt.immediate) { + /* + * Set the chunk size to zero, so that chunks get sent + * up immediately. + */ + si.ic_cmd = NIOCSCHUNK; + si.ic_len = sizeof(zero); + si.ic_dp = (char *)&zero; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCSCHUNK"); + return (-1); + } + } + si.ic_timout = INFTIM; + if (p->opt.timeout != 0) { + timeout.tv_sec = p->opt.timeout / 1000; + timeout.tv_usec = (p->opt.timeout * 1000) % 1000000; + si.ic_cmd = NIOCSTIME; + si.ic_len = sizeof(timeout); + si.ic_dp = (char *)&timeout; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCSTIME"); + return (-1); + } + } + flags = NI_TIMESTAMP | NI_LEN | NI_DROPS; + if (p->opt.promisc) + flags |= NI_PROMISC; + si.ic_cmd = NIOCSFLAGS; + si.ic_len = sizeof(flags); + si.ic_dp = (char *)&flags; + if (ioctl(p->fd, I_STR, (char *)&si) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCSFLAGS"); + return (-1); + } + return (0); +} + +static int +pcap_activate_snit(pcap_t *p) +{ + struct strioctl si; /* struct for ioctl() */ + struct ifreq ifr; /* interface request struct */ + int chunksize = CHUNKSIZE; + int fd; + static const char dev[] = "/dev/nit"; + int err; + + if (p->opt.rfmon) { + /* + * No monitor mode on SunOS 4.x (no Wi-Fi devices on + * hardware supported by SunOS 4.x). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + if (p->snapshot < 96) + /* + * NIT requires a snapshot length of at least 96. + */ + p->snapshot = 96; + + /* + * Initially try a read/write open (to allow the inject + * method to work). If that fails due to permission + * issues, fall back to read-only. This allows a + * non-root user to be granted specific access to pcap + * capabilities via file permissions. + * + * XXX - we should have an API that has a flag that + * controls whether to open read-only or read-write, + * so that denial of permission to send (or inability + * to send, if sending packets isn't supported on + * the device in question) can be indicated at open + * time. + */ + p->fd = fd = open(dev, O_RDWR); + if (fd < 0 && errno == EACCES) + p->fd = fd = open(dev, O_RDONLY); + if (fd < 0) { + if (errno == EACCES) { + err = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with EACCES - root privileges may be required", + dev); + } else { + err = PCAP_ERROR; + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s", dev); + } + goto bad; + } + + /* arrange to get discrete messages from the STREAM and use NIT_BUF */ + if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "I_SRDOPT"); + err = PCAP_ERROR; + goto bad; + } + if (ioctl(fd, I_PUSH, "nbuf") < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "push nbuf"); + err = PCAP_ERROR; + goto bad; + } + /* set the chunksize */ + si.ic_cmd = NIOCSCHUNK; + si.ic_timout = INFTIM; + si.ic_len = sizeof(chunksize); + si.ic_dp = (char *)&chunksize; + if (ioctl(fd, I_STR, (char *)&si) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCSCHUNK"); + err = PCAP_ERROR; + goto bad; + } + + /* request the interface */ + strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + si.ic_cmd = NIOCBIND; + si.ic_len = sizeof(ifr); + si.ic_dp = (char *)𝔦 + if (ioctl(fd, I_STR, (char *)&si) < 0) { + /* + * XXX - is there an error that means "no such device"? + * Is there one that means "that device doesn't support + * STREAMS NIT"? + */ + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCBIND: %s", ifr.ifr_name); + err = PCAP_ERROR; + goto bad; + } + + /* set the snapshot length */ + si.ic_cmd = NIOCSSNAP; + si.ic_len = sizeof(p->snapshot); + si.ic_dp = (char *)&p->snapshot; + if (ioctl(fd, I_STR, (char *)&si) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "NIOCSSNAP"); + err = PCAP_ERROR; + goto bad; + } + if (nit_setflags(p) < 0) { + err = PCAP_ERROR; + goto bad; + } + + (void)ioctl(fd, I_FLUSH, (char *)FLUSHR); + /* + * NIT supports only ethernets. + */ + p->linktype = DLT_EN10MB; + + p->bufsize = BUFSPACE; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + err = PCAP_ERROR; + goto bad; + } + + /* + * "p->fd" is an FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + err = PCAP_ERROR; + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + + p->read_op = pcap_read_snit; + p->inject_op = pcap_inject_snit; + p->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_snit; + + return (0); + bad: + pcapint_cleanup_live_common(p); + return (err); +} + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_snit); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_snit; + return (p); +} + +/* + * XXX - there's probably a NIOCBIND error that means "that device + * doesn't support NIT"; if so, we should try an NIOCBIND and use that. + */ +static int +can_be_bound(const char *name _U_) +{ + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do. + * XXX - is there a way to find out whether an adapter has + * something plugged into it? + */ + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound, + get_if_flags)); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-snoop.c b/src/libpcap-1.10.5/pcap-snoop.c new file mode 100644 index 0000000000..84ddd9e95d --- /dev/null +++ b/src/libpcap-1.10.5/pcap-snoop.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +/* + * Private data for capturing on snoop devices. + */ +struct pcap_snoop { + struct pcap_stat stat; +}; + +static int +pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_snoop *psn = p->priv; + int cc; + register struct snoopheader *sh; + register u_int datalen; + register u_int caplen; + register u_char *cp; + +again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + /* Don't choke when we get ptraced */ + switch (errno) { + + case EINTR: + goto again; + + case EWOULDBLOCK: + return (0); /* XXX */ + } + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "read"); + return (-1); + } + sh = (struct snoopheader *)p->buffer; + datalen = sh->snoop_packetlen; + + /* + * XXX - Sigh, snoop_packetlen is a 16 bit quantity. If we + * got a short length, but read a full sized snoop packet, + * assume we overflowed and add back the 64K... + */ + if (cc == (p->snapshot + sizeof(struct snoopheader)) && + (datalen < p->snapshot)) + datalen += (64 * 1024); + + caplen = (datalen < p->snapshot) ? datalen : p->snapshot; + cp = (u_char *)(sh + 1) + p->offset; /* XXX */ + + /* + * XXX unfortunately snoop loopback isn't exactly like + * BSD's. The address family is encoded in the first 2 + * bytes rather than the first 4 bytes! Luckily the last + * two snoop loopback bytes are zeroed. + */ + if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) { + u_int *uip = (u_int *)cp; + *uip >>= 16; + } + + if (p->fcode.bf_insns == NULL || + pcapint_filter(p->fcode.bf_insns, cp, datalen, caplen)) { + struct pcap_pkthdr h; + ++psn->stat.ps_recv; + h.ts.tv_sec = sh->snoop_timestamp.tv_sec; + h.ts.tv_usec = sh->snoop_timestamp.tv_usec; + h.len = datalen; + h.caplen = caplen; + (*callback)(user, &h, cp); + return (1); + } + return (0); +} + +static int +pcap_inject_snoop(pcap_t *p, const void *buf, int size) +{ + int ret; + + /* + * XXX - libnet overwrites the source address with what I + * presume is the interface's address; is that required? + */ + ret = write(p->fd, buf, size); + if (ret == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); + return (-1); + } + return (ret); +} + +static int +pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_snoop *psn = p->priv; + register struct rawstats *rs; + struct rawstats rawstats; + + rs = &rawstats; + memset(rs, 0, sizeof(*rs)); + if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "SIOCRAWSTATS"); + return (-1); + } + + /* + * "ifdrops" are those dropped by the network interface + * due to resource shortages or hardware errors. + * + * "sbdrops" are those dropped due to socket buffer limits. + * + * As filter is done in userland, "sbdrops" counts packets + * regardless of whether they would've passed the filter. + * + * XXX - does this count *all* Snoop or Drain sockets, + * rather than just this socket? If not, why does it have + * both Snoop and Drain statistics? + */ + psn->stat.ps_drop = + rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops + + rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops; + + /* + * "ps_recv" counts only packets that passed the filter. + * As filtering is done in userland, this does not include + * packets dropped because we ran out of buffer space. + */ + *ps = psn->stat; + return (0); +} + +/* XXX can't disable promiscuous */ +static int +pcap_activate_snoop(pcap_t *p) +{ + int fd; + struct sockaddr_raw sr; + struct snoopfilter sf; + u_int v; + int ll_hdrlen; + int snooplen; + struct ifreq ifr; + + fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "snoop socket"); + goto bad; + } + p->fd = fd; + memset(&sr, 0, sizeof(sr)); + sr.sr_family = AF_RAW; + (void)strncpy(sr.sr_ifname, p->opt.device, sizeof(sr.sr_ifname)); + if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) { + /* + * XXX - there's probably a particular bind error that + * means "there's no such device" and a particular bind + * error that means "that device doesn't support snoop"; + * they might be the same error, if they both end up + * meaning "snoop doesn't know about that device". + */ + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "snoop bind"); + goto bad; + } + memset(&sf, 0, sizeof(sf)); + if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCADDSNOOP"); + goto bad; + } + if (p->opt.buffer_size != 0) + v = p->opt.buffer_size; + else + v = 64 * 1024; /* default to 64K buffer size */ + (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v)); + /* + * XXX hack - map device name to link layer type + */ + if (strncmp("et", p->opt.device, 2) == 0 || /* Challenge 10 Mbit */ + strncmp("ec", p->opt.device, 2) == 0 || /* Indigo/Indy 10 Mbit, + O2 10/100 */ + strncmp("ef", p->opt.device, 2) == 0 || /* O200/2000 10/100 Mbit */ + strncmp("eg", p->opt.device, 2) == 0 || /* Octane/O2xxx/O3xxx Gigabit */ + strncmp("gfe", p->opt.device, 3) == 0 || /* GIO 100 Mbit */ + strncmp("fxp", p->opt.device, 3) == 0 || /* Challenge VME Enet */ + strncmp("ep", p->opt.device, 2) == 0 || /* Challenge 8x10 Mbit EPLEX */ + strncmp("vfe", p->opt.device, 3) == 0 || /* Challenge VME 100Mbit */ + strncmp("fa", p->opt.device, 2) == 0 || + strncmp("qaa", p->opt.device, 3) == 0 || + strncmp("cip", p->opt.device, 3) == 0 || + strncmp("el", p->opt.device, 2) == 0) { + p->linktype = DLT_EN10MB; + p->offset = RAW_HDRPAD(sizeof(struct ether_header)); + ll_hdrlen = sizeof(struct ether_header); + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + * + * XXX - are there any sorts of "fake Ethernet" that have + * Ethernet link-layer headers but that *shouldn't offer + * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it + * or get traffic bridged onto it? "el" is for ATM LANE + * Ethernet devices, so that might be the case for them; + * the same applies for "qaa" classical IP devices. If + * "fa" devices are for FORE SPANS, that'd apply to them + * as well; what are "cip" devices - some other ATM + * Classical IP devices? + */ + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } else if (strncmp("ipg", p->opt.device, 3) == 0 || + strncmp("rns", p->opt.device, 3) == 0 || /* O2/200/2000 FDDI */ + strncmp("xpi", p->opt.device, 3) == 0) { + p->linktype = DLT_FDDI; + p->offset = 3; /* XXX yeah? */ + ll_hdrlen = 13; + } else if (strncmp("ppp", p->opt.device, 3) == 0) { + p->linktype = DLT_RAW; + ll_hdrlen = 0; /* DLT_RAW meaning "no PPP header, just the IP packet"? */ + } else if (strncmp("qfa", p->opt.device, 3) == 0) { + p->linktype = DLT_IP_OVER_FC; + ll_hdrlen = 24; + } else if (strncmp("pl", p->opt.device, 2) == 0) { + p->linktype = DLT_RAW; + ll_hdrlen = 0; /* Cray UNICOS/mp pseudo link */ + } else if (strncmp("lo", p->opt.device, 2) == 0) { + p->linktype = DLT_NULL; + ll_hdrlen = 4; + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snoop: unknown physical layer type"); + goto bad; + } + + if (p->opt.rfmon) { + /* + * No monitor mode on Irix (no Wi-Fi devices on + * hardware supported by Irix). + */ + return (PCAP_ERROR_RFMON_NOTSUP); + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + +#ifdef SIOCGIFMTU + /* + * XXX - IRIX appears to give you an error if you try to set the + * capture length to be greater than the MTU, so let's try to get + * the MTU first and, if that succeeds, trim the snap length + * to be no greater than the MTU. + */ + (void)strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMTU"); + goto bad; + } + /* + * OK, we got it. + * + * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an + * "ifru_metric" member of the "ifr_ifru" union in an "ifreq" + * structure, others don't. + * + * I've no idea what's going on, so, if "ifr_mtu" isn't defined, + * we define it as "ifr_metric", as using that field appears to + * work on the versions that lack "ifr_mtu" (and, on those that + * don't lack it, "ifru_metric" and "ifru_mtu" are both "int" + * members of the "ifr_ifru" union, which suggests that they + * may be interchangeable in this case). + */ +#ifndef ifr_mtu +#define ifr_mtu ifr_metric +#endif + if (p->snapshot > ifr.ifr_mtu + ll_hdrlen) + p->snapshot = ifr.ifr_mtu + ll_hdrlen; +#endif + + /* + * The argument to SIOCSNOOPLEN is the number of link-layer + * payload bytes to capture - it doesn't count link-layer + * header bytes. + */ + snooplen = p->snapshot - ll_hdrlen; + if (snooplen < 0) + snooplen = 0; + if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCSNOOPLEN"); + goto bad; + } + v = 1; + if (ioctl(fd, SIOCSNOOPING, &v) < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCSNOOPING"); + goto bad; + } + + p->bufsize = 4096; /* XXX */ + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + goto bad; + } + + /* + * "p->fd" is a socket, so "select()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_snoop; + p->inject_op = pcap_inject_snoop; + p->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = NULL; /* can't change data link type */ + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; + p->stats_op = pcap_stats_snoop; + + return (0); + bad: + pcapint_cleanup_live_common(p); + return (PCAP_ERROR); +} + +pcap_t * +pcapint_create_interface(const char *device _U_, char *ebuf) +{ + pcap_t *p; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_snoop); + if (p == NULL) + return (NULL); + + p->activate_op = pcap_activate_snoop; + return (p); +} + +/* + * XXX - there's probably a particular bind error that means "that device + * doesn't support snoop"; if so, we should try a bind and use that. + */ +static int +can_be_bound(const char *name _U_) +{ + return (1); +} + +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do. + * XXX - is there a way to find out whether an adapter has + * something plugged into it? + */ + return (0); +} + +int +pcapint_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) +{ + return (pcapint_findalldevs_interfaces(devlistp, errbuf, can_be_bound, + get_if_flags)); +} + +/* + * Libpcap version string. + */ +const char * +pcap_lib_version(void) +{ + return (PCAP_VERSION_STRING); +} diff --git a/src/libpcap-1.10.5/pcap-tc.c b/src/libpcap-1.10.5/pcap-tc.c new file mode 100644 index 0000000000..4c6599d241 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-tc.c @@ -0,0 +1,1216 @@ +/* + * Copyright (c) 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CACE Technologies nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include + +#include "pcap-tc.h" + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +typedef TC_STATUS (TC_CALLCONV *TcFcnQueryPortList) (PTC_PORT *ppPorts, PULONG pLength); +typedef TC_STATUS (TC_CALLCONV *TcFcnFreePortList) (TC_PORT *pPorts); + +typedef PCHAR (TC_CALLCONV *TcFcnStatusGetString) (TC_STATUS status); + +typedef PCHAR (TC_CALLCONV *TcFcnPortGetName) (TC_PORT port); +typedef PCHAR (TC_CALLCONV *TcFcnPortGetDescription) (TC_PORT port); + +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceOpenByName) (PCHAR name, PTC_INSTANCE pInstance); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceClose) (TC_INSTANCE instance); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceSetFeature) (TC_INSTANCE instance, ULONG feature, ULONG value); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryFeature) (TC_INSTANCE instance, ULONG feature, PULONG pValue); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceReceivePackets) (TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer); +typedef HANDLE (TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceTransmitPackets) (TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer); +typedef TC_STATUS (TC_CALLCONV *TcFcnInstanceQueryStatistics) (TC_INSTANCE instance, PTC_STATISTICS pStatistics); + +typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCreate) (ULONG size, PTC_PACKETS_BUFFER pBuffer); +typedef VOID (TC_CALLCONV *TcFcnPacketsBufferDestroy) (TC_PACKETS_BUFFER buffer); +typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData); +typedef TC_STATUS (TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData); + +typedef VOID (TC_CALLCONV *TcFcnStatisticsDestroy) (TC_STATISTICS statistics); +typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsUpdate) (TC_STATISTICS statistics); +typedef TC_STATUS (TC_CALLCONV *TcFcnStatisticsQueryValue) (TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue); + +typedef enum LONG +{ + TC_API_UNLOADED = 0, + TC_API_LOADED, + TC_API_CANNOT_LOAD, + TC_API_LOADING +} + TC_API_LOAD_STATUS; + + +typedef struct _TC_FUNCTIONS +{ + TC_API_LOAD_STATUS LoadStatus; +#ifdef _WIN32 + HMODULE hTcApiDllHandle; +#endif + TcFcnQueryPortList QueryPortList; + TcFcnFreePortList FreePortList; + TcFcnStatusGetString StatusGetString; + + TcFcnPortGetName PortGetName; + TcFcnPortGetDescription PortGetDescription; + + TcFcnInstanceOpenByName InstanceOpenByName; + TcFcnInstanceClose InstanceClose; + TcFcnInstanceSetFeature InstanceSetFeature; + TcFcnInstanceQueryFeature InstanceQueryFeature; + TcFcnInstanceReceivePackets InstanceReceivePackets; +#ifdef _WIN32 + TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle; +#endif + TcFcnInstanceTransmitPackets InstanceTransmitPackets; + TcFcnInstanceQueryStatistics InstanceQueryStatistics; + + TcFcnPacketsBufferCreate PacketsBufferCreate; + TcFcnPacketsBufferDestroy PacketsBufferDestroy; + TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket; + TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket; + + TcFcnStatisticsDestroy StatisticsDestroy; + TcFcnStatisticsUpdate StatisticsUpdate; + TcFcnStatisticsQueryValue StatisticsQueryValue; +} + TC_FUNCTIONS; + +static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port); +static int TcSetDatalink(pcap_t *p, int dlt); +static int TcGetNonBlock(pcap_t *p); +static int TcSetNonBlock(pcap_t *p, int nonblock); +static void TcCleanup(pcap_t *p); +static int TcInject(pcap_t *p, const void *buf, int size); +static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user); +static int TcStats(pcap_t *p, struct pcap_stat *ps); +#ifdef _WIN32 +static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size); +static int TcSetBuff(pcap_t *p, int dim); +static int TcSetMode(pcap_t *p, int mode); +static int TcSetMinToCopy(pcap_t *p, int size); +static HANDLE TcGetReceiveWaitHandle(pcap_t *p); +static int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp); +static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp); +static u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync); +static int TcSetUserBuffer(pcap_t *p, int size); +static int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks); +static int TcLiveDumpEnded(pcap_t *p, int sync); +static PAirpcapHandle TcGetAirPcapHandle(pcap_t *p); +#endif + +#ifdef _WIN32 +TC_FUNCTIONS g_TcFunctions = +{ + TC_API_UNLOADED, /* LoadStatus */ + NULL, /* hTcApiDllHandle */ + NULL, /* QueryPortList */ + NULL, /* FreePortList */ + NULL, /* StatusGetString */ + NULL, /* PortGetName */ + NULL, /* PortGetDescription */ + NULL, /* InstanceOpenByName */ + NULL, /* InstanceClose */ + NULL, /* InstanceSetFeature */ + NULL, /* InstanceQueryFeature */ + NULL, /* InstanceReceivePackets */ + NULL, /* InstanceGetReceiveWaitHandle */ + NULL, /* InstanceTransmitPackets */ + NULL, /* InstanceQueryStatistics */ + NULL, /* PacketsBufferCreate */ + NULL, /* PacketsBufferDestroy */ + NULL, /* PacketsBufferQueryNextPacket */ + NULL, /* PacketsBufferCommitNextPacket */ + NULL, /* StatisticsDestroy */ + NULL, /* StatisticsUpdate */ + NULL /* StatisticsQueryValue */ +}; +#else +TC_FUNCTIONS g_TcFunctions = +{ + TC_API_LOADED, /* LoadStatus */ + TcQueryPortList, + TcFreePortList, + TcStatusGetString, + TcPortGetName, + TcPortGetDescription, + TcInstanceOpenByName, + TcInstanceClose, + TcInstanceSetFeature, + TcInstanceQueryFeature, + TcInstanceReceivePackets, +#ifdef _WIN32 + TcInstanceGetReceiveWaitHandle, +#endif + TcInstanceTransmitPackets, + TcInstanceQueryStatistics, + TcPacketsBufferCreate, + TcPacketsBufferDestroy, + TcPacketsBufferQueryNextPacket, + TcPacketsBufferCommitNextPacket, + TcStatisticsDestroy, + TcStatisticsUpdate, + TcStatisticsQueryValue, +}; +#endif + +#define MAX_TC_PACKET_SIZE 9500 + +#pragma pack(push, 1) + +#define PPH_PH_FLAG_PADDING ((UCHAR)0x01) +#define PPH_PH_VERSION ((UCHAR)0x00) + +typedef struct _PPI_PACKET_HEADER +{ + UCHAR PphVersion; + UCHAR PphFlags; + USHORT PphLength; + ULONG PphDlt; +} + PPI_PACKET_HEADER, *PPPI_PACKET_HEADER; + +typedef struct _PPI_FIELD_HEADER +{ + USHORT PfhType; + USHORT PfhLength; +} + PPI_FIELD_HEADER, *PPPI_FIELD_HEADER; + + +#define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08) + +typedef struct _PPI_FIELD_AGGREGATION_EXTENSION +{ + ULONG InterfaceId; +} + PPI_FIELD_AGGREGATION_EXTENSION, *PPPI_FIELD_AGGREGATION_EXTENSION; + + +#define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09) + +#define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001) + +typedef struct _PPI_FIELD_802_3_EXTENSION +{ + ULONG Flags; + ULONG Errors; +} + PPI_FIELD_802_3_EXTENSION, *PPPI_FIELD_802_3_EXTENSION; + +typedef struct _PPI_HEADER +{ + PPI_PACKET_HEADER PacketHeader; + PPI_FIELD_HEADER AggregationFieldHeader; + PPI_FIELD_AGGREGATION_EXTENSION AggregationField; + PPI_FIELD_HEADER Dot3FieldHeader; + PPI_FIELD_802_3_EXTENSION Dot3Field; +} + PPI_HEADER, *PPPI_HEADER; +#pragma pack(pop) + +#ifdef _WIN32 +/* + * NOTE: this function should be called by the pcap functions that can theoretically + * deal with the Tc library for the first time, namely listing the adapters and + * opening one. All the other ones (close, read, write, set parameters) work + * on an open instance of TC, so we do not care to call this function + */ +TC_API_LOAD_STATUS LoadTcFunctions(void) +{ + TC_API_LOAD_STATUS currentStatus; + + do + { + currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_UNLOADED); + + while(currentStatus == TC_API_LOADING) + { + currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_LOADING); + Sleep(10); + } + + /* + * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything) + * or in cannot load + */ + if(currentStatus == TC_API_LOADED) + { + return TC_API_LOADED; + } + + if (currentStatus == TC_API_CANNOT_LOAD) + { + return TC_API_CANNOT_LOAD; + } + + currentStatus = TC_API_CANNOT_LOAD; + + g_TcFunctions.hTcApiDllHandle = pcapint_load_code("TcApi.dll"); + if (g_TcFunctions.hTcApiDllHandle == NULL) break; + + g_TcFunctions.QueryPortList = (TcFcnQueryPortList) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList"); + g_TcFunctions.FreePortList = (TcFcnFreePortList) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcFreePortList"); + + g_TcFunctions.StatusGetString = (TcFcnStatusGetString) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString"); + + g_TcFunctions.PortGetName = (TcFcnPortGetName) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetName"); + g_TcFunctions.PortGetDescription = (TcFcnPortGetDescription) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription"); + + g_TcFunctions.InstanceOpenByName = (TcFcnInstanceOpenByName) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName"); + g_TcFunctions.InstanceClose = (TcFcnInstanceClose) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose"); + g_TcFunctions.InstanceSetFeature = (TcFcnInstanceSetFeature) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature"); + g_TcFunctions.InstanceQueryFeature = (TcFcnInstanceQueryFeature) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature"); + g_TcFunctions.InstanceReceivePackets = (TcFcnInstanceReceivePackets) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets"); + g_TcFunctions.InstanceGetReceiveWaitHandle = (TcFcnInstanceGetReceiveWaitHandle)pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle"); + g_TcFunctions.InstanceTransmitPackets = (TcFcnInstanceTransmitPackets)pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets"); + g_TcFunctions.InstanceQueryStatistics = (TcFcnInstanceQueryStatistics)pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics"); + + g_TcFunctions.PacketsBufferCreate = (TcFcnPacketsBufferCreate) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate"); + g_TcFunctions.PacketsBufferDestroy = (TcFcnPacketsBufferDestroy) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy"); + g_TcFunctions.PacketsBufferQueryNextPacket = (TcFcnPacketsBufferQueryNextPacket)pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket"); + g_TcFunctions.PacketsBufferCommitNextPacket = (TcFcnPacketsBufferCommitNextPacket)pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket"); + + g_TcFunctions.StatisticsDestroy = (TcFcnStatisticsDestroy) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy"); + g_TcFunctions.StatisticsUpdate = (TcFcnStatisticsUpdate) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate"); + g_TcFunctions.StatisticsQueryValue = (TcFcnStatisticsQueryValue) pcapint_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue"); + + if ( g_TcFunctions.QueryPortList == NULL + || g_TcFunctions.FreePortList == NULL + || g_TcFunctions.StatusGetString == NULL + || g_TcFunctions.PortGetName == NULL + || g_TcFunctions.PortGetDescription == NULL + || g_TcFunctions.InstanceOpenByName == NULL + || g_TcFunctions.InstanceClose == NULL + || g_TcFunctions.InstanceSetFeature == NULL + || g_TcFunctions.InstanceQueryFeature == NULL + || g_TcFunctions.InstanceReceivePackets == NULL + || g_TcFunctions.InstanceGetReceiveWaitHandle == NULL + || g_TcFunctions.InstanceTransmitPackets == NULL + || g_TcFunctions.InstanceQueryStatistics == NULL + || g_TcFunctions.PacketsBufferCreate == NULL + || g_TcFunctions.PacketsBufferDestroy == NULL + || g_TcFunctions.PacketsBufferQueryNextPacket == NULL + || g_TcFunctions.PacketsBufferCommitNextPacket == NULL + || g_TcFunctions.StatisticsDestroy == NULL + || g_TcFunctions.StatisticsUpdate == NULL + || g_TcFunctions.StatisticsQueryValue == NULL + ) + { + break; + } + + /* + * everything got loaded, yay!! + */ + currentStatus = TC_API_LOADED; + }while(FALSE); + + if (currentStatus != TC_API_LOADED) + { + if (g_TcFunctions.hTcApiDllHandle != NULL) + { + FreeLibrary(g_TcFunctions.hTcApiDllHandle); + g_TcFunctions.hTcApiDllHandle = NULL; + } + } + + InterlockedExchange((LONG*)&g_TcFunctions.LoadStatus, currentStatus); + + return currentStatus; +} +#else +// static linking +TC_API_LOAD_STATUS LoadTcFunctions(void) +{ + return TC_API_LOADED; +} +#endif + +/* + * Private data for capturing on TurboCap devices. + */ +struct pcap_tc { + TC_INSTANCE TcInstance; + TC_PACKETS_BUFFER TcPacketsBuffer; + ULONG TcAcceptedCount; + u_char *PpiPacket; +}; + +int +TcFindAllDevs(pcap_if_list_t *devlist, char *errbuf) +{ + TC_API_LOAD_STATUS loadStatus; + ULONG numPorts; + PTC_PORT pPorts = NULL; + TC_STATUS status; + int result = 0; + pcap_if_t *dev; + ULONG i; + + do + { + loadStatus = LoadTcFunctions(); + + if (loadStatus != TC_API_LOADED) + { + result = 0; + break; + } + + /* + * enumerate the ports, and add them to the list + */ + status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); + + if (status != TC_SUCCESS) + { + result = 0; + break; + } + + for (i = 0; i < numPorts; i++) + { + /* + * transform the port into an entry in the list + */ + dev = TcCreatePcapIfFromPort(pPorts[i]); + + if (dev != NULL) + pcapint_add_dev(devlist, dev->name, dev->flags, dev->description, errbuf); + } + + if (numPorts > 0) + { + /* + * ignore the result here + */ + status = g_TcFunctions.FreePortList(pPorts); + } + + }while(FALSE); + + return result; +} + +static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port) +{ + CHAR *name; + CHAR *description; + pcap_if_t *newIf = NULL; + + newIf = (pcap_if_t*)malloc(sizeof(*newIf)); + if (newIf == NULL) + { + return NULL; + } + + memset(newIf, 0, sizeof(*newIf)); + + name = g_TcFunctions.PortGetName(port); + description = g_TcFunctions.PortGetDescription(port); + + newIf->name = (char*)malloc(strlen(name) + 1); + if (newIf->name == NULL) + { + free(newIf); + return NULL; + } + + newIf->description = (char*)malloc(strlen(description) + 1); + if (newIf->description == NULL) + { + free(newIf->name); + free(newIf); + return NULL; + } + + strcpy(newIf->name, name); + strcpy(newIf->description, description); + + newIf->addresses = NULL; + newIf->next = NULL; + newIf->flags = 0; + + return newIf; + +} + +static int +TcActivate(pcap_t *p) +{ + struct pcap_tc *pt = p->priv; + TC_STATUS status; + ULONG timeout; + PPPI_HEADER pPpiHeader; + + if (p->opt.rfmon) + { + /* + * No monitor mode on Tc cards; they're Ethernet + * capture adapters. + */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + pt->PpiPacket = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE); + + if (pt->PpiPacket == NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory"); + return PCAP_ERROR; + } + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + + /* + * Initialize the PPI fixed fields + */ + pPpiHeader = (PPPI_HEADER)pt->PpiPacket; + pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB; + pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER); + pPpiHeader->PacketHeader.PphFlags = 0; + pPpiHeader->PacketHeader.PphVersion = 0; + + pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION); + pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION; + + pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION); + pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION; + + status = g_TcFunctions.InstanceOpenByName(p->opt.device, &pt->TcInstance); + + if (status != TC_SUCCESS) + { + /* Adapter detected but we are not able to open it. Return failure. */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status)); + return PCAP_ERROR; + } + + p->linktype = DLT_EN10MB; + p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); + if (p->dlt_list == NULL) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory"); + return PCAP_ERROR; + } + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_PPI; + p->dlt_count = 2; + + /* + * ignore promiscuous mode + * p->opt.promisc + */ + + + /* + * ignore all the buffer sizes + */ + + /* + * enable reception + */ + status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); + goto bad; + } + + /* + * enable transmission + */ + status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1); + /* + * Ignore the error here. + */ + + p->inject_op = TcInject; + /* + * if the timeout is -1, it means immediate return, no timeout + * if the timeout is 0, it means INFINITE + */ + + if (p->opt.timeout == 0) + { + timeout = 0xFFFFFFFF; + } + else + if (p->opt.timeout < 0) + { + /* + * we insert a minimal timeout here + */ + timeout = 10; + } + else + { + timeout = p->opt.timeout; + } + + status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status)); + goto bad; + } + + p->read_op = TcRead; + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = NULL; /* Not implemented. */ + p->set_datalink_op = TcSetDatalink; + p->getnonblock_op = TcGetNonBlock; + p->setnonblock_op = TcSetNonBlock; + p->stats_op = TcStats; +#ifdef _WIN32 + p->stats_ex_op = TcStatsEx; + p->setbuff_op = TcSetBuff; + p->setmode_op = TcSetMode; + p->setmintocopy_op = TcSetMinToCopy; + p->getevent_op = TcGetReceiveWaitHandle; + p->oid_get_request_op = TcOidGetRequest; + p->oid_set_request_op = TcOidSetRequest; + p->sendqueue_transmit_op = TcSendqueueTransmit; + p->setuserbuffer_op = TcSetUserBuffer; + p->live_dump_op = TcLiveDump; + p->live_dump_ended_op = TcLiveDumpEnded; + p->get_airpcap_handle_op = TcGetAirPcapHandle; +#else + p->selectable_fd = -1; +#endif + + p->cleanup_op = TcCleanup; + + return 0; +bad: + TcCleanup(p); + return PCAP_ERROR; +} + +pcap_t * +TcCreate(const char *device, char *ebuf, int *is_ours) +{ + ULONG numPorts; + PTC_PORT pPorts = NULL; + TC_STATUS status; + int is_tc; + ULONG i; + pcap_t *p; + + if (LoadTcFunctions() != TC_API_LOADED) + { + /* + * XXX - report this as an error rather than as + * "not a TurboCap device"? + */ + *is_ours = 0; + return NULL; + } + + /* + * enumerate the ports, and add them to the list + */ + status = g_TcFunctions.QueryPortList(&pPorts, &numPorts); + + if (status != TC_SUCCESS) + { + /* + * XXX - report this as an error rather than as + * "not a TurboCap device"? + */ + *is_ours = 0; + return NULL; + } + + is_tc = FALSE; + for (i = 0; i < numPorts; i++) + { + if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0) + { + is_tc = TRUE; + break; + } + } + + if (numPorts > 0) + { + /* + * ignore the result here + */ + (void)g_TcFunctions.FreePortList(pPorts); + } + + if (!is_tc) + { + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_tc); + if (p == NULL) + return NULL; + + p->activate_op = TcActivate; + /* + * Set these up front, so that, even if our client tries + * to set non-blocking mode before we're activated, or + * query the state of non-blocking mode, they get an error, + * rather than having the non-blocking mode option set + * for use later. + */ + p->getnonblock_op = TcGetNonBlock; + p->setnonblock_op = TcSetNonBlock; + return p; +} + +static int TcSetDatalink(pcap_t *p, int dlt) +{ + /* + * We don't have to do any work here; pcap_set_datalink() checks + * whether the value is in the list of DLT_ values we + * supplied, so we don't have to, and, if it is valid, sets + * p->linktype to the new value; we don't have to do anything + * in hardware, we just use what's in p->linktype. + * + * We do have to have a routine, however, so that pcap_set_datalink() + * doesn't think we don't support setting the link-layer header + * type at all. + */ + return 0; +} + +static int TcGetNonBlock(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for TurboCap ports"); + return -1; +} + +static int TcSetNonBlock(pcap_t *p, int nonblock) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Non-blocking mode isn't supported for TurboCap ports"); + return -1; +} + +static void TcCleanup(pcap_t *p) +{ + struct pcap_tc *pt = p->priv; + + if (pt->TcPacketsBuffer != NULL) + { + g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); + pt->TcPacketsBuffer = NULL; + } + if (pt->TcInstance != NULL) + { + /* + * here we do not check for the error values + */ + g_TcFunctions.InstanceClose(pt->TcInstance); + pt->TcInstance = NULL; + } + + if (pt->PpiPacket != NULL) + { + free(pt->PpiPacket); + pt->PpiPacket = NULL; + } + + pcapint_cleanup_live_common(p); +} + +/* Send a packet to the network */ +static int TcInject(pcap_t *p, const void *buf, int size) +{ + struct pcap_tc *pt = p->priv; + TC_STATUS status; + TC_PACKETS_BUFFER buffer; + TC_PACKET_HEADER header; + + if (size >= 0xFFFF) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k"); + return -1; + } + + status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + + /* + * we assume that the packet is without the checksum, as common with WinPcap + */ + memset(&header, 0, sizeof(header)); + + header.Length = (USHORT)size; + header.CapturedLength = header.Length; + + status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf); + + if (status == TC_SUCCESS) + { + status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + } + } + else + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + } + + g_TcFunctions.PacketsBufferDestroy(buffer); + + if (status != TC_SUCCESS) + { + return -1; + } + else + { + return 0; + } +} + +static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct pcap_tc *pt = p->priv; + TC_STATUS status; + int n = 0; + + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) + { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + + if (pt->TcPacketsBuffer == NULL) + { + status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer); + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + } + + while (TRUE) + { + struct pcap_pkthdr hdr; + TC_PACKET_HEADER tcHeader; + PVOID data; + ULONG filterResult; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) + { + if (n == 0) + { + p->break_loop = 0; + return -2; + } + else + { + return n; + } + } + + if (pt->TcPacketsBuffer == NULL) + { + break; + } + + status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data); + + if (status == TC_ERROR_END_OF_BUFFER) + { + g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer); + pt->TcPacketsBuffer = NULL; + break; + } + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + + /* No underlying filtering system. We need to filter on our own */ + if (p->fcode.bf_insns) + { + filterResult = pcapint_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength); + + if (filterResult == 0) + { + continue; + } + + if (filterResult > tcHeader.CapturedLength) + { + filterResult = tcHeader.CapturedLength; + } + } + else + { + filterResult = tcHeader.CapturedLength; + } + + pt->TcAcceptedCount ++; + + hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000)); + hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000); + + if (p->linktype == DLT_EN10MB) + { + hdr.caplen = filterResult; + hdr.len = tcHeader.Length; + (*callback)(user, &hdr, data); + } + else + { + PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket; + PVOID data2 = pPpiHeader + 1; + + pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags); + pPpiHeader->Dot3Field.Errors = tcHeader.Errors; + if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM) + { + pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT; + } + else + { + pPpiHeader->Dot3Field.Flags = 0; + } + + if (filterResult <= MAX_TC_PACKET_SIZE) + { + memcpy(data2, data, filterResult); + hdr.caplen = sizeof(PPI_HEADER) + filterResult; + hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; + } + else + { + memcpy(data2, data, MAX_TC_PACKET_SIZE); + hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE; + hdr.len = sizeof(PPI_HEADER) + tcHeader.Length; + } + + (*callback)(user, &hdr, pt->PpiPacket); + + } + + if (++n >= cnt && cnt > 0) + { + return n; + } + } + + return n; +} + +static int +TcStats(pcap_t *p, struct pcap_stat *ps) +{ + struct pcap_tc *pt = p->priv; + TC_STATISTICS statistics; + TC_STATUS status; + ULONGLONG counter; + struct pcap_stat s; + + status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + + memset(&s, 0, sizeof(s)); + + status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + if (counter <= (ULONGLONG)0xFFFFFFFF) + { + s.ps_recv = (ULONG)counter; + } + else + { + s.ps_recv = 0xFFFFFFFF; + } + + status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return -1; + } + if (counter <= (ULONGLONG)0xFFFFFFFF) + { + s.ps_ifdrop = (ULONG)counter; + s.ps_drop = (ULONG)counter; + } + else + { + s.ps_ifdrop = 0xFFFFFFFF; + s.ps_drop = 0xFFFFFFFF; + } + +#if defined(_WIN32) && defined(ENABLE_REMOTE) + s.ps_capt = pt->TcAcceptedCount; +#endif + *ps = s; + + return 0; +} + + +#ifdef _WIN32 +static struct pcap_stat * +TcStatsEx(pcap_t *p, int *pcap_stat_size) +{ + struct pcap_tc *pt = p->priv; + TC_STATISTICS statistics; + TC_STATUS status; + ULONGLONG counter; + + *pcap_stat_size = sizeof (p->stat); + + status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return NULL; + } + + memset(&p->stat, 0, sizeof(p->stat)); + + status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter); + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return NULL; + } + if (counter <= (ULONGLONG)0xFFFFFFFF) + { + p->stat.ps_recv = (ULONG)counter; + } + else + { + p->stat.ps_recv = 0xFFFFFFFF; + } + + status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter); + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + return NULL; + } + if (counter <= (ULONGLONG)0xFFFFFFFF) + { + p->stat.ps_ifdrop = (ULONG)counter; + p->stat.ps_drop = (ULONG)counter; + } + else + { + p->stat.ps_ifdrop = 0xFFFFFFFF; + p->stat.ps_drop = 0xFFFFFFFF; + } + +#if defined(_WIN32) && defined(ENABLE_REMOTE) + p->stat.ps_capt = pt->TcAcceptedCount; +#endif + + return &p->stat; +} + +/* Set the dimension of the kernel-level capture buffer */ +static int +TcSetBuff(pcap_t *p, int dim) +{ + /* + * XXX turbocap has an internal way of managing buffers. + * And at the moment it's not configurable, so we just + * silently ignore the request to set the buffer. + */ + return 0; +} + +static int +TcSetMode(pcap_t *p, int mode) +{ + if (mode != MODE_CAPT) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %d not supported by TurboCap devices. TurboCap only supports capture.", mode); + return -1; + } + + return 0; +} + +static int +TcSetMinToCopy(pcap_t *p, int size) +{ + struct pcap_tc *pt = p->priv; + TC_STATUS status; + + if (size < 0) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0."); + return -1; + } + + status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size); + + if (status != TC_SUCCESS) + { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status); + } + + return 0; +} + +static HANDLE +TcGetReceiveWaitHandle(pcap_t *p) +{ + struct pcap_tc *pt = p->priv; + + return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance); +} + +static int +TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID get request cannot be performed on a TurboCap device"); + return PCAP_ERROR; +} + +static int +TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID set request cannot be performed on a TurboCap device"); + return PCAP_ERROR; +} + +static u_int +TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packets cannot be bulk transmitted on a TurboCap device"); + return 0; +} + +static int +TcSetUserBuffer(pcap_t *p, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The user buffer cannot be set on a TurboCap device"); + return -1; +} + +static int +TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a TurboCap device"); + return -1; +} + +static int +TcLiveDumpEnded(pcap_t *p, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a TurboCap device"); + return -1; +} + +static PAirpcapHandle +TcGetAirPcapHandle(pcap_t *p _U_) +{ + return NULL; +} +#endif diff --git a/src/libpcap-1.10.5/pcap-tc.h b/src/libpcap-1.10.5/pcap-tc.h new file mode 100644 index 0000000000..f7b2d12def --- /dev/null +++ b/src/libpcap-1.10.5/pcap-tc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of CACE Technologies nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __PCAP_TC_H__ +#define __PCAP_TC_H__ + +/* + * needed because gcc headers do not have C_ASSERT + */ +#ifndef C_ASSERT +#define C_ASSERT(a) +#endif + +#include + +/* + * functions used effectively by the pcap library + */ + +pcap_t * +TcCreate(const char *device, char *ebuf, int *is_ours); + +int +TcFindAllDevs(pcap_if_list_t *devlistp, char *errbuf); + +#endif diff --git a/src/libpcap-1.10.5/pcap-tstamp.manmisc.in b/src/libpcap-1.10.5/pcap-tstamp.manmisc.in new file mode 100644 index 0000000000..2044be00f5 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-tstamp.manmisc.in @@ -0,0 +1,202 @@ +.\" +.\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP-TSTAMP @MAN_MISC_INFO@ "14 July 2020" +.SH NAME +pcap-tstamp \- packet time stamps in libpcap +.SH DESCRIPTION +When capturing traffic, each packet is given a time stamp representing, +for incoming packets, the arrival time of the packet and, for outgoing +packets, the transmission time of the packet. This time is an +approximation of the arrival or transmission time. If it is supplied by +the operating system running on the host on which the capture is being +done, there are several reasons why it might not precisely represent the +arrival or transmission time: +.IP +if the time stamp is applied to the packet when the networking stack +receives the packet, the networking stack might not see the packet until +an interrupt is delivered for the packet or a timer event causes the +networking device driver to poll for packets, and the time stamp might +not be applied until the packet has had some processing done by other +code in the networking stack, so there might be a significant delay +between the time when the last bit of the packet is received by the +capture device and when the networking stack time-stamps the packet; +.IP +the timer used to generate the time stamps might have low resolution, +for example, it might be a timer updated once per host operating system +timer tick, with the host operating system timer ticking once every few +milliseconds; +.IP +a high-resolution timer might use a counter that runs at a rate +dependent on the processor clock speed, and that clock speed might be +adjusted upwards or downwards over time and the timer might not be able +to compensate for all those adjustments; +.IP +the host operating system's clock might be adjusted over time to match a +time standard to which the host is being synchronized, which might be +done by temporarily slowing down or speeding up the clock or by making a +single adjustment; +.IP +different CPU cores on a multi-core or multi-processor system might be +running at different speeds, or might not have time counters all +synchronized, so packets time-stamped by different cores might not have +consistent time stamps; +.IP +some time sources, such as those that supply POSIX "seconds since the +Epoch" time, do not count leap seconds, meaning that the seconds +portion +.RB ( tv_sec ) +of the time stamp might not be incremented for a leap second, so that +the fraction-of-a-second part of the time stamp might roll over past +zero but the second part would not change, or the clock might run +slightly more slowly for a period before the leap second. +.LP +For these reasons, time differences between packet time stamps will not +necessarily accurately reflect the time differences between the receipt +or transmission times of the packets. +.LP +In addition, packets time-stamped by different cores might be +time-stamped in one order and added to the queue of packets for libpcap +to read in another order, so time stamps might not be monotonically +increasing. +.LP +Some capture devices on some platforms can provide time stamps for +packets; those time stamps are usually high-resolution time stamps, and +are usually applied to the packet when the first or last bit of the +packet arrives, and are thus more accurate than time stamps provided by +the host operating system. Those time stamps might not, however, be +synchronized with the host operating system's clock, so that, for +example, the time stamp of a packet might not correspond to the time +stamp of an event on the host triggered by the arrival of that packet. +If they are synchronized with the host operating system's clock, some of +the issues listed above with time stamps supplied by the host operating +system may also apply to time stamps supplied by the capture device. +.LP +Depending on the capture device and the software on the host, libpcap +might allow different types of time stamp to be used. The +.BR pcap_list_tstamp_types (3PCAP) +routine provides, for a packet capture handle created by +.BR pcap_create (3PCAP) +but not yet activated by +.BR pcap_activate (3PCAP), +a list of time stamp types supported by the capture device for that +handle. +The list might be empty, in which case no choice of time stamp type is +offered for that capture device. If the list is not empty, the +.BR pcap_set_tstamp_type (3PCAP) +routine can be used after a +.BR pcap_create () +call and before a +.BR pcap_activate () +call to specify the type of time stamp to be used on the device. +The time stamp types are listed here; the first value is the +.B #define +to use in code, the second value is the value returned by +.BR pcap_tstamp_type_val_to_name (3PCAP) +and accepted by +.BR pcap_tstamp_type_name_to_val (3PCAP). +.RS 5 +.TP 5 +.BR PCAP_TSTAMP_HOST " - " host +Time stamp provided by the host on which the capture is being done. The +precision of this time stamp is unspecified; it might or might not be +synchronized with the host operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_LOWPREC " - " host_lowprec +Time stamp provided by the host on which the capture is being done. +This is a low-precision time stamp, synchronized with the host operating +system's clock. +.TP 5 +.BR PCAP_TSTAMP_HOST_HIPREC " - " host_hiprec +Time stamp provided by the host on which the capture is being done. +This is a high-precision time stamp, synchronized with the host +operating system's clock. It might be more expensive to fetch than +.BR PCAP_TSTAMP_HOST_LOWPREC . +.TP 5 +.BR PCAP_TSTAMP_HOST_HIPREC_UNSYNCED " - " host_hiprec_unsynced +Time stamp provided by the host on which the capture is being done. +This is a high-precision time stamp, not synchronized with the host +operating system's clock. It might be more expensive to fetch than +.BR PCAP_TSTAMP_HOST_LOWPREC . +.TP 5 +.BR PCAP_TSTAMP_ADAPTER " - " adapter +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp, synchronized with the host +operating system's clock. +.TP 5 +.BR PCAP_TSTAMP_ADAPTER_UNSYNCED " - " adapter_unsynced +Time stamp provided by the network adapter on which the capture is being +done. This is a high-precision time stamp; it is not synchronized with +the host operating system's clock. +.RE +.LP +Time stamps synchronized with the system clock can go backwards, as the +system clock can go backwards. If a clock is not in sync with the +system clock, that could be because the system clock isn't keeping +accurate time, because the other clock isn't keeping accurate time, or +both. +.LP +Host-provided time stamps generally correspond to the time when the +time-stamping code sees the packet; this could be some unknown amount of +time after the first or last bit of the packet is received by the +network adapter, due to batching of interrupts for packet arrival, +queueing delays, etc.. +.LP +By default, when performing a live capture or reading from a savefile, +time stamps are supplied as seconds since January 1, 1970, 00:00:00 UTC, +and microseconds since that seconds value, even if higher-resolution +time stamps are available from the capture device or in the savefile. +If, when reading a savefile, the time stamps in the file have a higher +resolution than one microsecond, the additional digits of resolution are +discarded. +.LP +The +.BR pcap_set_tstamp_precision (3PCAP) +routine can be used after a +.BR pcap_create () +call and after a +.BR pcap_activate () +call to specify the resolution of the time stamps to get for the device. +If the hardware or software cannot supply a higher-resolution time +stamp, the +.BR pcap_set_tstamp_precision () +call will fail, and the time stamps supplied after the +.BR pcap_activate () +call will have microsecond resolution. +.LP +When opening a savefile, the +.BR \%pcap_open_offline_with_tstamp_precision (3PCAP) +and +.BR \%pcap_fopen_offline_with_tstamp_precision (3PCAP) +routines can be used to specify the resolution of time stamps to be read +from the file; if the time stamps in the file have a lower resolution, +the fraction-of-a-second portion of the time stamps will be scaled to +the specified resolution. +.LP +The +.BR pcap_get_tstamp_precision (3PCAP) +routine returns the resolution of time stamps that will be supplied; +when capturing packets, this does not reflect the actual precision of +the time stamp supplied by the hardware or operating system and, when +reading a savefile, this does not indicate the actual precision of time +stamps in the file. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap-types.h b/src/libpcap-1.10.5/pcap-types.h new file mode 100644 index 0000000000..7d0fe81ff7 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-types.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef pcap_types_h +#define pcap_types_h + +/* + * Get u_int defined, by hook or by crook. + */ +#ifdef _WIN32 + /* + * This defines u_int. + */ + #include +#else /* _WIN32 */ + /* + * This defines u_int, among other types. + */ + #include +#endif + +#endif /* pcap_types_h */ diff --git a/src/libpcap-1.10.5/pcap-usb-linux-common.h b/src/libpcap-1.10.5/pcap-usb-linux-common.h new file mode 100644 index 0000000000..333c6b6e0c --- /dev/null +++ b/src/libpcap-1.10.5/pcap-usb-linux-common.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-usb-linux-common.h - common code for everything that needs to + * deal with Linux USB captures, whether live or in a capture file; + * the later means that this is *not* Linux-only. + */ + +#include + +/* + * Return the sum of the two u_int arguments if that sum fits in a u_int, + * and return UINT_MAX otherwise. + */ +static inline u_int +u_int_sum(u_int a, u_int b) +{ + return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX); +} + +/* + * Is this a completion event for an isochronous transfer? + */ +static inline int +is_isochronous_transfer_completion(const pcap_usb_header_mmapped *hdr) +{ + return (hdr->transfer_type == URB_ISOCHRONOUS && + hdr->event_type == URB_COMPLETE && + (hdr->endpoint_number & URB_TRANSFER_IN)); +} + +/* + * Total length of the pseudo-header, including the isochronous + * descriptors. + */ +static inline uint32_t +iso_pseudo_header_len(const pcap_usb_header_mmapped *usb_hdr) +{ + return (sizeof(pcap_usb_header_mmapped) + + usb_hdr->ndesc * sizeof (usb_isodesc)); +} + +/* + * Calculate the packet length for a "this is complete" incoming + * isochronous transfer event. + * + * Calculating that from hdr->urb_len is not correct, because the + * data is not contiguous, and the isochroous descriptors show how + * it's scattered. + */ +static inline u_int +incoming_isochronous_transfer_completed_len(struct pcap_pkthdr *phdr, + const u_char *bp) +{ + const pcap_usb_header_mmapped *hdr; + u_int bytes_left; + const usb_isodesc *descs; + u_int pre_truncation_data_len; + + /* + * All callers of this routine must ensure that pkth->caplen is + * >= sizeof (pcap_usb_header_mmapped). + */ + bytes_left = phdr->caplen; + bytes_left -= sizeof (pcap_usb_header_mmapped); + + hdr = (const pcap_usb_header_mmapped *) bp; + descs = (const usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped)); + + /* + * Find the end of the last chunk of data in the buffer + * referred to by the isochronous descriptors; that indicates + * how far into the buffer the data would have gone. + * + * Make sure we don't run past the end of the captured data + * while processing the isochronous descriptors. + */ + pre_truncation_data_len = 0; + for (uint32_t desc = 0; + desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc); + desc++, bytes_left -= sizeof (usb_isodesc)) { + u_int desc_end; + + if (descs[desc].len != 0) { + /* + * Compute the end offset of the data + * for this descriptor, i.e. the offset + * of the byte after the data. Clamp + * the sum at UINT_MAX, so that it fits + * in a u_int. + */ + desc_end = u_int_sum(descs[desc].offset, + descs[desc].len); + if (desc_end > pre_truncation_data_len) + pre_truncation_data_len = desc_end; + } + } + + /* + * Return the sum of the total header length (memory-mapped + * header and ISO descriptors) and the data length, clamped + * to UINT_MAX. + * + * We've made sure that the number of descriptors is + * <= USB_MAXDESC, so we know that the total size, + * in bytes, of the descriptors fits in a 32-bit + * integer. + */ + return (u_int_sum(iso_pseudo_header_len(hdr), pre_truncation_data_len)); +} diff --git a/src/libpcap-1.10.5/pcap-usb-linux.c b/src/libpcap-1.10.5/pcap-usb-linux.c new file mode 100644 index 0000000000..bc39b1db44 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-usb-linux.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * USB sniffing API implementation for Linux platform + * By Paolo Abeni + * Modifications: Kris Katterjohn + * + */ + +#include + +#include "pcap/usb.h" +#include "pcap-int.h" +#include "pcap-usb-linux.h" +#include "pcap-usb-linux-common.h" + +#include "extract.h" + +#ifdef NEED_STRERROR_H +#include "strerror.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LINUX_USBDEVICE_FS_H +/* + * We might need to define __user for + * . + */ +#ifdef HAVE_LINUX_COMPILER_H +#include +#endif /* HAVE_LINUX_COMPILER_H */ +#include +#endif /* HAVE_LINUX_USBDEVICE_FS_H */ + +#include "diag-control.h" + +#define USB_IFACE "usbmon" + +#define USBMON_DEV_PREFIX "usbmon" +#define USBMON_DEV_PREFIX_LEN (sizeof USBMON_DEV_PREFIX - 1) +#define USB_LINE_LEN 4096 + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htols(s) s +#define htoll(l) l +#define htol64(ll) ll +#else +#define htols(s) bswap_16(s) +#define htoll(l) bswap_32(l) +#define htol64(ll) bswap_64(ll) +#endif + +struct mon_bin_stats { + uint32_t queued; + uint32_t dropped; +}; + +struct mon_bin_get { + pcap_usb_header *hdr; + void *data; + size_t data_len; /* Length of data (can be zero) */ +}; + +struct mon_bin_mfetch { + int32_t *offvec; /* Vector of events fetched */ + int32_t nfetch; /* Number of events to fetch (out: fetched) */ + int32_t nflush; /* Number of events to flush */ +}; + +#define MON_IOC_MAGIC 0x92 + +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +#define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr) +#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) +#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) +#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) +#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) +#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) + +#define MON_BIN_SETUP 0x1 /* setup hdr is present*/ +#define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ +#define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ +#define MON_BIN_ERROR 0x8 + +/* + * Private data for capturing on Linux USB. + */ +struct pcap_usb_linux { + u_char *mmapbuf; /* memory-mapped region pointer */ + size_t mmapbuflen; /* size of region */ + int bus_index; + u_int packets_read; +}; + +/* forward declaration */ +static int usb_activate(pcap_t *); +static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *); +static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *); +static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *); +static int usb_inject_linux(pcap_t *, const void *, int); +static int usb_setdirection_linux(pcap_t *, pcap_direction_t); +static void usb_cleanup_linux_mmap(pcap_t *); + +/* facility to add an USB device to the device list*/ +static int +usb_dev_add(pcap_if_list_t *devlistp, int n, char *err_str) +{ + char dev_name[10]; + char dev_descr[30]; + snprintf(dev_name, 10, USB_IFACE"%d", n); + /* + * XXX - is there any notion of "up" and "running"? + */ + if (n == 0) { + /* + * As this refers to all buses, there's no notion of + * "connected" vs. "disconnected", as that's a property + * that would apply to a particular USB interface. + */ + if (pcapint_add_dev(devlistp, dev_name, + PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, + "Raw USB traffic, all USB buses", err_str) == NULL) + return -1; + } else { + /* + * XXX - is there a way to determine whether anything's + * plugged into this bus interface or not, and set + * PCAP_IF_CONNECTION_STATUS_CONNECTED or + * PCAP_IF_CONNECTION_STATUS_DISCONNECTED? + */ + snprintf(dev_descr, 30, "Raw USB traffic, bus number %d", n); + if (pcapint_add_dev(devlistp, dev_name, 0, dev_descr, err_str) == NULL) + return -1; + } + + return 0; +} + +int +usb_findalldevs(pcap_if_list_t *devlistp, char *err_str) +{ + struct dirent* data; + int ret = 0; + DIR* dir; + int n; + char* name; + + /* + * We require 2.6.27 or later kernels, so we have binary-mode support. + * The devices are of the form /dev/usbmon{N}. + * Open /dev and scan it. + */ + dir = opendir("/dev"); + if (dir != NULL) { + while ((ret == 0) && ((data = readdir(dir)) != 0)) { + name = data->d_name; + + /* + * Is this a usbmon device? + */ + if (strncmp(name, USBMON_DEV_PREFIX, + USBMON_DEV_PREFIX_LEN) != 0) + continue; /* no */ + + /* + * What's the device number? + */ + if (sscanf(&name[USBMON_DEV_PREFIX_LEN], "%d", &n) == 0) + continue; /* failed */ + + ret = usb_dev_add(devlistp, n, err_str); + } + + closedir(dir); + } + return 0; +} + +/* + * Matches what's in mon_bin.c in the Linux kernel. + */ +#define MIN_RING_SIZE (8*1024) +#define MAX_RING_SIZE (1200*1024) + +static int +usb_set_ring_size(pcap_t* handle, int header_size) +{ + /* + * A packet from binary usbmon has: + * + * 1) a fixed-length header, of size header_size; + * 2) descriptors, for isochronous transfers; + * 3) the payload. + * + * The kernel buffer has a size, defaulting to 300KB, with a + * minimum of 8KB and a maximum of 1200KB. The size is set with + * the MON_IOCT_RING_SIZE ioctl; the size passed in is rounded up + * to a page size. + * + * No more than {buffer size}/5 bytes worth of payload is saved. + * Therefore, if we subtract the fixed-length size from the + * snapshot length, we have the biggest payload we want (we + * don't worry about the descriptors - if we have descriptors, + * we'll just discard the last bit of the payload to get it + * to fit). We multiply that result by 5 and set the buffer + * size to that value. + */ + int ring_size; + + if (handle->snapshot < header_size) + handle->snapshot = header_size; + /* The maximum snapshot size is small enough that this won't overflow */ + ring_size = (handle->snapshot - header_size) * 5; + + /* + * Will this get an error? + * (There's no way to query the minimum or maximum, so we just + * copy the value from the kernel source. We don't round it + * up to a multiple of the page size.) + */ + if (ring_size > MAX_RING_SIZE) { + /* + * Yes. Lower the ring size to the maximum, and set the + * snapshot length to the value that would give us a + * maximum-size ring. + */ + ring_size = MAX_RING_SIZE; + handle->snapshot = header_size + (MAX_RING_SIZE/5); + } else if (ring_size < MIN_RING_SIZE) { + /* + * Yes. Raise the ring size to the minimum, but leave + * the snapshot length unchanged, so we show the + * callback no more data than specified by the + * snapshot length. + */ + ring_size = MIN_RING_SIZE; + } + + if (ioctl(handle->fd, MON_IOCT_RING_SIZE, ring_size) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't set ring size from fd %d", handle->fd); + return -1; + } + return ring_size; +} + +static +int usb_mmap(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + int len; + + /* + * Attempt to set the ring size as appropriate for the snapshot + * length, reducing the snapshot length if that'd make the ring + * bigger than the kernel supports. + */ + len = usb_set_ring_size(handle, (int)sizeof(pcap_usb_header_mmapped)); + if (len == -1) { + /* Failed. Fall back on non-memory-mapped access. */ + return 0; + } + + handlep->mmapbuflen = len; + handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ, + MAP_SHARED, handle->fd, 0); + if (handlep->mmapbuf == MAP_FAILED) { + /* + * Failed. We don't treat that as a fatal error, we + * just try to fall back on non-memory-mapped access. + */ + return 0; + } + return 1; +} + +#ifdef HAVE_LINUX_USBDEVICE_FS_H + +#define CTRL_TIMEOUT (5*1000) /* milliseconds */ + +#define USB_DIR_IN 0x80 +#define USB_TYPE_STANDARD 0x00 +#define USB_RECIP_DEVICE 0x00 + +#define USB_REQ_GET_DESCRIPTOR 6 + +#define USB_DT_DEVICE 1 +#define USB_DT_CONFIG 2 + +#define USB_DEVICE_DESCRIPTOR_SIZE 18 +#define USB_CONFIG_DESCRIPTOR_SIZE 9 + +/* probe the descriptors of the devices attached to the bus */ +/* the descriptors will end up in the captured packet stream */ +/* and be decoded by external apps like wireshark */ +/* without these identifying probes packet data can't be fully decoded */ +static void +probe_devices(int bus) +{ + struct usbdevfs_ctrltransfer ctrl; + struct dirent* data; + int ret = 0; + char busdevpath[sizeof("/dev/bus/usb/000/") + NAME_MAX]; + DIR* dir; + uint8_t descriptor[USB_DEVICE_DESCRIPTOR_SIZE]; + uint8_t configdesc[USB_CONFIG_DESCRIPTOR_SIZE]; + + /* scan usb bus directories for device nodes */ + snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d", bus); + dir = opendir(busdevpath); + if (!dir) + return; + + while ((ret >= 0) && ((data = readdir(dir)) != 0)) { + int fd; + char* name = data->d_name; + + if (name[0] == '.') + continue; + + snprintf(busdevpath, sizeof(busdevpath), "/dev/bus/usb/%03d/%s", bus, data->d_name); + + fd = open(busdevpath, O_RDWR); + if (fd == -1) + continue; + + /* + * Sigh. Different kernels have different member names + * for this structure. + */ +#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; + ctrl.wValue = USB_DT_DEVICE << 8; + ctrl.wIndex = 0; + ctrl.wLength = sizeof(descriptor); +#else + ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + ctrl.request = USB_REQ_GET_DESCRIPTOR; + ctrl.value = USB_DT_DEVICE << 8; + ctrl.index = 0; + ctrl.length = sizeof(descriptor); +#endif + ctrl.data = descriptor; + ctrl.timeout = CTRL_TIMEOUT; + + ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); + + /* Request CONFIGURATION descriptor alone to know wTotalLength */ +#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + ctrl.wValue = USB_DT_CONFIG << 8; + ctrl.wLength = sizeof(configdesc); +#else + ctrl.value = USB_DT_CONFIG << 8; + ctrl.length = sizeof(configdesc); +#endif + ctrl.data = configdesc; + ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); + if (ret >= 0) { + uint16_t wtotallength; + wtotallength = EXTRACT_LE_U_2(&configdesc[2]); +#ifdef HAVE_STRUCT_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE + ctrl.wLength = wtotallength; +#else + ctrl.length = wtotallength; +#endif + ctrl.data = malloc(wtotallength); + if (ctrl.data) { + ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); + free(ctrl.data); + } + } + close(fd); + } + closedir(dir); +} +#endif /* HAVE_LINUX_USBDEVICE_FS_H */ + +pcap_t * +usb_create(const char *device, char *ebuf, int *is_ours) +{ + const char *cp; + char *cpend; + long devnum; + pcap_t *p; + + /* Does this look like a USB monitoring device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with USB_IFACE? */ + if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) { + /* Nope, doesn't begin with USB_IFACE */ + *is_ours = 0; + return NULL; + } + /* Yes - is USB_IFACE followed by a number? */ + cp += sizeof USB_IFACE - 1; + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = PCAP_CREATE_COMMON(ebuf, struct pcap_usb_linux); + if (p == NULL) + return (NULL); + + p->activate_op = usb_activate; + return (p); +} + +static int +usb_activate(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + char full_path[USB_LINE_LEN]; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) + handle->snapshot = MAXIMUM_SNAPLEN; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = handle->snapshot; + handle->offset = 0; + handle->linktype = DLT_USB_LINUX; + + handle->inject_op = usb_inject_linux; + handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = usb_setdirection_linux; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcapint_getnonblock_fd; + handle->setnonblock_op = pcapint_setnonblock_fd; + + /*get usb bus index from device name */ + if (sscanf(handle->opt.device, USB_IFACE"%d", &handlep->bus_index) != 1) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't get USB bus index from %s", handle->opt.device); + return PCAP_ERROR; + } + + /* + * We require 2.6.27 or later kernels, so we have binary-mode support. + * Try to open the binary interface. + */ + snprintf(full_path, USB_LINE_LEN, "/dev/"USBMON_DEV_PREFIX"%d", + handlep->bus_index); + handle->fd = open(full_path, O_RDONLY, 0); + if (handle->fd < 0) + { + /* + * The attempt failed; why? + */ + switch (errno) { + + case ENOENT: + /* + * The device doesn't exist. + * That could either mean that there's + * no support for monitoring USB buses + * (which probably means "the usbmon + * module isn't loaded") or that there + * is but that *particular* device + * doesn't exist (no "scan all buses" + * device if the bus index is 0, no + * such bus if the bus index isn't 0). + * + * For now, don't provide an error message; + * if we can determine what the particular + * problem is, we should report that. + */ + handle->errbuf[0] = '\0'; + return PCAP_ERROR_NO_SUCH_DEVICE; + + case EACCES: + /* + * We didn't have permission to open it. + */ +DIAG_OFF_FORMAT_TRUNCATION + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with EACCES - root privileges may be required", + full_path); +DIAG_ON_FORMAT_TRUNCATION + return PCAP_ERROR_PERM_DENIED; + + default: + /* + * Something went wrong. + */ + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't open USB bus file %s", full_path); + return PCAP_ERROR; + } + } + + if (handle->opt.rfmon) + { + /* + * Monitor mode doesn't apply to USB devices. + */ + close(handle->fd); + return PCAP_ERROR_RFMON_NOTSUP; + } + + /* try to use fast mmap access */ + if (usb_mmap(handle)) + { + /* We succeeded. */ + handle->linktype = DLT_USB_LINUX_MMAPPED; + handle->stats_op = usb_stats_linux_bin; + handle->read_op = usb_read_linux_mmap; + handle->cleanup_op = usb_cleanup_linux_mmap; +#ifdef HAVE_LINUX_USBDEVICE_FS_H + probe_devices(handlep->bus_index); +#endif + + /* + * "handle->fd" is a real file, so + * "select()" and "poll()" work on it. + */ + handle->selectable_fd = handle->fd; + return 0; + } + + /* + * We failed; try plain binary interface access. + * + * Attempt to set the ring size as appropriate for + * the snapshot length, reducing the snapshot length + * if that'd make the ring bigger than the kernel + * supports. + */ + if (usb_set_ring_size(handle, (int)sizeof(pcap_usb_header)) == -1) { + /* Failed. */ + close(handle->fd); + return PCAP_ERROR; + } + handle->stats_op = usb_stats_linux_bin; + handle->read_op = usb_read_linux_bin; +#ifdef HAVE_LINUX_USBDEVICE_FS_H + probe_devices(handlep->bus_index); +#endif + + /* + * "handle->fd" is a real file, so "select()" and "poll()" + * work on it. + */ + handle->selectable_fd = handle->fd; + + /* for plain binary access and text access we need to allocate the read + * buffer */ + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + close(handle->fd); + return PCAP_ERROR; + } + return 0; +} + +static int +usb_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Packet injection is not supported on USB devices"); + return (-1); +} + +static int +usb_setdirection_linux(pcap_t *p, pcap_direction_t d) +{ + /* + * It's guaranteed, at this point, that d is a valid + * direction value. + */ + p->direction = d; + return 0; +} + +static int +usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) +{ + struct pcap_usb_linux *handlep = handle->priv; + int ret; + struct mon_bin_stats st; + ret = ioctl(handle->fd, MON_IOCG_STATS, &st); + if (ret < 0) + { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't read stats from fd %d", handle->fd); + return -1; + } + + stats->ps_recv = handlep->packets_read + st.queued; + stats->ps_drop = st.dropped; + stats->ps_ifdrop = 0; + return 0; +} + +/* + * see /Documentation/usb/usbmon.txt and + * /drivers/usb/mon/mon_bin.c binary ABI + */ +static int +usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct pcap_usb_linux *handlep = handle->priv; + struct mon_bin_get info; + int ret; + struct pcap_pkthdr pkth; + u_int clen = handle->snapshot - sizeof(pcap_usb_header); + + /* the usb header is going to be part of 'packet' data*/ + info.hdr = (pcap_usb_header*) handle->buffer; + info.data = (u_char *)handle->buffer + sizeof(pcap_usb_header); + info.data_len = clen; + + /* ignore interrupt system call errors */ + do { + ret = ioctl(handle->fd, MON_IOCX_GET, &info); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + if (ret < 0) + { + if (errno == EAGAIN) + return 0; /* no data there */ + + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't read from fd %d", handle->fd); + return -1; + } + + /* + * info.hdr->data_len is the number of bytes of isochronous + * descriptors (if any) plus the number of bytes of data + * provided. There are no isochronous descriptors here, + * because we're using the old 48-byte header. + * + * If info.hdr->data_flag is non-zero, there's no URB data; + * info.hdr->urb_len is the size of the buffer into which + * data is to be placed; it does not represent the amount + * of data transferred. If info.hdr->data_flag is zero, + * there is URB data, and info.hdr->urb_len is the number + * of bytes transmitted or received; it doesn't include + * isochronous descriptors. + * + * The kernel may give us more data than the snaplen; if it did, + * reduce the data length so that the total number of bytes we + * tell our client we have is not greater than the snaplen. + */ + if (info.hdr->data_len < clen) + clen = info.hdr->data_len; + info.hdr->data_len = clen; + pkth.caplen = sizeof(pcap_usb_header) + clen; + if (info.hdr->data_flag) { + /* + * No data; just base the original length on + * info.hdr->data_len (so that it's >= the captured + * length). + */ + pkth.len = sizeof(pcap_usb_header) + info.hdr->data_len; + } else { + /* + * We got data; base the original length on + * info.hdr->urb_len, so that it includes data + * discarded by the USB monitor device due to + * its buffer being too small. + */ + pkth.len = sizeof(pcap_usb_header) + info.hdr->urb_len; + } + pkth.ts.tv_sec = (time_t)info.hdr->ts_sec; + pkth.ts.tv_usec = info.hdr->ts_usec; + + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, handle->buffer, + pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, handle->buffer); + return 1; + } + + return 0; /* didn't pass filter */ +} + +/* + * see /Documentation/usb/usbmon.txt and + * /drivers/usb/mon/mon_bin.c binary ABI + */ +#define VEC_SIZE 32 +static int +usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) +{ + struct pcap_usb_linux *handlep = handle->priv; + struct mon_bin_mfetch fetch; + int32_t vec[VEC_SIZE]; + struct pcap_pkthdr pkth; + u_char *bp; + pcap_usb_header_mmapped* hdr; + int nflush = 0; + int packets = 0; + u_int clen, max_clen; + + max_clen = handle->snapshot - sizeof(pcap_usb_header_mmapped); + + for (;;) { + int i, ret; + int limit; + + if (PACKET_COUNT_IS_UNLIMITED(max_packets)) { + /* + * There's no limit on the number of packets + * to process, so try to fetch VEC_SIZE packets. + */ + limit = VEC_SIZE; + } else { + /* + * Try to fetch as many packets as we have left + * to process, or VEC_SIZE packets, whichever + * is less. + * + * At this point, max_packets > 0 (otherwise, + * PACKET_COUNT_IS_UNLIMITED(max_packets) + * would be true) and max_packets > packets + * (packet starts out as 0, and the test + * at the bottom of the loop exits if + * max_packets <= packets), so limit is + * guaranteed to be > 0. + */ + limit = max_packets - packets; + if (limit > VEC_SIZE) + limit = VEC_SIZE; + } + + /* + * Try to fetch as many events as possible, up to + * the limit, and flush the events we've processed + * earlier (nflush) - MON_IOCX_MFETCH does both + * (presumably to reduce the number of system + * calls in loops like this). + */ + fetch.offvec = vec; + fetch.nfetch = limit; + fetch.nflush = nflush; + /* ignore interrupt system call errors */ + do { + ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + if (ret < 0) + { + if (errno == EAGAIN) + return 0; /* no data there */ + + pcapint_fmt_errmsg_for_errno(handle->errbuf, + PCAP_ERRBUF_SIZE, errno, "Can't mfetch fd %d", + handle->fd); + return -1; + } + + /* keep track of processed events, we will flush them later */ + nflush = fetch.nfetch; + for (i=0; immapbuf[vec[i]]; + + /* That begins with a metadata header */ + hdr = (pcap_usb_header_mmapped*) bp; + + /* discard filler */ + if (hdr->event_type == '@') + continue; + + /* + * hdr->data_len is the number of bytes of + * isochronous descriptors (if any) plus the + * number of bytes of data provided. + * + * If hdr->data_flag is non-zero, there's no + * URB data; hdr->urb_len is the size of the + * buffer into which data is to be placed; it does + * not represent the amount of data transferred. + * If hdr->data_flag is zero, there is URB data, + * and hdr->urb_len is the number of bytes + * transmitted or received; it doesn't include + * isochronous descriptors. + * + * The kernel may give us more data than the + * snaplen; if it did, reduce the data length + * so that the total number of bytes we + * tell our client we have is not greater than + * the snaplen. + */ + clen = max_clen; + if (hdr->data_len < clen) + clen = hdr->data_len; + pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen; + if (hdr->data_flag) { + /* + * No data; just base the original length + * on hdr->data_len (so that it's >= the + * captured length). Clamp the result + * at UINT_MAX, so it fits in an unsigned + * int. + */ + pkth.len = u_int_sum(sizeof(pcap_usb_header_mmapped), + hdr->data_len); + } else { + /* + * We got data. + */ + if (is_isochronous_transfer_completion(hdr)) { + /* + * For isochronous transfer completion + * events, hdr->urb_len doesn't take + * into account the way the data is + * put into the buffer, as it doesn't + * count any padding between the + * chunks of isochronous data, so + * we have to calculate the amount + * of data from the isochronous + * descriptors. + */ + pkth.len = incoming_isochronous_transfer_completed_len(&pkth, bp); + } else { + /* + * For everything else, the original + * data length is just the length of + * the memory-mapped Linux USB header + * plus hdr->urb_len; we use + * hdr->urb_len so that it includes + * data discarded by the USB monitor + * device due to its buffer being + * too small. Clamp the result at + * UINT_MAX, so it fits in an + * unsigned int. + */ + pkth.len = u_int_sum(sizeof(pcap_usb_header_mmapped), + hdr->urb_len); + } + } + pkth.ts.tv_sec = (time_t)hdr->ts_sec; + pkth.ts.tv_usec = hdr->ts_usec; + + if (handle->fcode.bf_insns == NULL || + pcapint_filter(handle->fcode.bf_insns, (u_char*) hdr, + pkth.len, pkth.caplen)) { + handlep->packets_read++; + callback(user, &pkth, (u_char*) hdr); + packets++; + } + } + + /* + * If max_packets specifies "unlimited", we stop after + * the first chunk. + */ + if (PACKET_COUNT_IS_UNLIMITED(max_packets) || + (packets >= max_packets)) + break; + } + + /* flush pending events*/ + if (ioctl(handle->fd, MON_IOCH_MFLUSH, nflush) == -1) { + pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't mflush fd %d", handle->fd); + return -1; + } + return packets; +} + +static void +usb_cleanup_linux_mmap(pcap_t* handle) +{ + struct pcap_usb_linux *handlep = handle->priv; + + /* if we have a memory-mapped buffer, unmap it */ + if (handlep->mmapbuf != NULL) { + munmap(handlep->mmapbuf, handlep->mmapbuflen); + handlep->mmapbuf = NULL; + } + pcapint_cleanup_live_common(handle); +} diff --git a/src/libpcap-1.10.5/pcap-usb-linux.h b/src/libpcap-1.10.5/pcap-usb-linux.h new file mode 100644 index 0000000000..3ddc12f484 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-usb-linux.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * USB sniffing API implementation for Linux platform + * By Paolo Abeni + */ + +/* + * Prototypes for USB-related functions + */ +int usb_findalldevs(pcap_if_list_t *devlistp, char *err_str); +pcap_t *usb_create(const char *device, char *ebuf, int *is_ours); diff --git a/src/libpcap-1.10.5/pcap-util.c b/src/libpcap-1.10.5/pcap-util.c new file mode 100644 index 0000000000..1aa8e13e32 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-util.c @@ -0,0 +1,627 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-util.c - common code for various files + */ + +#include + +#include + +#include "pcap/can_socketcan.h" +#include "pcap/sll.h" +#include "pcap/usb.h" +#include "pcap/nflog.h" + +#include "pcap-int.h" +#include "extract.h" +#include "pcap-usb-linux-common.h" + +#include "pcap-util.h" +#include "pflog.h" + +/* + * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields + * that are saved in host byte order. + * + * When reading a DLT_PFLOG packet, we need to convert those fields from + * the byte order of the host that wrote the file to this host's byte + * order. + */ +static void +swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + u_int pfloghdr_length; + struct pfloghdr *pflhdr = (struct pfloghdr *)buf; + + if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) || + length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { + /* Not enough data to have the uid field */ + return; + } + + pfloghdr_length = pflhdr->length; + + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) { + /* Header doesn't include uid field */ + return; + } + pflhdr->uid = SWAPLONG(pflhdr->uid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) || + length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { + /* Not enough data to have the pid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) { + /* Header doesn't include pid field */ + return; + } + pflhdr->pid = SWAPLONG(pflhdr->pid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) || + length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { + /* Not enough data to have the rule_uid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) { + /* Header doesn't include rule_uid field */ + return; + } + pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid); + + if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) || + length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { + /* Not enough data to have the rule_pid field */ + return; + } + if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) { + /* Header doesn't include rule_pid field */ + return; + } + pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid); +} + +/* + * Linux cooked capture packets with a protocol type of LINUX_SLL_P_CAN or + * LINUX_SLL_P_CANFD have SocketCAN CAN classic/CAN FD headers in front + * of the payload,with the CAN ID being in the byte order of the host + * that wrote the packet, and Linux cooked capture packets with a protocol + * type of LINUX_SLL_P_CANXL have SocketCAN CAN XL headers in front of the + * payload with the protocol/VCID field, the payload length, and the + * acceptance field in the byte order of the host that wrote the packet. + * + * When reading a Linux cooked capture packet, we need to check for those + * packets and, if the byte order host that wrote the packet, as + * indicated by the byte order of the pcap file or pcapng section + * containing the packet, is the opposite of our byte order, convert + * the header files to our byte order by byte-swapping them. + */ +static void +swap_socketcan_header(uint16_t protocol, u_int caplen, u_int length, + u_char *buf) +{ + pcap_can_socketcan_hdr *hdrp; + pcap_can_socketcan_xl_hdr *xl_hdrp; + + switch (protocol) { + + case LINUX_SLL_P_CAN: + case LINUX_SLL_P_CANFD: + /* + * CAN classic/CAN FD packet; fix up the packet's header + * by byte-swapping the CAN ID field. + */ + hdrp = (pcap_can_socketcan_hdr *)buf; + if (caplen < (u_int) (offsetof(pcap_can_socketcan_hdr, can_id) + sizeof hdrp->can_id) || + length < (u_int) (offsetof(pcap_can_socketcan_hdr, can_id) + sizeof hdrp->can_id)) { + /* Not enough data to have the can_id field */ + return; + } + hdrp->can_id = SWAPLONG(hdrp->can_id); + break; + + case LINUX_SLL_P_CANXL: + /* + * CAN XL packet; fix up the packet's header by + * byte-swapping the priority/VCID field, the + * payload length, and the acceptance field. + */ + xl_hdrp = (pcap_can_socketcan_xl_hdr *)buf; + if (caplen < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, priority_vcid) + sizeof xl_hdrp->priority_vcid) || + length < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, priority_vcid) + sizeof xl_hdrp->priority_vcid)) { + /* Not enough data to have the priority_vcid field */ + return; + } + xl_hdrp->priority_vcid = SWAPLONG(xl_hdrp->priority_vcid); + if (caplen < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, payload_length) + sizeof xl_hdrp->payload_length) || + length < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, payload_length) + sizeof xl_hdrp->payload_length)) { + /* Not enough data to have the payload_length field */ + return; + } + xl_hdrp->payload_length = SWAPSHORT(xl_hdrp->payload_length); + if (caplen < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, acceptance_field) + sizeof xl_hdrp->acceptance_field) || + length < (u_int) (offsetof(pcap_can_socketcan_xl_hdr, acceptance_field) + sizeof xl_hdrp->acceptance_field)) { + /* Not enough data to have the acceptance_field field */ + return; + } + xl_hdrp->acceptance_field = SWAPLONG(xl_hdrp->acceptance_field); + break; + + default: + /* + * Not a CAN packet; nothing to do. + */ + break; + } +} + +/* + * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or + * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload, + * with the CAN ID being in host byte order. + * + * When reading a DLT_LINUX_SLL packet, we need to check for those + * packets and convert the CAN ID from the byte order of the host that + * wrote the file to this host's byte order. + */ +static void +swap_linux_sll_socketcan_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + struct sll_header *shdr = (struct sll_header *)buf; + + if (caplen < (u_int) sizeof(struct sll_header) || + length < (u_int) sizeof(struct sll_header)) { + /* Not enough data to have the protocol field */ + return; + } + + /* + * Byte-swap what needs to be byte-swapped. + */ + swap_socketcan_header(EXTRACT_BE_U_2(&shdr->sll_protocol), + caplen - (u_int) sizeof(struct sll_header), + length - (u_int) sizeof(struct sll_header), + buf + sizeof(struct sll_header)); +} + +/* + * The same applies for DLT_LINUX_SLL2. + */ +static void +swap_linux_sll2_socketcan_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_int caplen = hdr->caplen; + u_int length = hdr->len; + struct sll2_header *shdr = (struct sll2_header *)buf; + + if (caplen < (u_int) sizeof(struct sll2_header) || + length < (u_int) sizeof(struct sll2_header)) { + /* Not enough data to have the protocol field */ + return; + } + + /* + * Byte-swap what needs to be byte-swapped. + */ + swap_socketcan_header(EXTRACT_BE_U_2(&shdr->sll2_protocol), + caplen - (u_int) sizeof(struct sll2_header), + length - (u_int) sizeof(struct sll2_header), + buf + sizeof(struct sll2_header)); +} + +/* + * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host + * byte order when capturing (it's supplied directly from a + * memory-mapped buffer shared by the kernel). + * + * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we + * need to convert it from the byte order of the host that wrote the + * file to this host's byte order. + */ +static void +swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, + int header_len_64_bytes) +{ + pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; + bpf_u_int32 offset = 0; + + /* + * "offset" is the offset *past* the field we're swapping; + * we skip the field *before* checking to make sure + * the captured data length includes the entire field. + */ + + /* + * The URB id is a totally opaque value; do we really need to + * convert it to the reading host's byte order??? + */ + offset += 8; /* skip past id */ + if (hdr->caplen < offset) + return; + uhdr->id = SWAPLL(uhdr->id); + + offset += 4; /* skip past various 1-byte fields */ + + offset += 2; /* skip past bus_id */ + if (hdr->caplen < offset) + return; + uhdr->bus_id = SWAPSHORT(uhdr->bus_id); + + offset += 2; /* skip past various 1-byte fields */ + + offset += 8; /* skip past ts_sec */ + if (hdr->caplen < offset) + return; + uhdr->ts_sec = SWAPLL(uhdr->ts_sec); + + offset += 4; /* skip past ts_usec */ + if (hdr->caplen < offset) + return; + uhdr->ts_usec = SWAPLONG(uhdr->ts_usec); + + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + uhdr->status = SWAPLONG(uhdr->status); + + offset += 4; /* skip past urb_len */ + if (hdr->caplen < offset) + return; + uhdr->urb_len = SWAPLONG(uhdr->urb_len); + + offset += 4; /* skip past data_len */ + if (hdr->caplen < offset) + return; + uhdr->data_len = SWAPLONG(uhdr->data_len); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + offset += 4; /* skip past s.iso.error_count */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count); + + offset += 4; /* skip past s.iso.numdesc */ + if (hdr->caplen < offset) + return; + uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc); + } else + offset += 8; /* skip USB setup header */ + + /* + * With the old header, there are no isochronous descriptors + * after the header. + * + * With the new header, the actual number of descriptors in + * the header is not s.iso.numdesc, it's ndesc - only the + * first N descriptors, for some value of N, are put into + * the header, and ndesc is set to the actual number copied. + * In addition, if s.iso.numdesc is negative, no descriptors + * are captured, and ndesc is set to 0. + */ + if (header_len_64_bytes) { + /* + * This is either the "version 1" header, with + * 16 bytes of additional fields at the end, or + * a "version 0" header from a memory-mapped + * capture, with 16 bytes of zeroed-out padding + * at the end. Byte swap them as if this were + * a "version 1" header. + */ + offset += 4; /* skip past interval */ + if (hdr->caplen < offset) + return; + uhdr->interval = SWAPLONG(uhdr->interval); + + offset += 4; /* skip past start_frame */ + if (hdr->caplen < offset) + return; + uhdr->start_frame = SWAPLONG(uhdr->start_frame); + + offset += 4; /* skip past xfer_flags */ + if (hdr->caplen < offset) + return; + uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); + + offset += 4; /* skip past ndesc */ + if (hdr->caplen < offset) + return; + uhdr->ndesc = SWAPLONG(uhdr->ndesc); + + if (uhdr->transfer_type == URB_ISOCHRONOUS) { + /* swap the values in struct linux_usb_isodesc */ + usb_isodesc *pisodesc; + uint32_t i; + + pisodesc = (usb_isodesc *)(void *)(buf+offset); + for (i = 0; i < uhdr->ndesc; i++) { + offset += 4; /* skip past status */ + if (hdr->caplen < offset) + return; + pisodesc->status = SWAPLONG(pisodesc->status); + + offset += 4; /* skip past offset */ + if (hdr->caplen < offset) + return; + pisodesc->offset = SWAPLONG(pisodesc->offset); + + offset += 4; /* skip past len */ + if (hdr->caplen < offset) + return; + pisodesc->len = SWAPLONG(pisodesc->len); + + offset += 4; /* skip past padding */ + + pisodesc++; + } + } + } +} + +/* + * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order + * data. They begin with a fixed-length header with big-endian fields, + * followed by a set of TLVs, where the type and length are in host + * byte order but the values are either big-endian or are a raw byte + * sequence that's the same regardless of the host's byte order. + * + * When reading a DLT_NFLOG packet, we need to convert the type and + * length values from the byte order of the host that wrote the file + * to the byte order of this host. + */ +static void +swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf) +{ + u_char *p = buf; + nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf; + nflog_tlv_t *tlv; + u_int caplen = hdr->caplen; + u_int length = hdr->len; + u_int size; + + if (caplen < (u_int) sizeof(nflog_hdr_t) || + length < (u_int) sizeof(nflog_hdr_t)) { + /* Not enough data to have any TLVs. */ + return; + } + + if (nfhdr->nflog_version != 0) { + /* Unknown NFLOG version */ + return; + } + + length -= sizeof(nflog_hdr_t); + caplen -= sizeof(nflog_hdr_t); + p += sizeof(nflog_hdr_t); + + while (caplen >= sizeof(nflog_tlv_t)) { + tlv = (nflog_tlv_t *) p; + + /* Swap the type and length. */ + tlv->tlv_type = SWAPSHORT(tlv->tlv_type); + tlv->tlv_length = SWAPSHORT(tlv->tlv_length); + + /* Get the length of the TLV. */ + size = tlv->tlv_length; + if (size % 4 != 0) + size += 4 - size % 4; + + /* Is the TLV's length less than the minimum? */ + if (size < sizeof(nflog_tlv_t)) { + /* Yes. Give up now. */ + return; + } + + /* Do we have enough data for the full TLV? */ + if (caplen < size || length < size) { + /* No. */ + return; + } + + /* Skip over the TLV. */ + length -= size; + caplen -= size; + p += size; + } +} + +static void +swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) +{ + /* + * Convert pseudo-headers from the byte order of + * the host on which the file was saved to our + * byte order, as necessary. + */ + switch (linktype) { + + case DLT_PFLOG: + swap_pflog_header(hdr, data); + break; + + case DLT_LINUX_SLL: + swap_linux_sll_socketcan_header(hdr, data); + break; + + case DLT_LINUX_SLL2: + swap_linux_sll2_socketcan_header(hdr, data); + break; + + case DLT_USB_LINUX: + swap_linux_usb_header(hdr, data, 0); + break; + + case DLT_USB_LINUX_MMAPPED: + swap_linux_usb_header(hdr, data, 1); + break; + + case DLT_NFLOG: + swap_nflog_header(hdr, data); + break; + } +} + +static inline int +packet_length_might_be_wrong(struct pcap_pkthdr *hdr, + const pcap_usb_header_mmapped *usb_hdr) +{ + uint32_t old_style_packet_length; + + /* + * Calculate the packet length the old way. + * We know that the multiplication won't overflow, but + * we don't know that the additions won't. Calculate + * it with no overflow checks, as that's how it + * would have been calculated when it was captured. + */ + old_style_packet_length = iso_pseudo_header_len(usb_hdr) + + usb_hdr->urb_len; + return (hdr->len == old_style_packet_length); +} + +void +pcapint_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr, + u_char *data) +{ + if (swapped) + swap_pseudo_headers(linktype, hdr, data); + + /* + * Is this a memory-mapped Linux USB capture? + */ + if (linktype == DLT_USB_LINUX_MMAPPED) { + /* + * Yes. + * + * In older versions of libpcap, in memory-mapped Linux + * USB captures, the original length of completion events + * for incoming isochronous transfers was miscalculated; + * it needed to be calculated based on the offsets and + * lengths in the descriptors, not on the raw URB length, + * but it wasn't. + * + * If this packet contains transferred data (yes, data_flag + * is 0 if we *do* have data), it's a completion event + * for an incoming isochronous transfer, and the + * transfer length appears to have been calculated + * from the raw URB length, fix it. + * + * We only do this if we have the full USB pseudo-header, + * because we will have to look at that header and at + * all of the isochronous descriptors. + */ + if (hdr->caplen < sizeof (pcap_usb_header_mmapped)) { + /* + * We don't have the full pseudo-header. + */ + return; + } + + const pcap_usb_header_mmapped *usb_hdr = + (const pcap_usb_header_mmapped *) data; + + /* + * Make sure the number of descriptors is sane. + * + * The Linux binary USB monitor code limits the number of + * isochronous descriptors to 128; if the number in the file + * is larger than that, either 1) the file's been damaged + * or 2) the file was produced after the number was raised + * in the kernel. + * + * In case 1), the number can't be trusted, so don't rely on + * it to attempt to fix the original length field in the pcap + * or pcapng header. + * + * In case 2), the system was probably running a version of + * libpcap that didn't miscalculate the original length, so + * it probably doesn't need to be fixed. + * + * This avoids the possibility of the product of the number of + * descriptors and the size of descriptors won't overflow an + * unsigned 32-bit integer. + */ + if (usb_hdr->ndesc > USB_MAXDESC) + return; + + if (!usb_hdr->data_flag && + is_isochronous_transfer_completion(usb_hdr) && + packet_length_might_be_wrong(hdr, usb_hdr)) { + u_int len; + + /* + * Make sure we have all of the descriptors, + * as we will have to look at all of them. + * + * If not, we don't bother trying to fix + * anything. + */ + if (hdr->caplen < iso_pseudo_header_len(usb_hdr)) + return; + + /* + * Calculate what the length should have been. + */ + len = incoming_isochronous_transfer_completed_len(hdr, + data); + + /* + * len is the smaller of UINT_MAX and the total + * header plus data length. That's guaranteed + * to fit in a UINT_MAX. + * + * Don't reduce the original length to a value + * below the captured length, however, as that + * is bogus. + */ + if (len >= hdr->caplen) + hdr->len = len; + + /* + * If the captured length is greater than the + * length, use the captured length. + * + * For completion events for incoming isochronous + * transfers, it's based on data_len, which is + * calculated the same way we calculated + * pre_truncation_data_len above, except that + * it has access to all the isochronous descriptors, + * not just the ones that the kernel were able to + * provide us or, for a capture file, that weren't + * sliced off by a snapshot length. + * + * However, it might have been reduced by the USB + * capture mechanism arbitrarily limiting the amount + * of data it provides to userland, or by the libpcap + * capture code limiting it to being no more than the + * snapshot, so we don't want to just use it all the + * time; we only do so to try to get a better estimate + * of the actual length - and to make sure the + * original length is always >= the captured length. + */ + if (hdr->caplen > hdr->len) + hdr->len = hdr->caplen; + } + } +} diff --git a/src/libpcap-1.10.5/pcap-util.h b/src/libpcap-1.10.5/pcap-util.h new file mode 100644 index 0000000000..5b40e45b96 --- /dev/null +++ b/src/libpcap-1.10.5/pcap-util.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * pcap-util.h - common code for various files + */ + +/* + * We use the "receiver-makes-right" approach to byte order; + * because time is at a premium when we are writing the file. + * In other words, the pcap_file_header and pcap_pkthdr, + * records are written in host byte order. + * Note that the bytes of packet data are written out in the order in + * which they were received, so multi-byte fields in packets are not + * written in host byte order, they're written in whatever order the + * sending machine put them in. + * + * We also use this for fixing up packet data headers from a remote + * capture, where the server may have a different byte order from the + * client. + * + * ntoh[ls] aren't sufficient because we might need to swap on a big-endian + * machine (if the file was written in little-end order). + */ +#define SWAPLONG(y) \ + (((((u_int)(y))&0xff)<<24) | \ + ((((u_int)(y))&0xff00)<<8) | \ + ((((u_int)(y))&0xff0000)>>8) | \ + ((((u_int)(y))>>24)&0xff)) +#define SWAPSHORT(y) \ + ((u_short)(((((u_int)(y))&0xff)<<8) | \ + ((((u_int)(y))&0xff00)>>8))) + +extern void pcapint_post_process(int linktype, int swapped, + struct pcap_pkthdr *hdr, u_char *data); diff --git a/src/libpcap-1.10.5/pcap.3pcap.in b/src/libpcap-1.10.5/pcap.3pcap.in new file mode 100644 index 0000000000..6336c3a8f8 --- /dev/null +++ b/src/libpcap-1.10.5/pcap.3pcap.in @@ -0,0 +1,1058 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP 3PCAP "9 September 2020" +.SH NAME +pcap \- Packet Capture library +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +.ft +.fi +.SH DESCRIPTION +The Packet Capture library +provides a high level interface to packet capture systems. All packets +on the network, even those destined for other hosts, are accessible +through this mechanism. +It also supports saving captured packets to a ``savefile'', and reading +packets from a ``savefile''. +.SS Initializing +.BR pcap_init () +initializes the library. It takes an argument giving options; +currently, the options are: +.TP +.B PCAP_CHAR_ENC_LOCAL +Treat all strings supplied as arguments, and return all strings to the +caller, as being in the local character encoding. +.TP +.B PCAP_CHAR_ENC_UTF_8 +Treat all strings supplied as arguments, and return all strings to the +caller, as being in UTF-8. +.PP +On UNIX-like systems, the local character encoding is assumed to be +UTF-8, so no character encoding transformations are done. +.PP +On Windows, the local character encoding is the local ANSI code page. +.PP +If +.BR pcap_init () +is called, the deprecated +.BR pcap_lookupdev () +routine always fails, so it should not be used, and, on Windows, +.BR pcap_create () +does not attempt to handle UTF-16LE strings. +.PP +If +.BR pcap_init () +is not called, strings are treated as being in the local ANSI code page +on Windows, +.BR pcap_lookupdev () +will succeed if there is a device on which to capture, and +.BR pcap_create () +makes an attempt to check whether the string passed as an argument is a +UTF-16LE string - note that this attempt is unsafe, as it may run past +the end of the string - to handle +.BR pcap_lookupdev () +returning a UTF-16LE string. Programs that don't call +.BR pcap_init () +should, on Windows, call +.BR pcap_wsockinit () +to initialize Winsock; this is not necessary if +.BR pcap_init () +is called, as +.BR pcap_init () +will initialize Winsock itself on Windows. +.TP +.B Routines +.RS +.TP +.BR pcap_init (3PCAP) +initialize the library +.RE +.SS Opening a capture handle for reading +To open a handle for a live capture, given the name of the network or +other interface on which the capture should be done, call +.BR pcap_create (), +set the appropriate options on the handle, and then activate it with +.BR pcap_activate (). +If +.BR pcap_activate () +fails, the handle should be closed with +.BR pcap_close (). +.PP +To obtain a list of devices that can be opened for a live capture, call +.BR pcap_findalldevs (); +to free the list returned by +.BR pcap_findalldevs (), +call +.BR pcap_freealldevs (). +.BR pcap_lookupdev () +will return the first device on that list that is not a ``loopback`` +network interface. +.PP +To open a handle for a ``savefile'' from which to read packets, given the +pathname of the ``savefile'', call +.BR pcap_open_offline (); +to set up a handle for a ``savefile'', given a +.B "FILE\ *" +referring to a file already opened for reading, call +.BR pcap_fopen_offline (). +.PP +In order to get a ``fake'' +.B pcap_t +for use in routines that require a +.B pcap_t +as an argument, such as routines to open a ``savefile'' for writing and +to compile a filter expression, call +.BR pcap_open_dead (). +.PP +.BR pcap_create (), +.BR pcap_open_offline (), +.BR pcap_fopen_offline (), +and +.BR pcap_open_dead () +return a pointer to a +.BR pcap_t , +which is the handle used for reading packets from the capture stream or +the ``savefile'', and for finding out information about the capture +stream or ``savefile''. +To close a handle, use +.BR pcap_close (). +.PP +The options that can be set on a capture handle include +.IP "snapshot length" +If, when capturing, you capture the entire contents of the packet, that +requires more CPU time to copy the packet to your application, more disk +and possibly network bandwidth to write the packet data to a file, and +more disk space to save the packet. If you don't need the entire +contents of the packet - for example, if you are only interested in the +TCP headers of packets - you can set the "snapshot length" for the +capture to an appropriate value. If the snapshot length is set to +.IR snaplen , +and +.I snaplen +is less +than the size of a packet that is captured, only the first +.I snaplen +bytes of that packet will be captured and provided as packet data. +.IP +A snapshot length of 65535 should be sufficient, on most if not all +networks, to capture all the data available from the packet. +.IP +The snapshot length is set with +.BR pcap_set_snaplen (). +.IP "promiscuous mode" +On broadcast LANs such as Ethernet, if the network isn't switched, or if +the adapter is connected to a "mirror port" on a switch to which all +packets passing through the switch are sent, a network adapter receives +all packets on the LAN, including unicast or multicast packets not sent +to a network address that the network adapter isn't configured to +recognize. +.IP +Normally, the adapter will discard those packets; however, many network +adapters support "promiscuous mode", which is a mode in which all +packets, even if they are not sent to an address that the adapter +recognizes, are provided to the host. This is useful for passively +capturing traffic between two or more other hosts for analysis. +.IP +Note that even if an application does not set promiscuous mode, the +adapter could well be in promiscuous mode for some other reason. +.IP +For now, this doesn't work on the "any" device; if an argument of "any" +or +.B NULL +is supplied, the setting of promiscuous mode is ignored. +.IP +Promiscuous mode is set with +.BR pcap_set_promisc (). +.IP "monitor mode" +On IEEE 802.11 wireless LANs, even if an adapter is in promiscuous mode, +it will supply to the host only frames for the network with which it's +associated. It might also supply only data frames, not management or +control frames, and might not provide the 802.11 header or radio +information pseudo-header for those frames. +.IP +In "monitor mode", sometimes also called "rfmon mode" (for "Radio +Frequency MONitor"), the adapter will supply all frames that it +receives, with 802.11 headers, and might supply a pseudo-header with +radio information about the frame as well. +.IP +Note that in monitor mode the adapter might disassociate from the +network with which it's associated, so that you will not be able to use +any wireless networks with that adapter. This could prevent accessing +files on a network server, or resolving host names or network addresses, +if you are capturing in monitor mode and are not connected to another +network with another adapter. +.IP +Monitor mode is set with +.BR pcap_set_rfmon (), +and +.BR pcap_can_set_rfmon () +can be used to determine whether an adapter can be put into monitor +mode. +.IP "packet buffer timeout" +If, when capturing, packets are delivered as soon as they arrive, the +application capturing the packets will be woken up for each packet as it +arrives, and might have to make one or more calls to the operating +system to fetch each packet. +.IP +If, instead, packets are not delivered as soon as they arrive, but are +delivered after a short delay (called a "packet buffer timeout"), more +than one packet can be accumulated before the packets are delivered, so +that a single wakeup would be done for multiple packets, and each set of +calls made to the operating system would supply multiple packets, rather +than a single packet. This reduces the per-packet CPU overhead if +packets are arriving at a high rate, increasing the number of packets +per second that can be captured. +.IP +The packet buffer timeout is required so that an application won't wait +for the operating system's capture buffer to fill up before packets are +delivered; if packets are arriving slowly, that wait could take an +arbitrarily long period of time. +.IP +Not all platforms support a packet buffer timeout; on platforms that +don't, the packet buffer timeout is ignored. A zero value for the +timeout, on platforms that support a packet buffer timeout, will cause a +read to wait forever to allow enough packets to arrive, with no timeout. +A negative value is invalid; the result of setting the timeout to a +negative value is unpredictable. +.IP +.BR NOTE : +the packet buffer timeout cannot be used to cause calls that read +packets to return within a limited period of time, because, on some +platforms, the packet buffer timeout isn't supported, and, on other +platforms, the timer doesn't start until at least one packet arrives. +This means that the packet buffer timeout should +.B NOT +be used, for example, in an interactive application to allow the packet +capture loop to ``poll'' for user input periodically, as there's no +guarantee that a call reading packets will return after the timeout +expires even if no packets have arrived. +.IP +The packet buffer timeout is set with +.BR pcap_set_timeout (). +.IP "immediate mode" +In immediate mode, packets are always delivered as soon as they arrive, +with no buffering. Immediate mode is set with +.BR pcap_set_immediate_mode (). +.IP "buffer size" +Packets that arrive for a capture are stored in a buffer, so that they +do not have to be read by the application as soon as they arrive. On +some platforms, the buffer's size can be set; a size that's too small +could mean that, if too many packets are being captured and the snapshot +length doesn't limit the amount of data that's buffered, packets could +be dropped if the buffer fills up before the application can read +packets from it, while a size that's too large could use more +non-pageable operating system memory than is necessary to prevent +packets from being dropped. +.IP +The buffer size is set with +.BR pcap_set_buffer_size (). +.IP "timestamp type" +On some platforms, the time stamp given to packets on live captures can +come from different sources that can have different resolutions or that +can have different relationships to the time values for the current time +supplied by routines on the native operating system. See +.BR \%pcap-tstamp (@MAN_MISC_INFO@) +for a list of time stamp types. +.IP +The time stamp type is set with +.BR pcap_set_tstamp_type (). +.PP +Reading packets from a network interface may require that you have +special privileges: +.TP +.B Under SunOS 3.x or 4.x with NIT or BPF: +You must have read access to +.I /dev/nit +or +.IR /dev/bpf* . +.TP +.B Under Solaris with DLPI: +You must have read/write access to the network pseudo device, e.g. +.IR /dev/le . +On at least some versions of Solaris, however, this is not sufficient to +allow +.I tcpdump +to capture in promiscuous mode; on those versions of Solaris, you must +be root, or the application capturing packets +must be installed setuid to root, in order to capture in promiscuous +mode. Note that, on many (perhaps all) interfaces, if you don't capture +in promiscuous mode, you will not see any outgoing packets, so a capture +not done in promiscuous mode may not be very useful. +.IP +In newer versions of Solaris, you must have been given the +.B net_rawaccess +privilege; this is both necessary and sufficient to give you access to the +network pseudo-device - there is no need to change the privileges on +that device. A user can be given that privilege by, for example, adding +that privilege to the user's +.B defaultpriv +key with the +.BR usermod (@MAN_ADMIN_COMMANDS@) +command. +.TP +.B Under HP-UX with DLPI: +You must be root or the application capturing packets must be installed +setuid to root. +.TP +.B Under IRIX with snoop: +You must be root or the application capturing packets must be installed +setuid to root. +.TP +.B Under Linux: +You must be root or the application capturing packets must be installed +setuid to root, unless your distribution has a kernel +that supports capability bits such as CAP_NET_RAW and code to allow +those capability bits to be given to particular accounts and to cause +those bits to be set on a user's initial processes when they log in, in +which case you must have CAP_NET_RAW in order to capture. +.TP +.B Under ULTRIX and Digital UNIX/Tru64 UNIX: +Any user may capture network traffic. +However, no user (not even the super-user) can capture in promiscuous +mode on an interface unless the super-user has enabled promiscuous-mode +operation on that interface using +.IR pfconfig (8), +and no user (not even the super-user) can capture unicast traffic +received by or sent by the machine on an interface unless the super-user +has enabled copy-all-mode operation on that interface using +.IR pfconfig , +so +.I useful +packet capture on an interface probably requires that either +promiscuous-mode or copy-all-mode operation, or both modes of +operation, be enabled on that interface. +.TP +.B Under BSD (this includes macOS): +You must have read access to +.I /dev/bpf* +on systems that don't have a cloning BPF device, or to +.I /dev/bpf +on systems that do. +On BSDs with a devfs (this includes macOS), this might involve more +than just having somebody with super-user access setting the ownership +or permissions on the BPF devices - it might involve configuring devfs +to set the ownership or permissions every time the system is booted, +if the system even supports that; if it doesn't support that, you might +have to find some other way to make that happen at boot time. +.PP +Reading a saved packet file doesn't require special privileges. +.PP +The packets read from the handle may include a ``pseudo-header'' +containing various forms of packet meta-data, and probably includes a +link-layer header whose contents can differ for different network +interfaces. To determine the format of the packets supplied by the +handle, call +.BR pcap_datalink (); +.I https://www.tcpdump.org/linktypes.html +lists the values it returns and describes the packet formats that +correspond to those values. +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +or +.B DLT_LINUX_SLL2 +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.PP +To obtain the +.B "FILE\ *" +corresponding to a +.B pcap_t +opened for a ``savefile'', call +.BR pcap_file (). +.TP +.B Routines +.RS +.TP +.BR pcap_create (3PCAP) +get a +.B pcap_t +for live capture +.TP +.BR pcap_activate (3PCAP) +activate a +.B pcap_t +for live capture +.TP +.BR pcap_findalldevs (3PCAP) +get a list of devices that can be opened for a live capture +.TP +.BR pcap_freealldevs (3PCAP) +free list of devices +.TP +.BR pcap_lookupdev (3PCAP) +get first non-loopback device on that list +.TP +.BR pcap_open_offline (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a pathname +.TP +.BR pcap_open_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a pathname, and specify the precision to +provide for packet time stamps +.TP +.BR pcap_fopen_offline (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a +.B "FILE\ *" +.TP +.BR pcap_fopen_offline_with_tstamp_precision (3PCAP) +open a +.B pcap_t +for a ``savefile'', given a +.BR "FILE\ *" , +and specify the precision to provide for packet time stamps +.TP +.BR pcap_open_dead (3PCAP) +create a ``fake'' +.B pcap_t +.TP +.BR pcap_close (3PCAP) +close a +.B pcap_t +.TP +.BR pcap_set_snaplen (3PCAP) +set the snapshot length for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_snapshot (3PCAP) +get the snapshot length for a +.B pcap_t +.TP +.BR pcap_set_promisc (3PCAP) +set promiscuous mode for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_protocol_linux (3PCAP) +set capture protocol for a not-yet-activated +.B pcap_t +for live capture (Linux only) +.TP +.BR pcap_set_rfmon (3PCAP) +set monitor mode for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_can_set_rfmon (3PCAP) +determine whether monitor mode can be set for a +.B pcap_t +for live capture +.TP +.BR pcap_set_timeout (3PCAP) +set packet buffer timeout for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_immediate_mode (3PCAP) +set immediate mode for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_buffer_size (3PCAP) +set buffer size for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_set_tstamp_type (3PCAP) +set time stamp type for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_list_tstamp_types (3PCAP) +get list of available time stamp types for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_free_tstamp_types (3PCAP) +free list of available time stamp types +.TP +.BR pcap_tstamp_type_val_to_name (3PCAP) +get name for a time stamp type +.TP +.BR pcap_tstamp_type_val_to_description (3PCAP) +get description for a time stamp type +.TP +.BR pcap_tstamp_type_name_to_val (3PCAP) +get time stamp type corresponding to a name +.TP +.BR pcap_set_tstamp_precision (3PCAP) +set time stamp precision for a not-yet-activated +.B pcap_t +for live capture +.TP +.BR pcap_get_tstamp_precision (3PCAP) +get the time stamp precision of a +.B pcap_t +for live capture +.TP +.BR pcap_datalink (3PCAP) +get link-layer header type for a +.B pcap_t +.TP +.BR pcap_file (3PCAP) +get the +.B "FILE\ *" +for a +.B pcap_t +opened for a ``savefile'' +.TP +.BR pcap_is_swapped (3PCAP) +determine whether a ``savefile'' being read came from a machine with the +opposite byte order +.TP +.BR pcap_major_version (3PCAP) +.PD 0 +.TP +.BR pcap_minor_version (3PCAP) +get the major and minor version of the file format version for a +``savefile'' +.PD +.RE +.SS Selecting a link-layer header type for a live capture +Some devices may provide more than one link-layer header type. To +obtain a list of all link-layer header types provided by a device, call +.BR pcap_list_datalinks () +on an activated +.B pcap_t +for the device. +To free a list of link-layer header types, call +.BR pcap_free_datalinks (). +To set the link-layer header type for a device, call +.BR pcap_set_datalink (). +This should be done after the device has been activated but before any +packets are read and before any filters are compiled or installed. +.TP +.B Routines +.RS +.TP +.BR pcap_list_datalinks (3PCAP) +get a list of link-layer header types for a device +.TP +.BR pcap_free_datalinks (3PCAP) +free list of link-layer header types +.TP +.BR pcap_set_datalink (3PCAP) +set link-layer header type for a device +.TP +.BR pcap_datalink_val_to_name (3PCAP) +get name for a link-layer header type +.TP +.BR pcap_datalink_val_to_description (3PCAP) +.PD 0 +.TP +.BR pcap_datalink_val_to_description_or_dlt (3PCAP) +get description for a link-layer header type +.PD +.TP +.BR pcap_datalink_name_to_val (3PCAP) +get link-layer header type corresponding to a name +.RE +.SS Reading packets +Packets are read with +.BR pcap_dispatch () +or +.BR pcap_loop (), +which process one or more packets, calling a callback routine for each +packet, or with +.BR pcap_next () +or +.BR pcap_next_ex (), +which return the next packet. +The callback for +.BR pcap_dispatch () +and +.BR pcap_loop () +is supplied a pointer to a +.BR "struct pcap_pkthdr" , +which includes the following members: +.RS +.TP +.B ts +a +.B struct timeval +containing the time when the packet was captured +.TP +.B caplen +a +.B bpf_u_int32 +giving the number of bytes of the packet that are available from the +capture +.TP +.B len +a +.B bpf_u_int32 +giving the length of the packet, in bytes (which might be more than the +number of bytes available from the capture, if the length of the packet +is larger than the maximum number of bytes to capture). +.RE +.PP +The callback is also supplied a +.B const u_char +pointer to the first +.B caplen +(as given in the +.B struct pcap_pkthdr +mentioned above) +bytes of data from the packet. This won't necessarily be the entire +packet; to capture the entire packet, you will have to provide a value +for +.I snaplen +in your call to +.BR pcap_set_snaplen () +that is sufficiently large to get all of the packet's data - a value of +65535 should be sufficient on most if not all networks). When reading +from a ``savefile'', the snapshot length specified when the capture was +performed will limit the amount of packet data available. +.PP +.BR pcap_next () +is passed an argument that points to a +.B struct pcap_pkthdr +structure, and fills it in with the time stamp and length values for the +packet. It returns a +.B const u_char * +to the first +.B caplen +bytes of the packet on success, and +.B NULL +on error. +.PP +.BR pcap_next_ex () +is passed two pointer arguments, one of which points to a +.B struct pcap_pkthdr * +and the other points to a +.BR "const u_char *" . +It sets the first pointer to point to a +.B struct pcap_pkthdr +structure with the time stamp and length values for the packet, and sets +the second pointer to point to the first +.B caplen +bytes of the packet. +.PP +To force the loop in +.BR pcap_dispatch () +or +.BR pcap_loop () +to terminate, call +.BR pcap_breakloop (). +.PP +By default, when reading packets from an interface opened for a live +capture, +.BR pcap_dispatch (), +.BR pcap_next (), +and +.BR pcap_next_ex () +will, if no packets are currently available to be read, block waiting +for packets to become available. On some, but +.I not +all, platforms, if a packet buffer timeout was specified, the wait will +terminate after the packet buffer timeout expires; applications should +be prepared for this, as it happens on some platforms, but should not +rely on it, as it does not happen on other platforms. Note that the +wait might, or might not, terminate even if no packets are available; +applications should be prepared for this to happen, but must not rely on +it happening. +.PP +A handle can be put into ``non-blocking mode'', so that those routines +will, rather than blocking, return an indication that no packets are +available to read. Call +.BR pcap_setnonblock () +to put a handle into non-blocking mode or to take it out of non-blocking +mode; call +.BR pcap_getnonblock () +to determine whether a handle is in non-blocking mode. Note that +non-blocking mode does not work correctly in Mac OS X 10.6. +.PP +Non-blocking mode is often combined with routines such as +.BR select (2) +or +.BR poll (2) +or other routines a platform offers to wait for any of a set of +descriptors to be ready to read. To obtain, for a handle, a descriptor +that can be used in those routines, call +.BR pcap_get_selectable_fd (). +If the routine indicates that data is +available to read on the descriptor, an attempt should be made to read +from the device. +.PP +Not all handles have such a descriptor available; +.BR pcap_get_selectable_fd () +will return +.B \-1 +if no such descriptor is available. If no such +descriptor is available, this may be because the device must be polled +periodically for packets; in that case, +.BR pcap_get_required_select_timeout () +will return a pointer to a +.B struct timeval +whose value can be used as a timeout in those routines. When the +routine returns, an attempt should be made to read packets from the +device. If +.BR pcap_get_required_select_timeout () +returns +.BR NULL , +no such timeout is available, and those routines cannot be +used with the device. +.PP +In addition, for various +reasons, one or more of those routines will not work properly with the +descriptor; the documentation for +.BR pcap_get_selectable_fd () +gives details. Note that, just as an attempt to read packets from a +.B pcap_t +may not return any packets if the packet buffer timeout expires, a +.BR select (), +.BR poll (), +or other such call may, if the packet buffer timeout expires, indicate +that a descriptor is ready to read even if there are no packets +available to read. +.TP +.B Routines +.RS +.TP +.BR pcap_dispatch (3PCAP) +read a bufferful of packets from a +.B pcap_t +open for a live capture or the full set of packets from a +.B pcap_t +open for a ``savefile'' +.TP +.BR pcap_loop (3PCAP) +read packets from a +.B pcap_t +until an interrupt or error occurs +.TP +.BR pcap_next (3PCAP) +read the next packet from a +.B pcap_t +without an indication whether an error occurred +.TP +.BR pcap_next_ex (3PCAP) +read the next packet from a +.B pcap_t +with an error indication on an error +.TP +.BR pcap_breakloop (3PCAP) +prematurely terminate the loop in +.BR pcap_dispatch () +or +.BR pcap_loop () +.TP +.BR pcap_setnonblock (3PCAP) +set or clear non-blocking mode on a +.B pcap_t +.TP +.BR pcap_getnonblock (3PCAP) +get the state of non-blocking mode for a +.B pcap_t +.TP +.BR pcap_get_selectable_fd (3PCAP) +attempt to get a descriptor for a +.B pcap_t +that can be used in calls such as +.BR select () +and +.BR poll () +.TP +.BR pcap_get_required_select_timeout (3PCAP) +attempt to get a timeout required for using a +.B pcap_t +in calls such as +.BR select () +and +.BR poll () +.RE +.SS Filters +In order to cause only certain packets to be returned when reading +packets, a filter can be set on a handle. For a live capture, the +filtering will be performed in kernel mode, if possible, to avoid +copying ``uninteresting'' packets from the kernel to user mode. +.PP +A filter can be specified as a text string; the syntax and semantics of +the string are as described by +.BR \%pcap-filter (@MAN_MISC_INFO@). +A filter string is compiled into a program in a pseudo-machine-language +by +.BR pcap_compile () +and the resulting program can be made a filter for a handle with +.BR pcap_setfilter (). +The result of +.BR pcap_compile () +can be freed with a call to +.BR pcap_freecode (). +.BR pcap_compile () +may require a network mask for certain expressions in the filter string; +.BR pcap_lookupnet () +can be used to find the network address and network mask for a given +capture device. +.PP +A compiled filter can also be applied directly to a packet that has been +read using +.BR pcap_offline_filter (). +.TP +.B Routines +.RS +.TP +.BR pcap_compile (3PCAP) +compile filter expression to a pseudo-machine-language code program +.TP +.BR pcap_freecode (3PCAP) +free a filter program +.TP +.BR pcap_setfilter (3PCAP) +set filter for a +.B pcap_t +.TP +.BR pcap_lookupnet (3PCAP) +get network address and network mask for a capture device +.TP +.BR pcap_offline_filter (3PCAP) +apply a filter program to a packet +.RE +.SS Incoming and outgoing packets +By default, libpcap will attempt to capture both packets sent by the +machine and packets received by the machine. To limit it to capturing +only packets received by the machine or, if possible, only packets sent +by the machine, call +.BR pcap_setdirection (). +.TP +.BR Routines +.RS +.TP +.BR pcap_setdirection (3PCAP) +specify whether to capture incoming packets, outgoing packets, or both +.RE +.SS Capture statistics +To get statistics about packets received and dropped in a live capture, +call +.BR pcap_stats (). +.TP +.B Routines +.RS +.TP +.BR pcap_stats (3PCAP) +get capture statistics +.RE +.SS Opening a handle for writing captured packets +To open a ``savefile`` to which to write packets, given the pathname the +``savefile'' should have, call +.BR pcap_dump_open (). +To open a ``savefile`` to which to write packets, given the pathname the +``savefile'' should have, call +.BR pcap_dump_open (); +to set up a handle for a ``savefile'', given a +.B "FILE\ *" +referring to a file already opened for writing, call +.BR pcap_dump_fopen (). +They each return pointers to a +.BR pcap_dumper_t , +which is the handle used for writing packets to the ``savefile''. If it +succeeds, it will have created the file if it doesn't exist and +truncated the file if it does exist. +To close a +.BR pcap_dumper_t , +call +.BR pcap_dump_close (). +.TP +.B Routines +.RS +.TP +.BR pcap_dump_open (3PCAP) +open a +.B pcap_dumper_t +for a ``savefile``, given a pathname, replacing any existing data +.TP +.BR pcap_dump_open_append (3PCAP) +open a +.B pcap_dumper_t +for a ``savefile``, given a pathname, appending to the existing data +.TP +.BR pcap_dump_fopen (3PCAP) +open a +.B pcap_dumper_t +for a ``savefile``, given a +.BR "FILE\ *" , +assuming an empty file +.TP +.BR pcap_dump_close (3PCAP) +close a +.B pcap_dumper_t +.TP +.BR pcap_dump_file (3PCAP) +get the +.B "FILE\ *" +for a +.B pcap_dumper_t +opened for a ``savefile'' +.RE +.SS Writing packets +To write a packet to a +.BR pcap_dumper_t , +call +.BR pcap_dump (). +Packets written with +.BR pcap_dump () +may be buffered, rather than being immediately written to the +``savefile''. Closing the +.B pcap_dumper_t +will cause all buffered-but-not-yet-written packets to be written to the +``savefile''. +To force all packets written to the +.BR pcap_dumper_t , +and not yet written to the ``savefile'' because they're buffered by the +.BR pcap_dumper_t , +to be written to the ``savefile'', without closing the +.BR pcap_dumper_t , +call +.BR pcap_dump_flush (). +.TP +.B Routines +.RS +.TP +.BR pcap_dump (3PCAP) +write packet to a +.B pcap_dumper_t +.TP +.BR pcap_dump_flush (3PCAP) +flush buffered packets written to a +.B pcap_dumper_t +to the ``savefile'' +.TP +.BR pcap_dump_ftell (3PCAP) +get current file position for a +.B pcap_dumper_t +.RE +.SS Injecting packets +If you have the required privileges, you can inject packets onto a +network with a +.B pcap_t +for a live capture, using +.BR pcap_inject () +or +.BR pcap_sendpacket (). +(The two routines exist for compatibility with both OpenBSD and +WinPcap/Npcap; they perform the same function, but have different return +values.) +.TP +.B Routines +.RS +.TP +.BR pcap_inject (3PCAP) +.PD 0 +.TP +.BR pcap_sendpacket (3PCAP) +transmit a packet +.PD +.RE +.SS Reporting errors +Some routines return error or warning status codes; to convert them to a +string, use +.BR pcap_statustostr (). +.TP +.B Routines +.RS +.TP +.BR pcap_statustostr (3PCAP) +get a string for an error or warning status code +.RE +.SS Getting library version information +To get a string giving version information about libpcap, call +.BR pcap_lib_version (). +.TP +.B Routines +.RS +.TP +.BR pcap_lib_version (3PCAP) +get library version string +.RE +.SH BACKWARD COMPATIBILITY +.PP +In versions of libpcap prior to 1.0, the +.B pcap.h +header file was not in a +.B pcap +directory on most platforms; if you are writing an application that must +work on versions of libpcap prior to 1.0, include +.BR , +which will include +.B +for you, rather than including +.BR . +.PP +.BR pcap_create () +and +.BR pcap_activate () +were not available in versions of libpcap prior to 1.0; if you are +writing an application that must work on versions of libpcap prior to +1.0, either use +.BR pcap_open_live () +to get a handle for a live capture or, if you want to be able to use the +additional capabilities offered by using +.BR pcap_create () +and +.BR pcap_activate (), +use an +.BR autoconf (1) +script or some other configuration script to check whether the libpcap +1.0 APIs are available and use them only if they are. +.SH SEE ALSO +.BR autoconf (1), +.BR tcpdump (1), +.BR tcpslice (1), +.BR \%pcap-filter (@MAN_MISC_INFO@), +.BR pfconfig (8), +.BR usermod (@MAN_ADMIN_COMMANDS@) +.SH AUTHORS +The original authors of libpcap are: +.LP +Van Jacobson, +Craig Leres and +Steven McCanne, all of the +Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. +.LP +The current version is available from "The Tcpdump Group"'s Web site at +.LP +.RS +.I https://www.tcpdump.org/ +.RE +.SH BUGS +To report a security issue please send an e-mail to \%security@tcpdump.org. +.LP +To report bugs and other problems, contribute patches, request a +feature, provide generic feedback etc please see the file +.I CONTRIBUTING.md +in the libpcap source tree root. diff --git a/src/libpcap-1.10.5/pcap.c b/src/libpcap-1.10.5/pcap.c new file mode 100644 index 0000000000..d7850f12bc --- /dev/null +++ b/src/libpcap-1.10.5/pcap.c @@ -0,0 +1,4589 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* Get the same variety of strerror_r() as Autoconf/CMake has detected. */ +#include "ftmacros.h" + +#include +#ifndef _WIN32 +#include +#ifndef MSDOS +#include +#endif +#include +#include +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ +#include +#include +#endif /* _WIN32 */ + +#include +#include +#include +#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__MINGW32__) +#include +#endif +#include +#include +#include + +#include "diag-control.h" + +#include "thread-local.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifdef MSDOS +#include "pcap-dos.h" +#endif + +#include "pcap-int.h" + +#include "optimize.h" + +#ifdef HAVE_DAG_API +#include "pcap-dag.h" +#endif /* HAVE_DAG_API */ + +#ifdef HAVE_SEPTEL_API +#include "pcap-septel.h" +#endif /* HAVE_SEPTEL_API */ + +#ifdef HAVE_SNF_API +#include "pcap-snf.h" +#endif /* HAVE_SNF_API */ + +#ifdef HAVE_TC_API +#include "pcap-tc.h" +#endif /* HAVE_TC_API */ + +#ifdef PCAP_SUPPORT_LINUX_USBMON +#include "pcap-usb-linux.h" +#endif + +#ifdef PCAP_SUPPORT_BT +#include "pcap-bt-linux.h" +#endif + +#ifdef PCAP_SUPPORT_BT_MONITOR +#include "pcap-bt-monitor-linux.h" +#endif + +#ifdef PCAP_SUPPORT_NETFILTER +#include "pcap-netfilter-linux.h" +#endif + +#ifdef PCAP_SUPPORT_NETMAP +#include "pcap-netmap.h" +#endif + +#ifdef PCAP_SUPPORT_DBUS +#include "pcap-dbus.h" +#endif + +#ifdef PCAP_SUPPORT_RDMASNIFF +#include "pcap-rdmasniff.h" +#endif + +#ifdef PCAP_SUPPORT_DPDK +#include "pcap-dpdk.h" +#endif + +#ifdef HAVE_AIRPCAP_API +#include "pcap-airpcap.h" +#endif + +#ifdef _WIN32 +/* + * To quote the WSAStartup() documentation: + * + * The WSAStartup function typically leads to protocol-specific helper + * DLLs being loaded. As a result, the WSAStartup function should not + * be called from the DllMain function in a application DLL. This can + * potentially cause deadlocks. + * + * and the WSACleanup() documentation: + * + * The WSACleanup function typically leads to protocol-specific helper + * DLLs being unloaded. As a result, the WSACleanup function should not + * be called from the DllMain function in a application DLL. This can + * potentially cause deadlocks. + * + * So we don't initialize Winsock in a DllMain() routine. + * + * pcap_init() should be called to initialize pcap on both UN*X and + * Windows; it will initialize Winsock on Windows. (It will also be + * initialized as needed if pcap_init() hasn't been called.) + */ + +/* + * Shut down Winsock. + * + * Ignores the return value of WSACleanup(); given that this is + * an atexit() routine, there's nothing much we can do about + * a failure. + */ +static void +internal_wsockfini(void) +{ + WSACleanup(); +} + +/* + * Start Winsock. + * Internal routine. + */ +static int +internal_wsockinit(char *errbuf) +{ + WORD wVersionRequested; + WSADATA wsaData; + static int err = -1; + static int done = 0; + int status; + + if (done) + return (err); + + /* + * Versions of Windows that don't support Winsock 2.2 are + * too old for us. + */ + wVersionRequested = MAKEWORD(2, 2); + status = WSAStartup(wVersionRequested, &wsaData); + done = 1; + if (status != 0) { + if (errbuf != NULL) { + pcapint_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + status, "WSAStartup() failed"); + } + return (err); + } + atexit(internal_wsockfini); + err = 0; + return (err); +} + +/* + * Exported in case some applications using WinPcap/Npcap called it, + * even though it wasn't exported. + */ +int +wsockinit(void) +{ + return (internal_wsockinit(NULL)); +} + +/* + * This is the exported function; new programs should call this. + * *Newer* programs should call pcap_init(). + */ +int +pcap_wsockinit(void) +{ + return (internal_wsockinit(NULL)); +} +#endif /* _WIN32 */ + +/* + * Do whatever initialization is needed for libpcap. + * + * The argument specifies whether we use the local code page or UTF-8 + * for strings; on UN*X, we just assume UTF-8 in places where the encoding + * would matter, whereas, on Windows, we use the local code page for + * PCAP_CHAR_ENC_LOCAL and UTF-8 for PCAP_CHAR_ENC_UTF_8. + * + * On Windows, we also disable the hack in pcap_create() to deal with + * being handed UTF-16 strings, because if the user calls this they're + * explicitly declaring that they will either be passing local code + * page strings or UTF-8 strings, so we don't need to allow UTF-16LE + * strings to be passed. For good measure, on Windows *and* UN*X, + * we disable pcap_lookupdev(), to prevent anybody from even + * *trying* to pass the result of pcap_lookupdev() - which might be + * UTF-16LE on Windows, for ugly compatibility reasons - to pcap_create() + * or pcap_open_live() or pcap_open(). + * + * Returns 0 on success, -1 on error. + */ +int pcapint_new_api; /* pcap_lookupdev() always fails */ +int pcapint_utf_8_mode; /* Strings should be in UTF-8. */ + +int +pcap_init(unsigned int opts, char *errbuf) +{ + static int initialized; + + /* + * Don't allow multiple calls that set different modes; that + * may mean a library is initializing pcap in one mode and + * a program using that library, or another library used by + * that program, is initializing it in another mode. + */ + switch (opts) { + + case PCAP_CHAR_ENC_LOCAL: + /* Leave "UTF-8 mode" off. */ + if (initialized) { + if (pcapint_utf_8_mode) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Multiple pcap_init calls with different character encodings"); + return (PCAP_ERROR); + } + } + break; + + case PCAP_CHAR_ENC_UTF_8: + /* Turn on "UTF-8 mode". */ + if (initialized) { + if (!pcapint_utf_8_mode) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Multiple pcap_init calls with different character encodings"); + return (PCAP_ERROR); + } + } + pcapint_utf_8_mode = 1; + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown options specified"); + return (PCAP_ERROR); + } + + /* + * Turn the appropriate mode on for error messages; those routines + * are also used in rpcapd, which has no access to pcap's internal + * UTF-8 mode flag, so we have to call a routine to set its + * UTF-8 mode flag. + */ + pcapint_fmt_set_encoding(opts); + + if (initialized) { + /* + * Nothing more to do; for example, on Windows, we've + * already initialized Winsock. + */ + return (0); + } + +#ifdef _WIN32 + /* + * Now set up Winsock. + */ + if (internal_wsockinit(errbuf) == -1) { + /* Failed. */ + return (PCAP_ERROR); + } +#endif + + /* + * We're done. + */ + initialized = 1; + pcapint_new_api = 1; + return (0); +} + +/* + * String containing the library version. + * Not explicitly exported via a header file - the right API to use + * is pcap_lib_version() - but some programs included it, so we + * provide it. + * + * We declare it here, right before defining it, to squelch any + * warnings we might get from compilers about the lack of a + * declaration. + */ +PCAP_API char pcap_version[]; +PCAP_API_DEF char pcap_version[] = PACKAGE_VERSION; + +static void +pcap_set_not_initialized_message(pcap_t *pcap) +{ + if (pcap->activated) { + /* A module probably forgot to set the function pointer */ + (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This operation isn't properly handled by that device"); + return; + } + /* in case the caller doesn't check for PCAP_ERROR_NOT_ACTIVATED */ + (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "This handle hasn't been activated yet"); +} + +static int +pcap_read_not_initialized(pcap_t *pcap, int cnt _U_, pcap_handler callback _U_, + u_char *user _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_inject_not_initialized(pcap_t *pcap, const void * buf _U_, int size _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setfilter_not_initialized(pcap_t *pcap, struct bpf_program *fp _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setdirection_not_initialized(pcap_t *pcap, pcap_direction_t d _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_set_datalink_not_initialized(pcap_t *pcap, int dlt _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_getnonblock_not_initialized(pcap_t *pcap) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_stats_not_initialized(pcap_t *pcap, struct pcap_stat *ps _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +#ifdef _WIN32 +static struct pcap_stat * +pcap_stats_ex_not_initialized(pcap_t *pcap, int *pcap_stat_size _U_) +{ + pcap_set_not_initialized_message(pcap); + return (NULL); +} + +static int +pcap_setbuff_not_initialized(pcap_t *pcap, int dim _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setmode_not_initialized(pcap_t *pcap, int mode _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_setmintocopy_not_initialized(pcap_t *pcap, int size _U_) +{ + pcap_set_not_initialized_message(pcap); + /* this means 'not initialized' */ + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static HANDLE +pcap_getevent_not_initialized(pcap_t *pcap) +{ + pcap_set_not_initialized_message(pcap); + return (INVALID_HANDLE_VALUE); +} + +static int +pcap_oid_get_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_, + void *data _U_, size_t *lenp _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_oid_set_request_not_initialized(pcap_t *pcap, bpf_u_int32 oid _U_, + const void *data _U_, size_t *lenp _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static u_int +pcap_sendqueue_transmit_not_initialized(pcap_t *pcap, pcap_send_queue* queue _U_, + int sync _U_) +{ + pcap_set_not_initialized_message(pcap); + return (0); +} + +static int +pcap_setuserbuffer_not_initialized(pcap_t *pcap, int size _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_live_dump_not_initialized(pcap_t *pcap, char *filename _U_, int maxsize _U_, + int maxpacks _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static int +pcap_live_dump_ended_not_initialized(pcap_t *pcap, int sync _U_) +{ + pcap_set_not_initialized_message(pcap); + return (PCAP_ERROR_NOT_ACTIVATED); +} + +static PAirpcapHandle +pcap_get_airpcap_handle_not_initialized(pcap_t *pcap) +{ + pcap_set_not_initialized_message(pcap); + return (NULL); +} +#endif + +/* + * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't, + * a PCAP_ERROR value on an error. + */ +int +pcap_can_set_rfmon(pcap_t *p) +{ + return (p->can_set_rfmon_op(p)); +} + +/* + * For systems where rfmon mode is never supported. + */ +static int +pcap_cant_set_rfmon(pcap_t *p _U_) +{ + return (0); +} + +/* + * Sets *tstamp_typesp to point to an array 1 or more supported time stamp + * types; the return value is the number of supported time stamp types. + * The list should be freed by a call to pcap_free_tstamp_types() when + * you're done with it. + * + * A return value of 0 means "you don't get a choice of time stamp type", + * in which case *tstamp_typesp is set to null. + * + * PCAP_ERROR is returned on error. + */ +int +pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp) +{ + if (p->tstamp_type_count == 0) { + /* + * We don't support multiple time stamp types. + * That means the only type we support is PCAP_TSTAMP_HOST; + * set up a list containing only that type. + */ + *tstamp_typesp = (int*)malloc(sizeof(**tstamp_typesp)); + if (*tstamp_typesp == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (PCAP_ERROR); + } + **tstamp_typesp = PCAP_TSTAMP_HOST; + return (1); + } else { + *tstamp_typesp = (int*)calloc(p->tstamp_type_count, + sizeof(**tstamp_typesp)); + if (*tstamp_typesp == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (PCAP_ERROR); + } + (void)memcpy(*tstamp_typesp, p->tstamp_type_list, + sizeof(**tstamp_typesp) * p->tstamp_type_count); + return (p->tstamp_type_count); + } +} + +/* + * In Windows, you might have a library built with one version of the + * C runtime library and an application built with another version of + * the C runtime library, which means that the library might use one + * version of malloc() and free() and the application might use another + * version of malloc() and free(). If so, that means something + * allocated by the library cannot be freed by the application, so we + * need to have a pcap_free_tstamp_types() routine to free up the list + * allocated by pcap_list_tstamp_types(), even though it's just a wrapper + * around free(). + */ +void +pcap_free_tstamp_types(int *tstamp_type_list) +{ + free(tstamp_type_list); +} + +/* + * Default one-shot callback; overridden for capture types where the + * packet data cannot be guaranteed to be available after the callback + * returns, so that a copy must be made. + */ +void +pcapint_oneshot(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) +{ + struct oneshot_userdata *sp = (struct oneshot_userdata *)user; + + *sp->hdr = *h; + *sp->pkt = pkt; +} + +const u_char * +pcap_next(pcap_t *p, struct pcap_pkthdr *h) +{ + struct oneshot_userdata s; + const u_char *pkt; + + s.hdr = h; + s.pkt = &pkt; + s.pd = p; + if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s) <= 0) + return (0); + return (pkt); +} + +int +pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, + const u_char **pkt_data) +{ + struct oneshot_userdata s; + + s.hdr = &p->pcap_header; + s.pkt = pkt_data; + s.pd = p; + + /* Saves a pointer to the packet headers */ + *pkt_header= &p->pcap_header; + + if (p->rfile != NULL) { + int status; + + /* We are on an offline capture */ + status = pcapint_offline_read(p, 1, p->oneshot_callback, + (u_char *)&s); + + /* + * Return codes for pcapint_offline_read() are: + * - 0: EOF + * - -1: error + * - >0: OK - result is number of packets read, so + * it will be 1 in this case, as we've passed + * a maximum packet count of 1 + * The first one ('0') conflicts with the return code of + * 0 from pcap_read() meaning "no packets arrived before + * the timeout expired", so we map it to -2 so you can + * distinguish between an EOF from a savefile and a + * "no packets arrived before the timeout expired, try + * again" from a live capture. + */ + if (status == 0) + return (-2); + else + return (status); + } + + /* + * Return codes for pcap_read() are: + * - 0: timeout + * - -1: error + * - -2: loop was broken out of with pcap_breakloop() + * - >0: OK, result is number of packets captured, so + * it will be 1 in this case, as we've passed + * a maximum packet count of 1 + * The first one ('0') conflicts with the return code of 0 from + * pcapint_offline_read() meaning "end of file". + */ + return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); +} + +/* + * Implementation of a pcap_if_list_t. + */ +struct pcap_if_list { + pcap_if_t *beginning; +}; + +static struct capture_source_type { + int (*findalldevs_op)(pcap_if_list_t *, char *); + pcap_t *(*create_op)(const char *, char *, int *); +} capture_source_types[] = { +#ifdef HAVE_DAG_API + { dag_findalldevs, dag_create }, +#endif +#ifdef HAVE_SEPTEL_API + { septel_findalldevs, septel_create }, +#endif +#ifdef HAVE_SNF_API + { snf_findalldevs, snf_create }, +#endif +#ifdef HAVE_TC_API + { TcFindAllDevs, TcCreate }, +#endif +#ifdef PCAP_SUPPORT_BT + { bt_findalldevs, bt_create }, +#endif +#ifdef PCAP_SUPPORT_BT_MONITOR + { bt_monitor_findalldevs, bt_monitor_create }, +#endif +#ifdef PCAP_SUPPORT_LINUX_USBMON + { usb_findalldevs, usb_create }, +#endif +#ifdef PCAP_SUPPORT_NETFILTER + { netfilter_findalldevs, netfilter_create }, +#endif +#ifdef PCAP_SUPPORT_NETMAP + { pcap_netmap_findalldevs, pcap_netmap_create }, +#endif +#ifdef PCAP_SUPPORT_DBUS + { dbus_findalldevs, dbus_create }, +#endif +#ifdef PCAP_SUPPORT_RDMASNIFF + { rdmasniff_findalldevs, rdmasniff_create }, +#endif +#ifdef PCAP_SUPPORT_DPDK + { pcap_dpdk_findalldevs, pcap_dpdk_create }, +#endif +#ifdef HAVE_AIRPCAP_API + { airpcap_findalldevs, airpcap_create }, +#endif + { NULL, NULL } +}; + +/* + * Get a list of all capture sources that are up and that we can open. + * Returns -1 on error, 0 otherwise. + * The list, as returned through "alldevsp", may be null if no interfaces + * were up and could be opened. + */ +int +pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) +{ + size_t i; + pcap_if_list_t devlist; + + /* + * Find all the local network interfaces on which we + * can capture. + */ + devlist.beginning = NULL; + if (pcapint_platform_finddevs(&devlist, errbuf) == -1) { + /* + * Failed - free all of the entries we were given + * before we failed. + */ + if (devlist.beginning != NULL) + pcap_freealldevs(devlist.beginning); + *alldevsp = NULL; + return (-1); + } + + /* + * Ask each of the non-local-network-interface capture + * source types what interfaces they have. + */ + for (i = 0; capture_source_types[i].findalldevs_op != NULL; i++) { + if (capture_source_types[i].findalldevs_op(&devlist, errbuf) == -1) { + /* + * We had an error; free the list we've been + * constructing. + */ + if (devlist.beginning != NULL) + pcap_freealldevs(devlist.beginning); + *alldevsp = NULL; + return (-1); + } + } + + /* + * Return the first entry of the list of all devices. + */ + *alldevsp = devlist.beginning; + return (0); +} + +static struct sockaddr * +dup_sockaddr(struct sockaddr *sa, size_t sa_length) +{ + struct sockaddr *newsa; + + if ((newsa = malloc(sa_length)) == NULL) + return (NULL); + return (memcpy(newsa, sa, sa_length)); +} + +/* + * Construct a "figure of merit" for an interface, for use when sorting + * the list of interfaces, in which interfaces that are up are superior + * to interfaces that aren't up, interfaces that are up and running are + * superior to interfaces that are up but not running, and non-loopback + * interfaces that are up and running are superior to loopback interfaces, + * and interfaces with the same flags have a figure of merit that's higher + * the lower the instance number. + * + * The goal is to try to put the interfaces most likely to be useful for + * capture at the beginning of the list. + * + * The figure of merit, which is lower the "better" the interface is, + * has the uppermost bit set if the interface isn't running, the bit + * below that set if the interface isn't up, the bit below that + * set if the interface is a loopback interface, and the bit below + * that set if it's the "any" interface. + * + * Note: we don't sort by unit number because 1) not all interfaces have + * a unit number (systemd, for example, might assign interface names + * based on the interface's MAC address or on the physical location of + * the adapter's connector), and 2) if the name does end with a simple + * unit number, it's not a global property of the interface, it's only + * useful as a sort key for device names with the same prefix, so xyz0 + * shouldn't necessarily sort before abc2. This means that interfaces + * with the same figure of merit will be sorted by the order in which + * the mechanism from which we're getting the interfaces supplies them. + */ +static u_int +get_figure_of_merit(pcap_if_t *dev) +{ + u_int n; + + n = 0; + if (!(dev->flags & PCAP_IF_RUNNING)) + n |= 0x80000000; + if (!(dev->flags & PCAP_IF_UP)) + n |= 0x40000000; + + /* + * Give non-wireless interfaces that aren't disconnected a better + * figure of merit than interfaces that are disconnected, as + * "disconnected" should indicate that the interface isn't + * plugged into a network and thus won't give you any traffic. + * + * For wireless interfaces, it means "associated with a network", + * which we presume not to necessarily prevent capture, as you + * might run the adapter in some flavor of monitor mode. + */ + if (!(dev->flags & PCAP_IF_WIRELESS) && + (dev->flags & PCAP_IF_CONNECTION_STATUS) == PCAP_IF_CONNECTION_STATUS_DISCONNECTED) + n |= 0x20000000; + + /* + * Sort loopback devices after non-loopback devices, *except* for + * disconnected devices. + */ + if (dev->flags & PCAP_IF_LOOPBACK) + n |= 0x10000000; + + /* + * Sort the "any" device before loopback and disconnected devices, + * but after all other devices. + */ + if (strcmp(dev->name, "any") == 0) + n |= 0x08000000; + + return (n); +} + +#ifndef _WIN32 +/* + * Try to get a description for a given device. + * Returns a malloced description if it could and NULL if it couldn't. + * + * XXX - on FreeBSDs that support it, should it get the sysctl named + * "dev.{adapter family name}.{adapter unit}.%desc" to get a description + * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" + * with my Cisco 350 card, so the name isn't entirely descriptive. The + * "dev.an.0.%pnpinfo" has a better description, although one might argue + * that the problem is really a driver bug - if it can find out that it's + * a Cisco 340 or 350, rather than an old Aironet card, it should use + * that in the description. + * + * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD + * and OpenBSD let you get a description, but it's not generated by the OS, + * it's set with another ioctl that ifconfig supports; we use that to get + * a description in FreeBSD and OpenBSD, but if there is no such + * description available, it still might be nice to get some description + * string based on the device type or something such as that. + * + * In macOS, the System Configuration framework can apparently return + * names in 10.4 and later. + * + * It also appears that freedesktop.org's HAL offers an "info.product" + * string, but the HAL specification says it "should not be used in any + * UI" and "subsystem/capability specific properties" should be used + * instead and, in any case, I think HAL is being deprecated in + * favor of other stuff such as DeviceKit. DeviceKit doesn't appear + * to have any obvious product information for devices, but maybe + * I haven't looked hard enough. + * + * Using the System Configuration framework, or HAL, or DeviceKit, or + * whatever, would require that libpcap applications be linked with + * the frameworks/libraries in question. That shouldn't be a problem + * for programs linking with the shared version of libpcap (unless + * you're running on AIX - which I think is the only UN*X that doesn't + * support linking a shared library with other libraries on which it + * depends, and having an executable linked only with the first shared + * library automatically pick up the other libraries when started - + * and using HAL or whatever). Programs linked with the static + * version of libpcap would have to use pcap-config with the --static + * flag in order to get the right linker flags in order to pick up + * the additional libraries/frameworks; those programs need that anyway + * for libpcap 1.1 and beyond on Linux, as, by default, it requires + * -lnl. + * + * Do any other UN*Xes, or desktop environments support getting a + * description? + */ +static char * +#ifdef SIOCGIFDESCR +get_if_description(const char *name) +{ + char *description = NULL; + int s; + struct ifreq ifrdesc; +#ifndef IFDESCRSIZE + size_t descrlen = 64; +#else + size_t descrlen = IFDESCRSIZE; +#endif /* IFDESCRSIZE */ + + /* + * Get the description for the interface. + */ + memset(&ifrdesc, 0, sizeof ifrdesc); + pcapint_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s >= 0) { +#ifdef __FreeBSD__ + /* + * On FreeBSD, if the buffer isn't big enough for the + * description, the ioctl succeeds, but the description + * isn't copied, ifr_buffer.length is set to the description + * length, and ifr_buffer.buffer is set to NULL. + */ + for (;;) { + free(description); + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_buffer.buffer = description; + ifrdesc.ifr_buffer.length = descrlen; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { + if (ifrdesc.ifr_buffer.buffer == + description) + break; + else + descrlen = ifrdesc.ifr_buffer.length; + } else { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + break; + } + } else + break; + } +#else /* __FreeBSD__ */ + /* + * The only other OS that currently supports + * SIOCGIFDESCR is OpenBSD, and it has no way + * to get the description length - it's clamped + * to a maximum of IFDESCRSIZE. + */ + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_data = (caddr_t)description; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + } + } +#endif /* __FreeBSD__ */ + close(s); + if (description != NULL && description[0] == '\0') { + /* + * Description is empty, so discard it. + */ + free(description); + description = NULL; + } + } + +#ifdef __FreeBSD__ + /* + * For FreeBSD, if we didn't get a description, and this is + * a device with a name of the form usbusN, label it as a USB + * bus. + */ + if (description == NULL) { + if (strncmp(name, "usbus", 5) == 0) { + /* + * OK, it begins with "usbus". + */ + long busnum; + char *p; + + errno = 0; + busnum = strtol(name + 5, &p, 10); + if (errno == 0 && p != name + 5 && *p == '\0' && + busnum >= 0 && busnum <= INT_MAX) { + /* + * OK, it's a valid number that's not + * bigger than INT_MAX. Construct + * a description from it. + * (If that fails, we don't worry about + * it, we just return NULL.) + */ + if (pcapint_asprintf(&description, + "USB bus number %ld", busnum) == -1) { + /* Failed. */ + description = NULL; + } + } + } + } +#endif + return (description); +#else /* SIOCGIFDESCR */ +get_if_description(const char *name _U_) +{ + return (NULL); +#endif /* SIOCGIFDESCR */ +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return a pointer to its entry. + * + * If we don't find it, attempt to add an entry for it, with the specified + * IFF_ flags and description, and, if that succeeds, return a pointer to + * the new entry, otherwise return NULL and set errbuf to an error message. + */ +pcap_if_t * +pcapint_find_or_add_if(pcap_if_list_t *devlistp, const char *name, + uint64_t if_flags, get_if_flags_func get_flags_func, char *errbuf) +{ + bpf_u_int32 pcap_flags; + + /* + * Convert IFF_ flags to pcap flags. + */ + pcap_flags = 0; +#ifdef IFF_LOOPBACK + if (if_flags & IFF_LOOPBACK) + pcap_flags |= PCAP_IF_LOOPBACK; +#else + /* + * We don't have IFF_LOOPBACK, so look at the device name to + * see if it looks like a loopback device. + */ + if (name[0] == 'l' && name[1] == 'o' && + (PCAP_ISDIGIT(name[2]) || name[2] == '\0')) + pcap_flags |= PCAP_IF_LOOPBACK; +#endif +#ifdef IFF_UP + if (if_flags & IFF_UP) + pcap_flags |= PCAP_IF_UP; +#endif +#ifdef IFF_RUNNING + if (if_flags & IFF_RUNNING) + pcap_flags |= PCAP_IF_RUNNING; +#endif + + /* + * Attempt to find an entry for this device; if we don't find one, + * attempt to add one. + */ + return (pcapint_find_or_add_dev(devlistp, name, pcap_flags, + get_flags_func, get_if_description(name), errbuf)); +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, then, if the specified address isn't null, add it to + * the list of addresses for the device and return 0. + * + * If we don't find it, attempt to add an entry for it, with the specified + * IFF_ flags and description, and, if that succeeds, add the specified + * address to its list of addresses if that address is non-null, and + * return 0, otherwise return -1 and set errbuf to an error message. + * + * (We can get called with a null address because we might get a list + * of interface name/address combinations from the underlying OS, with + * the address being absent in some cases, rather than a list of + * interfaces with each interface having a list of addresses, so this + * call may be the only call made to add to the list, and we want to + * add interfaces even if they have no addresses.) + */ +int +pcapint_add_addr_to_if(pcap_if_list_t *devlistp, const char *name, + uint64_t if_flags, get_if_flags_func get_flags_func, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_if_t *curdev; + + /* + * Check whether the device exists and, if not, add it. + */ + curdev = pcapint_find_or_add_if(devlistp, name, if_flags, get_flags_func, + errbuf); + if (curdev == NULL) { + /* + * Error - give up. + */ + return (-1); + } + + if (addr == NULL) { + /* + * There's no address to add; this entry just meant + * "here's a new interface". + */ + return (0); + } + + /* + * "curdev" is an entry for this interface, and we have an + * address for it; add an entry for that address to the + * interface's list of addresses. + */ + return (pcapint_add_addr_to_dev(curdev, addr, addr_size, netmask, + netmask_size, broadaddr, broadaddr_size, dstaddr, + dstaddr_size, errbuf)); +} +#endif /* _WIN32 */ + +/* + * Add an entry to the list of addresses for an interface. + * "curdev" is the entry for that interface. + */ +int +pcapint_add_addr_to_dev(pcap_if_t *curdev, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_addr_t *curaddr, *prevaddr, *nextaddr; + + /* + * Allocate the new entry and fill it in. + */ + curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + + curaddr->next = NULL; + if (addr != NULL && addr_size != 0) { + curaddr->addr = (struct sockaddr *)dup_sockaddr(addr, addr_size); + if (curaddr->addr == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + free(curaddr); + return (-1); + } + } else + curaddr->addr = NULL; + + if (netmask != NULL && netmask_size != 0) { + curaddr->netmask = (struct sockaddr *)dup_sockaddr(netmask, netmask_size); + if (curaddr->netmask == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->netmask = NULL; + + if (broadaddr != NULL && broadaddr_size != 0) { + curaddr->broadaddr = (struct sockaddr *)dup_sockaddr(broadaddr, broadaddr_size); + if (curaddr->broadaddr == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->broadaddr = NULL; + + if (dstaddr != NULL && dstaddr_size != 0) { + curaddr->dstaddr = (struct sockaddr *)dup_sockaddr(dstaddr, dstaddr_size); + if (curaddr->dstaddr == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + if (curaddr->broadaddr != NULL) + free(curaddr->broadaddr); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->dstaddr = NULL; + + /* + * Find the end of the list of addresses. + */ + for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { + nextaddr = prevaddr->next; + if (nextaddr == NULL) { + /* + * This is the end of the list. + */ + break; + } + } + + if (prevaddr == NULL) { + /* + * The list was empty; this is the first member. + */ + curdev->addresses = curaddr; + } else { + /* + * "prevaddr" is the last member of the list; append + * this member to it. + */ + prevaddr->next = curaddr; + } + + return (0); +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0 and set *curdev_ret to point to it. + * + * If we don't find it, attempt to add an entry for it, with the specified + * flags and description, and, if that succeeds, return 0, otherwise + * return -1 and set errbuf to an error message. + */ +pcap_if_t * +pcapint_find_or_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags, + get_if_flags_func get_flags_func, const char *description, char *errbuf) +{ + pcap_if_t *curdev; + + /* + * Is there already an entry in the list for this device? + */ + curdev = pcapint_find_dev(devlistp, name); + if (curdev != NULL) { + /* + * Yes, return it. + */ + return (curdev); + } + + /* + * No, we didn't find it. + */ + + /* + * Try to get additional flags for the device. + */ + if ((*get_flags_func)(name, &flags, errbuf) == -1) { + /* + * Failed. + */ + return (NULL); + } + + /* + * Now, try to add it to the list of devices. + */ + return (pcapint_add_dev(devlistp, name, flags, description, errbuf)); +} + +/* + * Look for a given device in the specified list of devices, and return + * the entry for it if we find it or NULL if we don't. + */ +pcap_if_t * +pcapint_find_dev(pcap_if_list_t *devlistp, const char *name) +{ + pcap_if_t *curdev; + + /* + * Is there an entry in the list for this device? + */ + for (curdev = devlistp->beginning; curdev != NULL; + curdev = curdev->next) { + if (strcmp(name, curdev->name) == 0) { + /* + * We found it, so, yes, there is. No need to + * add it. Provide the entry we found to our + * caller. + */ + return (curdev); + } + } + + /* + * No. + */ + return (NULL); +} + +/* + * Attempt to add an entry for a device, with the specified flags + * and description, and, if that succeeds, return 0 and return a pointer + * to the new entry, otherwise return NULL and set errbuf to an error + * message. + * + * If we weren't given a description, try to get one. + */ +pcap_if_t * +pcapint_add_dev(pcap_if_list_t *devlistp, const char *name, bpf_u_int32 flags, + const char *description, char *errbuf) +{ + pcap_if_t *curdev, *prevdev, *nextdev; + u_int this_figure_of_merit, nextdev_figure_of_merit; + + curdev = malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (NULL); + } + + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = strdup(name); + if (curdev->name == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + free(curdev); + return (NULL); + } + if (description == NULL) { + /* + * We weren't handed a description for the interface. + */ + curdev->description = NULL; + } else { + /* + * We were handed a description; make a copy. + */ + curdev->description = strdup(description); + if (curdev->description == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + free(curdev->name); + free(curdev); + return (NULL); + } + } + curdev->addresses = NULL; /* list starts out as empty */ + curdev->flags = flags; + + /* + * Add it to the list, in the appropriate location. + * First, get the "figure of merit" for this interface. + */ + this_figure_of_merit = get_figure_of_merit(curdev); + + /* + * Now look for the last interface with an figure of merit + * less than or equal to the new interface's figure of merit. + * + * We start with "prevdev" being NULL, meaning we're before + * the first element in the list. + */ + prevdev = NULL; + for (;;) { + /* + * Get the interface after this one. + */ + if (prevdev == NULL) { + /* + * The next element is the first element. + */ + nextdev = devlistp->beginning; + } else + nextdev = prevdev->next; + + /* + * Are we at the end of the list? + */ + if (nextdev == NULL) { + /* + * Yes - we have to put the new entry after "prevdev". + */ + break; + } + + /* + * Is the new interface's figure of merit less + * than the next interface's figure of merit, + * meaning that the new interface is better + * than the next interface? + */ + nextdev_figure_of_merit = get_figure_of_merit(nextdev); + if (this_figure_of_merit < nextdev_figure_of_merit) { + /* + * Yes - we should put the new entry + * before "nextdev", i.e. after "prevdev". + */ + break; + } + + prevdev = nextdev; + } + + /* + * Insert before "nextdev". + */ + curdev->next = nextdev; + + /* + * Insert after "prevdev" - unless "prevdev" is null, + * in which case this is the first interface. + */ + if (prevdev == NULL) { + /* + * This is the first interface. Make it + * the first element in the list of devices. + */ + devlistp->beginning = curdev; + } else + prevdev->next = curdev; + return (curdev); +} + +/* + * Add an entry for the "any" device. + */ +pcap_if_t * +pcap_add_any_dev(pcap_if_list_t *devlistp, char *errbuf) +{ + static const char any_descr[] = "Pseudo-device that captures on all interfaces"; + + /* + * As it refers to all network devices, not to any particular + * network device, the notion of "connected" vs. "disconnected" + * doesn't apply to the "any" device. + */ + return pcapint_add_dev(devlistp, "any", + PCAP_IF_UP|PCAP_IF_RUNNING|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, + any_descr, errbuf); +} + +/* + * Free a list of interfaces. + */ +void +pcap_freealldevs(pcap_if_t *alldevs) +{ + pcap_if_t *curdev, *nextdev; + pcap_addr_t *curaddr, *nextaddr; + + for (curdev = alldevs; curdev != NULL; curdev = nextdev) { + nextdev = curdev->next; + + /* + * Free all addresses. + */ + for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) { + nextaddr = curaddr->next; + if (curaddr->addr) + free(curaddr->addr); + if (curaddr->netmask) + free(curaddr->netmask); + if (curaddr->broadaddr) + free(curaddr->broadaddr); + if (curaddr->dstaddr) + free(curaddr->dstaddr); + free(curaddr); + } + + /* + * Free the name string. + */ + free(curdev->name); + + /* + * Free the description string, if any. + */ + if (curdev->description != NULL) + free(curdev->description); + + /* + * Free the interface. + */ + free(curdev); + } +} + +/* + * pcap-npf.c has its own pcap_lookupdev(), for compatibility reasons, as + * it actually returns the names of all interfaces, with a NUL separator + * between them; some callers may depend on that. + * + * MS-DOS has its own pcap_lookupdev(), but that might be useful only + * as an optimization. + * + * In all other cases, we just use pcap_findalldevs() to get a list of + * devices, and pick from that list. + */ +#if !defined(HAVE_PACKET32) && !defined(MSDOS) +/* + * Return the name of a network interface attached to the system, or NULL + * if none can be found. The interface must be configured up; the + * lowest unit number is preferred; loopback is ignored. + */ +char * +pcap_lookupdev(char *errbuf) +{ + pcap_if_t *alldevs; +#ifdef _WIN32 + /* + * Windows - use the same size as the old WinPcap 3.1 code. + * XXX - this is probably bigger than it needs to be. + */ + #define IF_NAMESIZE 8192 +#else + /* + * UN*X - use the system's interface name size. + * XXX - that might not be large enough for capture devices + * that aren't regular network interfaces. + */ + /* for old BSD systems, including bsdi3 */ + #ifndef IF_NAMESIZE + #define IF_NAMESIZE IFNAMSIZ + #endif +#endif + static char device[IF_NAMESIZE + 1]; + char *ret; + + /* + * We disable this in "new API" mode, because 1) in WinPcap/Npcap, + * it may return UTF-16 strings, for backwards-compatibility + * reasons, and we're also disabling the hack to make that work, + * for not-going-past-the-end-of-a-string reasons, and 2) we + * want its behavior to be consistent. + * + * In addition, it's not thread-safe, so we've marked it as + * deprecated. + */ + if (pcapint_new_api) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()"); + return (NULL); + } + + if (pcap_findalldevs(&alldevs, errbuf) == -1) + return (NULL); + + if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) { + /* + * There are no devices on the list, or the first device + * on the list is a loopback device, which means there + * are no non-loopback devices on the list. This means + * we can't return any device. + * + * XXX - why not return a loopback device? If we can't + * capture on it, it won't be on the list, and if it's + * on the list, there aren't any non-loopback devices, + * so why not just supply it as the default device? + */ + (void)pcapint_strlcpy(errbuf, "no suitable device found", + PCAP_ERRBUF_SIZE); + ret = NULL; + } else { + /* + * Return the name of the first device on the list. + */ + (void)pcapint_strlcpy(device, alldevs->name, sizeof(device)); + ret = device; + } + + pcap_freealldevs(alldevs); + return (ret); +} +#endif /* !defined(HAVE_PACKET32) && !defined(MSDOS) */ + +#if !defined(_WIN32) && !defined(MSDOS) +/* + * We don't just fetch the entire list of devices, search for the + * particular device, and use its first IPv4 address, as that's too + * much work to get just one device's netmask. + * + * If we had an API to get attributes for a given device, we could + * use that. + */ +int +pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, + char *errbuf) +{ + register int fd; + register struct sockaddr_in *sin4; + struct ifreq ifr; + + /* + * The pseudo-device "any" listens on all interfaces and therefore + * has the network address and -mask "0.0.0.0" therefore catching + * all traffic. Using NULL for the interface is the same as "any". + */ + if (!device || strcmp(device, "any") == 0 +#ifdef HAVE_DAG_API + || strstr(device, "dag") != NULL +#endif +#ifdef HAVE_SEPTEL_API + || strstr(device, "septel") != NULL +#endif +#ifdef PCAP_SUPPORT_BT + || strstr(device, "bluetooth") != NULL +#endif +#ifdef PCAP_SUPPORT_LINUX_USBMON + || strstr(device, "usbmon") != NULL +#endif +#ifdef HAVE_SNF_API + || strstr(device, "snf") != NULL +#endif +#ifdef PCAP_SUPPORT_NETMAP + || strncmp(device, "netmap:", 7) == 0 + || strncmp(device, "vale", 4) == 0 +#endif +#ifdef PCAP_SUPPORT_DPDK + || strncmp(device, "dpdk:", 5) == 0 +#endif + ) { + *netp = *maskp = 0; + return 0; + } + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); + return (-1); + } + memset(&ifr, 0, sizeof(ifr)); +#ifdef __linux__ + /* XXX Work around Linux kernel bug */ + ifr.ifr_addr.sa_family = AF_INET; +#endif + (void)pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); +#if defined(__HAIKU__) && defined(__clang__) + /* + * In Haiku R1/beta4 ioctl() is a macro that needs to take 4 + * arguments to initialize its intermediate 2-member structure fully so + * that Clang does not generate a -Wmissing-field-initializers warning + * (which manifests only when it runs with -Werror). This workaround + * can be removed as soon as there is a Haiku release that fixes the + * problem. See also https://review.haiku-os.org/c/haiku/+/6369 + */ + if (ioctl(fd, SIOCGIFADDR, (char *)&ifr, sizeof(ifr)) < 0) { +#else + if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { +#endif /* __HAIKU__ && __clang__ */ + if (errno == EADDRNOTAVAIL) { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s: no IPv4 address assigned", device); + } else { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFADDR: %s", device); + } + (void)close(fd); + return (-1); + } + sin4 = (struct sockaddr_in *)&ifr.ifr_addr; + *netp = sin4->sin_addr.s_addr; + memset(&ifr, 0, sizeof(ifr)); +#ifdef __linux__ + /* XXX Work around Linux kernel bug */ + ifr.ifr_addr.sa_family = AF_INET; +#endif + (void)pcapint_strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); +#if defined(__HAIKU__) && defined(__clang__) + /* Same as above. */ + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr, sizeof(ifr)) < 0) { +#else + if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { +#endif /* __HAIKU__ && __clang__ */ + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFNETMASK: %s", device); + (void)close(fd); + return (-1); + } + (void)close(fd); + *maskp = sin4->sin_addr.s_addr; + if (*maskp == 0) { + if (IN_CLASSA(*netp)) + *maskp = IN_CLASSA_NET; + else if (IN_CLASSB(*netp)) + *maskp = IN_CLASSB_NET; + else if (IN_CLASSC(*netp)) + *maskp = IN_CLASSC_NET; + else { + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "inet class for 0x%x unknown", *netp); + return (-1); + } + } + *netp &= *maskp; + return (0); +} +#endif /* !defined(_WIN32) && !defined(MSDOS) */ + +#ifdef ENABLE_REMOTE +#include "pcap-rpcap.h" + +/* + * Extract a substring from a string. + */ +static char * +get_substring(const char *p, size_t len, char *ebuf) +{ + char *token; + + token = malloc(len + 1); + if (token == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (NULL); + } + memcpy(token, p, len); + token[len] = '\0'; + return (token); +} + +/* + * Parse a capture source that might be a URL. + * + * If the source is not a URL, *schemep, *userinfop, *hostp, and *portp + * are set to NULL, *pathp is set to point to the source, and 0 is + * returned. + * + * If source is a URL, and the URL refers to a local device (a special + * case of rpcap:), *schemep, *userinfop, *hostp, and *portp are set + * to NULL, *pathp is set to point to the device name, and 0 is returned. + * + * If source is a URL, and it's not a special case that refers to a local + * device, and the parse succeeds: + * + * *schemep is set to point to an allocated string containing the scheme; + * + * if user information is present in the URL, *userinfop is set to point + * to an allocated string containing the user information, otherwise + * it's set to NULL; + * + * if host information is present in the URL, *hostp is set to point + * to an allocated string containing the host information, otherwise + * it's set to NULL; + * + * if a port number is present in the URL, *portp is set to point + * to an allocated string containing the port number, otherwise + * it's set to NULL; + * + * *pathp is set to point to an allocated string containing the + * path; + * + * and 0 is returned. + * + * If the parse fails, ebuf is set to an error string, and -1 is returned. + */ +static int +pcap_parse_source(const char *source, char **schemep, char **userinfop, + char **hostp, char **portp, char **pathp, char *ebuf) +{ + char *colonp; + size_t scheme_len; + char *scheme; + const char *endp; + size_t authority_len; + char *authority; + char *parsep, *atsignp, *bracketp; + char *userinfo, *host, *port, *path; + + /* + * Start out returning nothing. + */ + *schemep = NULL; + *userinfop = NULL; + *hostp = NULL; + *portp = NULL; + *pathp = NULL; + + /* + * RFC 3986 says: + * + * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * Step 1: look for the ":" at the end of the scheme. + * A colon in the source is *NOT* sufficient to indicate that + * this is a URL, as interface names on some platforms might + * include colons (e.g., I think some Solaris interfaces + * might). + */ + colonp = strchr(source, ':'); + if (colonp == NULL) { + /* + * The source is the device to open. + * Return a NULL pointer for the scheme, user information, + * host, and port, and return the device as the path. + */ + *pathp = strdup(source); + if (*pathp == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + return (0); + } + + /* + * All schemes must have "//" after them, i.e. we only support + * hier-part = "//" authority path-abempty, not + * hier-part = path-absolute + * hier-part = path-rootless + * hier-part = path-empty + * + * We need that in order to distinguish between a local device + * name that happens to contain a colon and a URI. + */ + if (strncmp(colonp + 1, "//", 2) != 0) { + /* + * The source is the device to open. + * Return a NULL pointer for the scheme, user information, + * host, and port, and return the device as the path. + */ + *pathp = strdup(source); + if (*pathp == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + return (0); + } + + /* + * XXX - check whether the purported scheme could be a scheme? + */ + + /* + * OK, this looks like a URL. + * Get the scheme. + */ + scheme_len = colonp - source; + scheme = malloc(scheme_len + 1); + if (scheme == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + memcpy(scheme, source, scheme_len); + scheme[scheme_len] = '\0'; + + /* + * Treat file: specially - take everything after file:// as + * the pathname. + */ + if (pcapint_strcasecmp(scheme, "file") == 0) { + *pathp = strdup(colonp + 3); + if (*pathp == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + free(scheme); + return (-1); + } + *schemep = scheme; + return (0); + } + + /* + * The WinPcap documentation says you can specify a local + * interface with "rpcap://{device}"; we special-case + * that here. If the scheme is "rpcap", and there are + * no slashes past the "//", we just return the device. + * + * XXX - %-escaping? + */ + if ((pcapint_strcasecmp(scheme, "rpcap") == 0 || + pcapint_strcasecmp(scheme, "rpcaps") == 0) && + strchr(colonp + 3, '/') == NULL) { + /* + * Local device. + * + * Return a NULL pointer for the scheme, user information, + * host, and port, and return the device as the path. + */ + free(scheme); + *pathp = strdup(colonp + 3); + if (*pathp == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + return (0); + } + + /* + * OK, now start parsing the authority. + * Get token, terminated with / or terminated at the end of + * the string. + */ + authority_len = strcspn(colonp + 3, "/"); + authority = get_substring(colonp + 3, authority_len, ebuf); + if (authority == NULL) { + /* + * Error. + */ + free(scheme); + return (-1); + } + endp = colonp + 3 + authority_len; + + /* + * Now carve the authority field into its components. + */ + parsep = authority; + + /* + * Is there a userinfo field? + */ + atsignp = strchr(parsep, '@'); + if (atsignp != NULL) { + /* + * Yes. + */ + size_t userinfo_len; + + userinfo_len = atsignp - parsep; + userinfo = get_substring(parsep, userinfo_len, ebuf); + if (userinfo == NULL) { + /* + * Error. + */ + free(authority); + free(scheme); + return (-1); + } + parsep = atsignp + 1; + } else { + /* + * No. + */ + userinfo = NULL; + } + + /* + * Is there a host field? + */ + if (*parsep == '\0') { + /* + * No; there's no host field or port field. + */ + host = NULL; + port = NULL; + } else { + /* + * Yes. + */ + size_t host_len; + + /* + * Is it an IP-literal? + */ + if (*parsep == '[') { + /* + * Yes. + * Treat everything up to the closing square + * bracket as the IP-Literal; we don't worry + * about whether it's a valid IPv6address or + * IPvFuture (or an IPv4address, for that + * matter, just in case we get handed a + * URL with an IPv4 IP-Literal, of the sort + * that pcap_createsrcstr() used to generate, + * and that pcap_parsesrcstr(), in the original + * WinPcap code, accepted). + */ + bracketp = strchr(parsep, ']'); + if (bracketp == NULL) { + /* + * There's no closing square bracket. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "IP-literal in URL doesn't end with ]"); + free(userinfo); + free(authority); + free(scheme); + return (-1); + } + if (*(bracketp + 1) != '\0' && + *(bracketp + 1) != ':') { + /* + * There's extra crud after the + * closing square bracket. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "Extra text after IP-literal in URL"); + free(userinfo); + free(authority); + free(scheme); + return (-1); + } + host_len = (bracketp - 1) - parsep; + host = get_substring(parsep + 1, host_len, ebuf); + if (host == NULL) { + /* + * Error. + */ + free(userinfo); + free(authority); + free(scheme); + return (-1); + } + parsep = bracketp + 1; + } else { + /* + * No. + * Treat everything up to a : or the end of + * the string as the host. + */ + host_len = strcspn(parsep, ":"); + host = get_substring(parsep, host_len, ebuf); + if (host == NULL) { + /* + * Error. + */ + free(userinfo); + free(authority); + free(scheme); + return (-1); + } + parsep = parsep + host_len; + } + + /* + * Is there a port field? + */ + if (*parsep == ':') { + /* + * Yes. It's the rest of the authority field. + */ + size_t port_len; + + parsep++; + port_len = strlen(parsep); + port = get_substring(parsep, port_len, ebuf); + if (port == NULL) { + /* + * Error. + */ + free(host); + free(userinfo); + free(authority); + free(scheme); + return (-1); + } + } else { + /* + * No. + */ + port = NULL; + } + } + free(authority); + + /* + * Everything else is the path. Strip off the leading /. + */ + if (*endp == '\0') + path = strdup(""); + else + path = strdup(endp + 1); + if (path == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + free(port); + free(host); + free(userinfo); + free(scheme); + return (-1); + } + *schemep = scheme; + *userinfop = userinfo; + *hostp = host; + *portp = port; + *pathp = path; + return (0); +} + +int +pcapint_createsrcstr_ex(char *source, int type, const char *host, const char *port, + const char *name, unsigned char uses_ssl, char *errbuf) +{ + switch (type) { + + case PCAP_SRC_FILE: + pcapint_strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE); + if (name != NULL && *name != '\0') { + pcapint_strlcat(source, name, PCAP_BUF_SIZE); + return (0); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The file name cannot be NULL."); + return (-1); + } + + case PCAP_SRC_IFREMOTE: + pcapint_strlcpy(source, + (uses_ssl ? "rpcaps://" : PCAP_SRC_IF_STRING), + PCAP_BUF_SIZE); + if (host != NULL && *host != '\0') { + if (strchr(host, ':') != NULL) { + /* + * The host name contains a colon, so it's + * probably an IPv6 address, and needs to + * be included in square brackets. + */ + pcapint_strlcat(source, "[", PCAP_BUF_SIZE); + pcapint_strlcat(source, host, PCAP_BUF_SIZE); + pcapint_strlcat(source, "]", PCAP_BUF_SIZE); + } else + pcapint_strlcat(source, host, PCAP_BUF_SIZE); + + if (port != NULL && *port != '\0') { + pcapint_strlcat(source, ":", PCAP_BUF_SIZE); + pcapint_strlcat(source, port, PCAP_BUF_SIZE); + } + + pcapint_strlcat(source, "/", PCAP_BUF_SIZE); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The host name cannot be NULL."); + return (-1); + } + + if (name != NULL && *name != '\0') + pcapint_strlcat(source, name, PCAP_BUF_SIZE); + + return (0); + + case PCAP_SRC_IFLOCAL: + pcapint_strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); + + if (name != NULL && *name != '\0') + pcapint_strlcat(source, name, PCAP_BUF_SIZE); + + return (0); + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The interface type is not valid."); + return (-1); + } +} + + +int +pcap_createsrcstr(char *source, int type, const char *host, const char *port, + const char *name, char *errbuf) +{ + return (pcapint_createsrcstr_ex(source, type, host, port, name, 0, errbuf)); +} + +int +pcapint_parsesrcstr_ex(const char *source, int *type, char *host, char *port, + char *name, unsigned char *uses_ssl, char *errbuf) +{ + char *scheme, *tmpuserinfo, *tmphost, *tmpport, *tmppath; + + /* Initialization stuff */ + if (host) + *host = '\0'; + if (port) + *port = '\0'; + if (name) + *name = '\0'; + if (uses_ssl) + *uses_ssl = 0; + + /* Parse the source string */ + if (pcap_parse_source(source, &scheme, &tmpuserinfo, &tmphost, + &tmpport, &tmppath, errbuf) == -1) { + /* + * Fail. + */ + return (-1); + } + + if (scheme == NULL) { + /* + * Local device. + */ + if (name && tmppath) + pcapint_strlcpy(name, tmppath, PCAP_BUF_SIZE); + if (type) + *type = PCAP_SRC_IFLOCAL; + free(tmppath); + free(tmpport); + free(tmphost); + free(tmpuserinfo); + return (0); + } + + int is_rpcap = 0; + if (strcmp(scheme, "rpcaps") == 0) { + is_rpcap = 1; + if (uses_ssl) *uses_ssl = 1; + } else if (strcmp(scheme, "rpcap") == 0) { + is_rpcap = 1; + } + + if (is_rpcap) { + /* + * rpcap[s]:// + * + * pcap_parse_source() has already handled the case of + * rpcap[s]://device + */ + if (host && tmphost) { + if (tmpuserinfo) + snprintf(host, PCAP_BUF_SIZE, "%s@%s", + tmpuserinfo, tmphost); + else + pcapint_strlcpy(host, tmphost, PCAP_BUF_SIZE); + } + if (port && tmpport) + pcapint_strlcpy(port, tmpport, PCAP_BUF_SIZE); + if (name && tmppath) + pcapint_strlcpy(name, tmppath, PCAP_BUF_SIZE); + if (type) + *type = PCAP_SRC_IFREMOTE; + free(tmppath); + free(tmpport); + free(tmphost); + free(tmpuserinfo); + free(scheme); + return (0); + } + + if (strcmp(scheme, "file") == 0) { + /* + * file:// + */ + if (name && tmppath) + pcapint_strlcpy(name, tmppath, PCAP_BUF_SIZE); + if (type) + *type = PCAP_SRC_FILE; + free(tmppath); + free(tmpport); + free(tmphost); + free(tmpuserinfo); + free(scheme); + return (0); + } + + /* + * Neither rpcap: nor file:; just treat the entire string + * as a local device. + */ + if (name) + pcapint_strlcpy(name, source, PCAP_BUF_SIZE); + if (type) + *type = PCAP_SRC_IFLOCAL; + free(tmppath); + free(tmpport); + free(tmphost); + free(tmpuserinfo); + free(scheme); + return (0); +} + +int +pcap_parsesrcstr(const char *source, int *type, char *host, char *port, + char *name, char *errbuf) +{ + return (pcapint_parsesrcstr_ex(source, type, host, port, name, NULL, errbuf)); +} +#endif + +pcap_t * +pcap_create(const char *device, char *errbuf) +{ + size_t i; + int is_theirs; + pcap_t *p; + char *device_str; + + /* + * A null device name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (device == NULL) + device_str = strdup("any"); + else { +#ifdef _WIN32 + /* + * On Windows, for backwards compatibility reasons, + * pcap_lookupdev() returns a pointer to a sequence of + * pairs of UTF-16LE device names and local code page + * description strings. + * + * This means that if a program uses pcap_lookupdev() + * to get a default device, and hands that to an API + * that opens devices, we'll get handed a UTF-16LE + * string, not a string in the local code page. + * + * To work around that, we check whether the string + * looks as if it might be a UTF-16LE string and, if + * so, convert it back to the local code page's + * extended ASCII. + * + * We disable that check in "new API" mode, because: + * + * 1) You *cannot* reliably detect whether a + * string is UTF-16LE or not; "a" could either + * be a one-character ASCII string or the first + * character of a UTF-16LE string. + * + * 2) Doing that test can run past the end of + * the string, if it's a 1-character ASCII + * string + * + * This particular version of this heuristic dates + * back to WinPcap 4.1.1; PacketOpenAdapter() does + * uses the same heuristic, with the exact same + * vulnerability. + * + * That's why we disable this in "new API" mode. + * We keep it around in legacy mode for backwards + * compatibility. + */ + if (!pcapint_new_api && device[0] != '\0' && device[1] == '\0') { + size_t length; + + length = wcslen((wchar_t *)device); + device_str = (char *)malloc(length + 1); + if (device_str == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); + return (NULL); + } + + snprintf(device_str, length + 1, "%ws", + (const wchar_t *)device); + } else +#endif + device_str = strdup(device); + } + if (device_str == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (NULL); + } + + /* + * Try each of the non-local-network-interface capture + * source types until we find one that works for this + * device or run out of types. + */ + for (i = 0; capture_source_types[i].create_op != NULL; i++) { + is_theirs = 0; + p = capture_source_types[i].create_op(device_str, errbuf, + &is_theirs); + if (is_theirs) { + /* + * The device name refers to a device of the + * type in question; either it succeeded, + * in which case p refers to a pcap_t to + * later activate for the device, or it + * failed, in which case p is null and we + * should return that to report the failure + * to create. + */ + if (p == NULL) { + /* + * We assume the caller filled in errbuf. + */ + free(device_str); + return (NULL); + } + p->opt.device = device_str; + return (p); + } + } + + /* + * OK, try it as a regular network interface. + */ + p = pcapint_create_interface(device_str, errbuf); + if (p == NULL) { + /* + * We assume the caller filled in errbuf. + */ + free(device_str); + return (NULL); + } + p->opt.device = device_str; + return (p); +} + +/* + * Set nonblocking mode on an unactivated pcap_t; this sets a flag + * checked by pcap_activate(), which sets the mode after calling + * the activate routine. + */ +static int +pcap_setnonblock_unactivated(pcap_t *p, int nonblock) +{ + p->opt.nonblock = nonblock; + return (0); +} + +static void +initialize_ops(pcap_t *p) +{ + /* + * Set operation pointers for operations that only work on + * an activated pcap_t to point to a routine that returns + * a "this isn't activated" error. + */ + p->read_op = pcap_read_not_initialized; + p->inject_op = pcap_inject_not_initialized; + p->setfilter_op = pcap_setfilter_not_initialized; + p->setdirection_op = pcap_setdirection_not_initialized; + p->set_datalink_op = pcap_set_datalink_not_initialized; + p->getnonblock_op = pcap_getnonblock_not_initialized; + p->stats_op = pcap_stats_not_initialized; +#ifdef _WIN32 + p->stats_ex_op = pcap_stats_ex_not_initialized; + p->setbuff_op = pcap_setbuff_not_initialized; + p->setmode_op = pcap_setmode_not_initialized; + p->setmintocopy_op = pcap_setmintocopy_not_initialized; + p->getevent_op = pcap_getevent_not_initialized; + p->oid_get_request_op = pcap_oid_get_request_not_initialized; + p->oid_set_request_op = pcap_oid_set_request_not_initialized; + p->sendqueue_transmit_op = pcap_sendqueue_transmit_not_initialized; + p->setuserbuffer_op = pcap_setuserbuffer_not_initialized; + p->live_dump_op = pcap_live_dump_not_initialized; + p->live_dump_ended_op = pcap_live_dump_ended_not_initialized; + p->get_airpcap_handle_op = pcap_get_airpcap_handle_not_initialized; +#endif + + /* + * Default cleanup operation - implementations can override + * this, but should call pcapint_cleanup_live_common() after + * doing their own additional cleanup. + */ + p->cleanup_op = pcapint_cleanup_live_common; + + /* + * In most cases, the standard one-shot callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcapint_oneshot; + + /* + * Default breakloop operation - implementations can override + * this, but should call pcapint_breakloop_common() before doing + * their own logic. + */ + p->breakloop_op = pcapint_breakloop_common; +} + +static pcap_t * +pcap_alloc_pcap_t(char *ebuf, size_t total_size, size_t private_offset) +{ + char *chunk; + pcap_t *p; + + /* + * total_size is the size of a structure containing a pcap_t + * followed by a private structure. + */ + chunk = calloc(total_size, 1); + if (chunk == NULL) { + pcapint_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (NULL); + } + + /* + * Get a pointer to the pcap_t at the beginning. + */ + p = (pcap_t *)chunk; + +#ifdef _WIN32 + p->handle = INVALID_HANDLE_VALUE; /* not opened yet */ +#else /* _WIN32 */ + p->fd = -1; /* not opened yet */ +#ifndef MSDOS + p->selectable_fd = -1; + p->required_select_timeout = NULL; +#endif /* MSDOS */ +#endif /* _WIN32 */ + + /* + * private_offset is the offset, in bytes, of the private + * data from the beginning of the structure. + * + * Set the pointer to the private data; that's private_offset + * bytes past the pcap_t. + */ + p->priv = (void *)(chunk + private_offset); + + return (p); +} + +pcap_t * +pcapint_create_common(char *ebuf, size_t total_size, size_t private_offset) +{ + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, total_size, private_offset); + if (p == NULL) + return (NULL); + + /* + * Default to "can't set rfmon mode"; if it's supported by + * a platform, the create routine that called us can set + * the op to its routine to check whether a particular + * device supports it. + */ + p->can_set_rfmon_op = pcap_cant_set_rfmon; + + /* + * If pcap_setnonblock() is called on a not-yet-activated + * pcap_t, default to setting a flag and turning + * on non-blocking mode when activated. + */ + p->setnonblock_op = pcap_setnonblock_unactivated; + + initialize_ops(p); + + /* put in some defaults*/ + p->snapshot = 0; /* max packet size unspecified */ + p->opt.timeout = 0; /* no timeout specified */ + p->opt.buffer_size = 0; /* use the platform's default */ + p->opt.promisc = 0; + p->opt.rfmon = 0; + p->opt.immediate = 0; + p->opt.tstamp_type = -1; /* default to not setting time stamp type */ + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + /* + * Platform-dependent options. + */ +#ifdef __linux__ + p->opt.protocol = 0; +#endif +#ifdef _WIN32 + p->opt.nocapture_local = 0; +#endif + + /* + * Start out with no BPF code generation flags set. + */ + p->bpf_codegen_flags = 0; + + return (p); +} + +int +pcapint_check_activated(pcap_t *p) +{ + if (p->activated) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform " + " operation on activated capture"); + return (-1); + } + return (0); +} + +int +pcap_set_snaplen(pcap_t *p, int snaplen) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->snapshot = snaplen; + return (0); +} + +int +pcap_set_promisc(pcap_t *p, int promisc) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.promisc = promisc; + return (0); +} + +int +pcap_set_rfmon(pcap_t *p, int rfmon) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.rfmon = rfmon; + return (0); +} + +int +pcap_set_timeout(pcap_t *p, int timeout_ms) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.timeout = timeout_ms; + return (0); +} + +int +pcap_set_tstamp_type(pcap_t *p, int tstamp_type) +{ + int i; + + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + + /* + * The argument should have been u_int, but that's too late + * to change now - it's an API. + */ + if (tstamp_type < 0) + return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); + + /* + * If p->tstamp_type_count is 0, we only support PCAP_TSTAMP_HOST; + * the default time stamp type is PCAP_TSTAMP_HOST. + */ + if (p->tstamp_type_count == 0) { + if (tstamp_type == PCAP_TSTAMP_HOST) { + p->opt.tstamp_type = tstamp_type; + return (0); + } + } else { + /* + * Check whether we claim to support this type of time stamp. + */ + for (i = 0; i < p->tstamp_type_count; i++) { + if (p->tstamp_type_list[i] == (u_int)tstamp_type) { + /* + * Yes. + */ + p->opt.tstamp_type = tstamp_type; + return (0); + } + } + } + + /* + * We don't support this type of time stamp. + */ + return (PCAP_WARNING_TSTAMP_TYPE_NOTSUP); +} + +int +pcap_set_immediate_mode(pcap_t *p, int immediate) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + p->opt.immediate = immediate; + return (0); +} + +int +pcap_set_buffer_size(pcap_t *p, int buffer_size) +{ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + if (buffer_size <= 0) { + /* + * Silently ignore invalid values. + */ + return (0); + } + p->opt.buffer_size = buffer_size; + return (0); +} + +int +pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) +{ + int i; + + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + + /* + * The argument should have been u_int, but that's too late + * to change now - it's an API. + */ + if (tstamp_precision < 0) + return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); + + /* + * If p->tstamp_precision_count is 0, we only support setting + * the time stamp precision to microsecond precision; every + * pcap module *MUST* support microsecond precision, even if + * it does so by converting the native precision to + * microseconds. + */ + if (p->tstamp_precision_count == 0) { + if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO) { + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } else { + /* + * Check whether we claim to support this precision of + * time stamp. + */ + for (i = 0; i < p->tstamp_precision_count; i++) { + if (p->tstamp_precision_list[i] == (u_int)tstamp_precision) { + /* + * Yes. + */ + p->opt.tstamp_precision = tstamp_precision; + return (0); + } + } + } + + /* + * We don't support this time stamp precision. + */ + return (PCAP_ERROR_TSTAMP_PRECISION_NOTSUP); +} + +int +pcap_get_tstamp_precision(pcap_t *p) +{ + return (p->opt.tstamp_precision); +} + +int +pcap_activate(pcap_t *p) +{ + int status; + + /* + * Catch attempts to re-activate an already-activated + * pcap_t; this should, for example, catch code that + * calls pcap_open_live() followed by pcap_activate(), + * as some code that showed up in a Stack Exchange + * question did. + */ + if (pcapint_check_activated(p)) + return (PCAP_ERROR_ACTIVATED); + status = p->activate_op(p); + if (status >= 0) { + /* + * If somebody requested non-blocking mode before + * calling pcap_activate(), turn it on now. + */ + if (p->opt.nonblock) { + status = p->setnonblock_op(p, 1); + if (status < 0) { + /* + * Failed. Undo everything done by + * the activate operation. + */ + p->cleanup_op(p); + initialize_ops(p); + return (status); + } + } + p->activated = 1; + } else { + if (p->errbuf[0] == '\0') { + /* + * No error message supplied by the activate routine; + * for the benefit of programs that don't specially + * handle errors other than PCAP_ERROR, return the + * error message corresponding to the status. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s", + pcap_statustostr(status)); + } + + /* + * Undo any operation pointer setting, etc. done by + * the activate operation. + */ + initialize_ops(p); + } + return (status); +} + +pcap_t * +pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *errbuf) +{ + pcap_t *p; + int status; +#ifdef ENABLE_REMOTE + char host[PCAP_BUF_SIZE + 1]; + char port[PCAP_BUF_SIZE + 1]; + char name[PCAP_BUF_SIZE + 1]; + int srctype; + + /* + * A null device name is equivalent to the "any" device - + * which might not be supported on this platform, but + * this means that you'll get a "not supported" error + * rather than, say, a crash when we try to dereference + * the null pointer. + */ + if (device == NULL) + device = "any"; + + /* + * Retrofit - we have to make older applications compatible with + * remote capture. + * So we're calling pcap_open_remote() from here; this is a very + * dirty hack. + * Obviously, we cannot exploit all the new features; for instance, + * we cannot send authentication, we cannot use a UDP data connection, + * and so on. + */ + if (pcap_parsesrcstr(device, &srctype, host, port, name, errbuf)) + return (NULL); + + if (srctype == PCAP_SRC_IFREMOTE) { + /* + * Although we already have host, port and iface, we prefer + * to pass only 'device' to pcap_open_rpcap(), so that it has + * to call pcap_parsesrcstr() again. + * This is less optimized, but much clearer. + */ + return (pcap_open_rpcap(device, snaplen, + promisc ? PCAP_OPENFLAG_PROMISCUOUS : 0, to_ms, + NULL, errbuf)); + } + if (srctype == PCAP_SRC_FILE) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown URL scheme \"file\""); + return (NULL); + } + if (srctype == PCAP_SRC_IFLOCAL) { + /* + * If it starts with rpcap://, that refers to a local device + * (no host part in the URL). Remove the rpcap://, and + * fall through to the regular open path. + */ + if (strncmp(device, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0) { + size_t len = strlen(device) - strlen(PCAP_SRC_IF_STRING) + 1; + + if (len > 0) + device += strlen(PCAP_SRC_IF_STRING); + } + } +#endif /* ENABLE_REMOTE */ + + p = pcap_create(device, errbuf); + if (p == NULL) + return (NULL); + status = pcap_set_snaplen(p, snaplen); + if (status < 0) + goto fail; + status = pcap_set_promisc(p, promisc); + if (status < 0) + goto fail; + status = pcap_set_timeout(p, to_ms); + if (status < 0) + goto fail; + /* + * Mark this as opened with pcap_open_live(), so that, for + * example, we show the full list of DLT_ values, rather + * than just the ones that are compatible with capturing + * when not in monitor mode. That allows existing applications + * to work the way they used to work, but allows new applications + * that know about the new open API to, for example, find out the + * DLT_ values that they can select without changing whether + * the adapter is in monitor mode or not. + */ + p->oldstyle = 1; + status = pcap_activate(p); + if (status < 0) + goto fail; + return (p); +fail: + if (status == PCAP_ERROR) { + /* + * Another buffer is a bit cumbersome, but it avoids + * -Wformat-truncation. + */ + char trimbuf[PCAP_ERRBUF_SIZE - 5]; /* 2 bytes shorter */ + + pcapint_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf)); + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %.*s", device, + PCAP_ERRBUF_SIZE - 3, trimbuf); + } else if (status == PCAP_ERROR_NO_SUCH_DEVICE || + status == PCAP_ERROR_PERM_DENIED || + status == PCAP_ERROR_PROMISC_PERM_DENIED) { + /* + * Only show the additional message if it's not + * empty. + */ + if (p->errbuf[0] != '\0') { + /* + * Idem. + */ + char trimbuf[PCAP_ERRBUF_SIZE - 8]; /* 2 bytes shorter */ + + pcapint_strlcpy(trimbuf, p->errbuf, sizeof(trimbuf)); + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%.*s)", + device, pcap_statustostr(status), + PCAP_ERRBUF_SIZE - 6, trimbuf); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + device, pcap_statustostr(status)); + } + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", device, + pcap_statustostr(status)); + } + pcap_close(p); + return (NULL); +} + +pcap_t * +pcapint_open_offline_common(char *ebuf, size_t total_size, size_t private_offset) +{ + pcap_t *p; + + p = pcap_alloc_pcap_t(ebuf, total_size, private_offset); + if (p == NULL) + return (NULL); + + p->opt.tstamp_precision = PCAP_TSTAMP_PRECISION_MICRO; + + return (p); +} + +int +pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + return (p->read_op(p, cnt, callback, user)); +} + +int +pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + register int n; + + for (;;) { + if (p->rfile != NULL) { + /* + * 0 means EOF, so don't loop if we get 0. + */ + n = pcapint_offline_read(p, cnt, callback, user); + } else { + /* + * XXX keep reading until we get something + * (or an error occurs) + */ + do { + n = p->read_op(p, cnt, callback, user); + } while (n == 0); + } + if (n <= 0) + return (n); + if (!PACKET_COUNT_IS_UNLIMITED(cnt)) { + cnt -= n; + if (cnt <= 0) + return (0); + } + } +} + +/* + * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. + */ +void +pcap_breakloop(pcap_t *p) +{ + p->breakloop_op(p); +} + +int +pcap_datalink(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->linktype); +} + +int +pcap_datalink_ext(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->linktype_ext); +} + +int +pcap_list_datalinks(pcap_t *p, int **dlt_buffer) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + if (p->dlt_count == 0) { + /* + * We couldn't fetch the list of DLTs, which means + * this platform doesn't support changing the + * DLT for an interface. Return a list of DLTs + * containing only the DLT this device supports. + */ + *dlt_buffer = (int*)malloc(sizeof(**dlt_buffer)); + if (*dlt_buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (PCAP_ERROR); + } + **dlt_buffer = p->linktype; + return (1); + } else { + *dlt_buffer = (int*)calloc(p->dlt_count, sizeof(**dlt_buffer)); + if (*dlt_buffer == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "malloc"); + return (PCAP_ERROR); + } + (void)memcpy(*dlt_buffer, p->dlt_list, + sizeof(**dlt_buffer) * p->dlt_count); + return (p->dlt_count); + } +} + +/* + * In Windows, you might have a library built with one version of the + * C runtime library and an application built with another version of + * the C runtime library, which means that the library might use one + * version of malloc() and free() and the application might use another + * version of malloc() and free(). If so, that means something + * allocated by the library cannot be freed by the application, so we + * need to have a pcap_free_datalinks() routine to free up the list + * allocated by pcap_list_datalinks(), even though it's just a wrapper + * around free(). + */ +void +pcap_free_datalinks(int *dlt_list) +{ + free(dlt_list); +} + +int +pcap_set_datalink(pcap_t *p, int dlt) +{ + int i; + const char *dlt_name; + + if (dlt < 0) + goto unsupported; + + if (p->dlt_count == 0 || p->set_datalink_op == NULL) { + /* + * We couldn't fetch the list of DLTs, or we don't + * have a "set datalink" operation, which means + * this platform doesn't support changing the + * DLT for an interface. Check whether the new + * DLT is the one this interface supports. + */ + if (p->linktype != dlt) + goto unsupported; + + /* + * It is, so there's nothing we need to do here. + */ + return (0); + } + for (i = 0; i < p->dlt_count; i++) + if (p->dlt_list[i] == (u_int)dlt) + break; + if (i >= p->dlt_count) + goto unsupported; + if (p->dlt_count == 2 && p->dlt_list[0] == DLT_EN10MB && + dlt == DLT_DOCSIS) { + /* + * This is presumably an Ethernet device, as the first + * link-layer type it offers is DLT_EN10MB, and the only + * other type it offers is DLT_DOCSIS. That means that + * we can't tell the driver to supply DOCSIS link-layer + * headers - we're just pretending that's what we're + * getting, as, presumably, we're capturing on a dedicated + * link to a Cisco Cable Modem Termination System, and + * it's putting raw DOCSIS frames on the wire inside low-level + * Ethernet framing. + */ + p->linktype = dlt; + return (0); + } + if (p->set_datalink_op(p, dlt) == -1) + return (-1); + p->linktype = dlt; + return (0); + +unsupported: + dlt_name = pcap_datalink_val_to_name(dlt); + if (dlt_name != NULL) { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "%s is not one of the DLTs supported by this device", + dlt_name); + } else { + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "DLT %d is not one of the DLTs supported by this device", + dlt); + } + return (-1); +} + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { + (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003', + (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007', + (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013', + (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017', + (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023', + (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027', + (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033', + (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037', + (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043', + (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047', + (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053', + (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057', + (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063', + (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067', + (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073', + (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077', + (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133', + (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137', + (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143', + (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147', + (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153', + (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157', + (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163', + (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167', + (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173', + (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177', + (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203', + (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207', + (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213', + (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217', + (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223', + (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227', + (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233', + (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237', + (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243', + (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247', + (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253', + (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257', + (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263', + (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267', + (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273', + (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277', + (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333', + (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337', + (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343', + (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347', + (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353', + (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357', + (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363', + (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367', + (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373', + (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377', +}; + +int +pcapint_strcasecmp(const char *s1, const char *s2) +{ + register const u_char *cm = charmap, + *us1 = (const u_char *)s1, + *us2 = (const u_char *)s2; + + while (cm[*us1] == cm[*us2++]) + if (*us1++ == '\0') + return(0); + return (cm[*us1] - cm[*--us2]); +} + +struct dlt_choice { + const char *name; + const char *description; + int dlt; +}; + +#define DLT_CHOICE(code, description) { #code, description, DLT_ ## code } +#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 } + +static struct dlt_choice dlt_choices[] = { + DLT_CHOICE(NULL, "BSD loopback"), + DLT_CHOICE(EN10MB, "Ethernet"), + DLT_CHOICE(IEEE802, "Token ring"), + DLT_CHOICE(ARCNET, "BSD ARCNET"), + DLT_CHOICE(SLIP, "SLIP"), + DLT_CHOICE(PPP, "PPP"), + DLT_CHOICE(FDDI, "FDDI"), + DLT_CHOICE(ATM_RFC1483, "RFC 1483 LLC-encapsulated ATM"), + DLT_CHOICE(RAW, "Raw IP"), + DLT_CHOICE(SLIP_BSDOS, "BSD/OS SLIP"), + DLT_CHOICE(PPP_BSDOS, "BSD/OS PPP"), + DLT_CHOICE(ATM_CLIP, "Linux Classical IP over ATM"), + DLT_CHOICE(PPP_SERIAL, "PPP over serial"), + DLT_CHOICE(PPP_ETHER, "PPPoE"), + DLT_CHOICE(SYMANTEC_FIREWALL, "Symantec Firewall"), + DLT_CHOICE(C_HDLC, "Cisco HDLC"), + DLT_CHOICE(IEEE802_11, "802.11"), + DLT_CHOICE(FRELAY, "Frame Relay"), + DLT_CHOICE(LOOP, "OpenBSD loopback"), + DLT_CHOICE(ENC, "OpenBSD encapsulated IP"), + DLT_CHOICE(LINUX_SLL, "Linux cooked v1"), + DLT_CHOICE(LTALK, "Localtalk"), + DLT_CHOICE(PFLOG, "OpenBSD pflog file"), + DLT_CHOICE(PFSYNC, "Packet filter state syncing"), + DLT_CHOICE(PRISM_HEADER, "802.11 plus Prism header"), + DLT_CHOICE(IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"), + DLT_CHOICE(SUNATM, "Sun raw ATM"), + DLT_CHOICE(IEEE802_11_RADIO, "802.11 plus radiotap header"), + DLT_CHOICE(ARCNET_LINUX, "Linux ARCNET"), + DLT_CHOICE(JUNIPER_MLPPP, "Juniper Multi-Link PPP"), + DLT_CHOICE(JUNIPER_MLFR, "Juniper Multi-Link Frame Relay"), + DLT_CHOICE(JUNIPER_ES, "Juniper Encryption Services PIC"), + DLT_CHOICE(JUNIPER_GGSN, "Juniper GGSN PIC"), + DLT_CHOICE(JUNIPER_MFR, "Juniper FRF.16 Frame Relay"), + DLT_CHOICE(JUNIPER_ATM2, "Juniper ATM2 PIC"), + DLT_CHOICE(JUNIPER_SERVICES, "Juniper Advanced Services PIC"), + DLT_CHOICE(JUNIPER_ATM1, "Juniper ATM1 PIC"), + DLT_CHOICE(APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"), + DLT_CHOICE(MTP2_WITH_PHDR, "SS7 MTP2 with Pseudo-header"), + DLT_CHOICE(MTP2, "SS7 MTP2"), + DLT_CHOICE(MTP3, "SS7 MTP3"), + DLT_CHOICE(SCCP, "SS7 SCCP"), + DLT_CHOICE(DOCSIS, "DOCSIS"), + DLT_CHOICE(LINUX_IRDA, "Linux IrDA"), + DLT_CHOICE(IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"), + DLT_CHOICE(JUNIPER_MONITOR, "Juniper Passive Monitor PIC"), + DLT_CHOICE(BACNET_MS_TP, "BACnet MS/TP"), + DLT_CHOICE(PPP_PPPD, "PPP for pppd, with direction flag"), + DLT_CHOICE(JUNIPER_PPPOE, "Juniper PPPoE"), + DLT_CHOICE(JUNIPER_PPPOE_ATM, "Juniper PPPoE/ATM"), + DLT_CHOICE(GPRS_LLC, "GPRS LLC"), + DLT_CHOICE(GPF_T, "GPF-T"), + DLT_CHOICE(GPF_F, "GPF-F"), + DLT_CHOICE(JUNIPER_PIC_PEER, "Juniper PIC Peer"), + DLT_CHOICE(ERF_ETH, "Ethernet with Endace ERF header"), + DLT_CHOICE(ERF_POS, "Packet-over-SONET with Endace ERF header"), + DLT_CHOICE(LINUX_LAPD, "Linux vISDN LAPD"), + DLT_CHOICE(JUNIPER_ETHER, "Juniper Ethernet"), + DLT_CHOICE(JUNIPER_PPP, "Juniper PPP"), + DLT_CHOICE(JUNIPER_FRELAY, "Juniper Frame Relay"), + DLT_CHOICE(JUNIPER_CHDLC, "Juniper C-HDLC"), + DLT_CHOICE(MFR, "FRF.16 Frame Relay"), + DLT_CHOICE(JUNIPER_VP, "Juniper Voice PIC"), + DLT_CHOICE(A429, "Arinc 429"), + DLT_CHOICE(A653_ICM, "Arinc 653 Interpartition Communication"), + DLT_CHOICE(USB_FREEBSD, "USB with FreeBSD header"), + DLT_CHOICE(BLUETOOTH_HCI_H4, "Bluetooth HCI UART transport layer"), + DLT_CHOICE(IEEE802_16_MAC_CPS, "IEEE 802.16 MAC Common Part Sublayer"), + DLT_CHOICE(USB_LINUX, "USB with Linux header"), + DLT_CHOICE(CAN20B, "Controller Area Network (CAN) v. 2.0B"), + DLT_CHOICE(IEEE802_15_4_LINUX, "IEEE 802.15.4 with Linux padding"), + DLT_CHOICE(PPI, "Per-Packet Information"), + DLT_CHOICE(IEEE802_16_MAC_CPS_RADIO, "IEEE 802.16 MAC Common Part Sublayer plus radiotap header"), + DLT_CHOICE(JUNIPER_ISM, "Juniper Integrated Service Module"), + DLT_CHOICE(IEEE802_15_4, "IEEE 802.15.4 with FCS"), + DLT_CHOICE(SITA, "SITA pseudo-header"), + DLT_CHOICE(ERF, "Endace ERF header"), + DLT_CHOICE(RAIF1, "Ethernet with u10 Networks pseudo-header"), + DLT_CHOICE(IPMB_KONTRON, "IPMB with Kontron pseudo-header"), + DLT_CHOICE(JUNIPER_ST, "Juniper Secure Tunnel"), + DLT_CHOICE(BLUETOOTH_HCI_H4_WITH_PHDR, "Bluetooth HCI UART transport layer plus pseudo-header"), + DLT_CHOICE(AX25_KISS, "AX.25 with KISS header"), + DLT_CHOICE(IPMB_LINUX, "IPMB with Linux/Pigeon Point pseudo-header"), + DLT_CHOICE(IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), + DLT_CHOICE(MPLS, "MPLS with label as link-layer header"), + DLT_CHOICE(LINUX_EVDEV, "Linux evdev events"), + DLT_CHOICE(USB_LINUX_MMAPPED, "USB with padded Linux header"), + DLT_CHOICE(DECT, "DECT"), + DLT_CHOICE(AOS, "AOS Space Data Link protocol"), + DLT_CHOICE(WIHART, "WirelessHART"), + DLT_CHOICE(FC_2, "Fibre Channel FC-2"), + DLT_CHOICE(FC_2_WITH_FRAME_DELIMS, "Fibre Channel FC-2 with frame delimiters"), + DLT_CHOICE(IPNET, "Solaris ipnet"), + DLT_CHOICE(CAN_SOCKETCAN, "CAN-bus with SocketCAN headers"), + DLT_CHOICE(IPV4, "Raw IPv4"), + DLT_CHOICE(IPV6, "Raw IPv6"), + DLT_CHOICE(IEEE802_15_4_NOFCS, "IEEE 802.15.4 without FCS"), + DLT_CHOICE(DBUS, "D-Bus"), + DLT_CHOICE(JUNIPER_VS, "Juniper Virtual Server"), + DLT_CHOICE(JUNIPER_SRX_E2E, "Juniper SRX E2E"), + DLT_CHOICE(JUNIPER_FIBRECHANNEL, "Juniper Fibre Channel"), + DLT_CHOICE(DVB_CI, "DVB-CI"), + DLT_CHOICE(MUX27010, "MUX27010"), + DLT_CHOICE(STANAG_5066_D_PDU, "STANAG 5066 D_PDUs"), + DLT_CHOICE(JUNIPER_ATM_CEMIC, "Juniper ATM CEMIC"), + DLT_CHOICE(NFLOG, "Linux netfilter log messages"), + DLT_CHOICE(NETANALYZER, "Ethernet with Hilscher netANALYZER pseudo-header"), + DLT_CHOICE(NETANALYZER_TRANSPARENT, "Ethernet with Hilscher netANALYZER pseudo-header and with preamble and SFD"), + DLT_CHOICE(IPOIB, "RFC 4391 IP-over-Infiniband"), + DLT_CHOICE(MPEG_2_TS, "MPEG-2 transport stream"), + DLT_CHOICE(NG40, "ng40 protocol tester Iub/Iur"), + DLT_CHOICE(NFC_LLCP, "NFC LLCP PDUs with pseudo-header"), + DLT_CHOICE(INFINIBAND, "InfiniBand"), + DLT_CHOICE(SCTP, "SCTP"), + DLT_CHOICE(USBPCAP, "USB with USBPcap header"), + DLT_CHOICE(RTAC_SERIAL, "Schweitzer Engineering Laboratories RTAC packets"), + DLT_CHOICE(BLUETOOTH_LE_LL, "Bluetooth Low Energy air interface"), + DLT_CHOICE(NETLINK, "Linux netlink"), + DLT_CHOICE(BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"), + DLT_CHOICE(BLUETOOTH_BREDR_BB, "Bluetooth Basic Rate/Enhanced Data Rate baseband packets"), + DLT_CHOICE(BLUETOOTH_LE_LL_WITH_PHDR, "Bluetooth Low Energy air interface with pseudo-header"), + DLT_CHOICE(PROFIBUS_DL, "PROFIBUS data link layer"), + DLT_CHOICE(PKTAP, "Apple DLT_PKTAP"), + DLT_CHOICE(EPON, "Ethernet with 802.3 Clause 65 EPON preamble"), + DLT_CHOICE(IPMI_HPM_2, "IPMI trace packets"), + DLT_CHOICE(ZWAVE_R1_R2, "Z-Wave RF profile R1 and R2 packets"), + DLT_CHOICE(ZWAVE_R3, "Z-Wave RF profile R3 packets"), + DLT_CHOICE(WATTSTOPPER_DLM, "WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol"), + DLT_CHOICE(ISO_14443, "ISO 14443 messages"), + DLT_CHOICE(RDS, "IEC 62106 Radio Data System groups"), + DLT_CHOICE(USB_DARWIN, "USB with Darwin header"), + DLT_CHOICE(OPENFLOW, "OpenBSD DLT_OPENFLOW"), + DLT_CHOICE(SDLC, "IBM SDLC frames"), + DLT_CHOICE(TI_LLN_SNIFFER, "TI LLN sniffer frames"), + DLT_CHOICE(VSOCK, "Linux vsock"), + DLT_CHOICE(NORDIC_BLE, "Nordic Semiconductor Bluetooth LE sniffer frames"), + DLT_CHOICE(DOCSIS31_XRA31, "Excentis XRA-31 DOCSIS 3.1 RF sniffer frames"), + DLT_CHOICE(ETHERNET_MPACKET, "802.3br mPackets"), + DLT_CHOICE(DISPLAYPORT_AUX, "DisplayPort AUX channel monitoring data"), + DLT_CHOICE(LINUX_SLL2, "Linux cooked v2"), + DLT_CHOICE(OPENVIZSLA, "OpenVizsla USB"), + DLT_CHOICE(EBHSCR, "Elektrobit High Speed Capture and Replay (EBHSCR)"), + DLT_CHOICE(VPP_DISPATCH, "VPP graph dispatch tracer"), + DLT_CHOICE(DSA_TAG_BRCM, "Broadcom tag"), + DLT_CHOICE(DSA_TAG_BRCM_PREPEND, "Broadcom tag (prepended)"), + DLT_CHOICE(IEEE802_15_4_TAP, "IEEE 802.15.4 with pseudo-header"), + DLT_CHOICE(DSA_TAG_DSA, "Marvell DSA"), + DLT_CHOICE(DSA_TAG_EDSA, "Marvell EDSA"), + DLT_CHOICE(ELEE, "ELEE lawful intercept packets"), + DLT_CHOICE(Z_WAVE_SERIAL, "Z-Wave serial frames between host and chip"), + DLT_CHOICE(USB_2_0, "USB 2.0/1.1/1.0 as transmitted over the cable"), + DLT_CHOICE(ATSC_ALP, "ATSC Link-Layer Protocol packets"), + DLT_CHOICE_SENTINEL +}; + +int +pcap_datalink_name_to_val(const char *name) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (pcapint_strcasecmp(dlt_choices[i].name, name) == 0) + return (dlt_choices[i].dlt); + } + return (-1); +} + +const char * +pcap_datalink_val_to_name(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].name); + } + return (NULL); +} + +const char * +pcap_datalink_val_to_description(int dlt) +{ + int i; + + for (i = 0; dlt_choices[i].name != NULL; i++) { + if (dlt_choices[i].dlt == dlt) + return (dlt_choices[i].description); + } + return (NULL); +} + +const char * +pcap_datalink_val_to_description_or_dlt(int dlt) +{ + static thread_local char unkbuf[40]; + const char *description; + + description = pcap_datalink_val_to_description(dlt); + if (description != NULL) { + return description; + } else { + (void)snprintf(unkbuf, sizeof(unkbuf), "DLT %d", dlt); + return unkbuf; + } +} + +struct tstamp_type_choice { + const char *name; + const char *description; + int type; +}; + +static struct tstamp_type_choice tstamp_type_choices[] = { + { "host", "Host", PCAP_TSTAMP_HOST }, + { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC }, + { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC }, + { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER }, + { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED }, + { "host_hiprec_unsynced", "Host, high precision, not synced with system time", PCAP_TSTAMP_HOST_HIPREC_UNSYNCED }, + { NULL, NULL, 0 } +}; + +int +pcap_tstamp_type_name_to_val(const char *name) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (pcapint_strcasecmp(tstamp_type_choices[i].name, name) == 0) + return (tstamp_type_choices[i].type); + } + return (PCAP_ERROR); +} + +const char * +pcap_tstamp_type_val_to_name(int tstamp_type) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (tstamp_type_choices[i].type == tstamp_type) + return (tstamp_type_choices[i].name); + } + return (NULL); +} + +const char * +pcap_tstamp_type_val_to_description(int tstamp_type) +{ + int i; + + for (i = 0; tstamp_type_choices[i].name != NULL; i++) { + if (tstamp_type_choices[i].type == tstamp_type) + return (tstamp_type_choices[i].description); + } + return (NULL); +} + +int +pcap_snapshot(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->snapshot); +} + +int +pcap_is_swapped(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->swapped); +} + +int +pcap_major_version(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_major); +} + +int +pcap_minor_version(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->version_minor); +} + +int +pcap_bufsize(pcap_t *p) +{ + if (!p->activated) + return (PCAP_ERROR_NOT_ACTIVATED); + return (p->bufsize); +} + +FILE * +pcap_file(pcap_t *p) +{ + return (p->rfile); +} + +#ifdef _WIN32 +int +pcap_fileno(pcap_t *p) +{ + if (p->handle != INVALID_HANDLE_VALUE) { + /* + * This is a bogus and now-deprecated API; we + * squelch the narrowing warning for the cast + * from HANDLE to intptr_t. If Windows programmers + * need to get at the HANDLE for a pcap_t, *if* + * there is one, they should request such a + * routine (and be prepared for it to return + * INVALID_HANDLE_VALUE). + */ +DIAG_OFF_NARROWING + return ((int)(intptr_t)p->handle); +DIAG_ON_NARROWING + } else + return (PCAP_ERROR); +} +#else /* _WIN32 */ +int +pcap_fileno(pcap_t *p) +{ + return (p->fd); +} +#endif /* _WIN32 */ + +#if !defined(_WIN32) && !defined(MSDOS) +int +pcap_get_selectable_fd(pcap_t *p) +{ + return (p->selectable_fd); +} + +const struct timeval * +pcap_get_required_select_timeout(pcap_t *p) +{ + return (p->required_select_timeout); +} +#endif + +void +pcap_perror(pcap_t *p, const char *prefix) +{ + fprintf(stderr, "%s: %s\n", prefix, p->errbuf); +} + +char * +pcap_geterr(pcap_t *p) +{ + return (p->errbuf); +} + +int +pcap_getnonblock(pcap_t *p, char *errbuf) +{ + int ret; + + ret = p->getnonblock_op(p); + if (ret == -1) { + /* + * The get nonblock operation sets p->errbuf; this + * function *shouldn't* have had a separate errbuf + * argument, as it didn't need one, but I goofed + * when adding it. + * + * We copy the error message to errbuf, so callers + * can find it in either place. + */ + pcapint_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); + } + return (ret); +} + +/* + * Get the current non-blocking mode setting, under the assumption that + * it's just the standard POSIX non-blocking flag. + */ +#if !defined(_WIN32) && !defined(MSDOS) +int +pcapint_getnonblock_fd(pcap_t *p) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "F_GETFL"); + return (-1); + } + if (fdflags & O_NONBLOCK) + return (1); + else + return (0); +} +#endif + +int +pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf) +{ + int ret; + + ret = p->setnonblock_op(p, nonblock); + if (ret == -1) { + /* + * The set nonblock operation sets p->errbuf; this + * function *shouldn't* have had a separate errbuf + * argument, as it didn't need one, but I goofed + * when adding it. + * + * We copy the error message to errbuf, so callers + * can find it in either place. + */ + pcapint_strlcpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE); + } + return (ret); +} + +#if !defined(_WIN32) && !defined(MSDOS) +/* + * Set non-blocking mode, under the assumption that it's just the + * standard POSIX non-blocking flag. (This can be called by the + * per-platform non-blocking-mode routine if that routine also + * needs to do some additional work.) + */ +int +pcapint_setnonblock_fd(pcap_t *p, int nonblock) +{ + int fdflags; + + fdflags = fcntl(p->fd, F_GETFL, 0); + if (fdflags == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "F_GETFL"); + return (-1); + } + if (nonblock) + fdflags |= O_NONBLOCK; + else + fdflags &= ~O_NONBLOCK; + if (fcntl(p->fd, F_SETFL, fdflags) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "F_SETFL"); + return (-1); + } + return (0); +} +#endif + +/* + * Generate error strings for PCAP_ERROR_ and PCAP_WARNING_ values. + */ +const char * +pcap_statustostr(int errnum) +{ + static thread_local char ebuf[15+10+1]; + + switch (errnum) { + + case PCAP_WARNING: + return("Generic warning"); + + case PCAP_WARNING_TSTAMP_TYPE_NOTSUP: + return ("That type of time stamp is not supported by that device"); + + case PCAP_WARNING_PROMISC_NOTSUP: + return ("That device doesn't support promiscuous mode"); + + case PCAP_ERROR: + return("Generic error"); + + case PCAP_ERROR_BREAK: + return("Loop terminated by pcap_breakloop"); + + case PCAP_ERROR_NOT_ACTIVATED: + return("The pcap_t has not been activated"); + + case PCAP_ERROR_ACTIVATED: + return ("The setting can't be changed after the pcap_t is activated"); + + case PCAP_ERROR_NO_SUCH_DEVICE: + return ("No such device exists"); + + case PCAP_ERROR_RFMON_NOTSUP: + return ("That device doesn't support monitor mode"); + + case PCAP_ERROR_NOT_RFMON: + return ("That operation is supported only in monitor mode"); + + case PCAP_ERROR_PERM_DENIED: + return ("You don't have permission to perform this capture on that device"); + + case PCAP_ERROR_IFACE_NOT_UP: + return ("That device is not up"); + + case PCAP_ERROR_CANTSET_TSTAMP_TYPE: + return ("That device doesn't support setting the time stamp type"); + + case PCAP_ERROR_PROMISC_PERM_DENIED: + return ("You don't have permission to capture in promiscuous mode on that device"); + + case PCAP_ERROR_TSTAMP_PRECISION_NOTSUP: + return ("That device doesn't support that time stamp precision"); + + case PCAP_ERROR_CAPTURE_NOTSUP: + return ("Packet capture is not supported on that device"); + } + (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum); + return(ebuf); +} + +/* + * A long time ago the purpose of this function was to hide the difference + * between those Unix-like OSes that implemented strerror() and those that + * didn't. All the currently supported OSes implement strerror(), which is in + * POSIX.1-2001, uniformly and that particular problem no longer exists. But + * now they implement a few incompatible thread-safe variants of strerror(), + * and hiding that difference is the current purpose of this function. + */ +const char * +pcap_strerror(int errnum) +{ +#ifdef _WIN32 + static thread_local char errbuf[PCAP_ERRBUF_SIZE]; + errno_t err = strerror_s(errbuf, PCAP_ERRBUF_SIZE, errnum); + + if (err != 0) /* err = 0 if successful */ + pcapint_strlcpy(errbuf, "strerror_s() error", PCAP_ERRBUF_SIZE); + return (errbuf); +#elif defined(HAVE_GNU_STRERROR_R) + /* + * We have a GNU-style strerror_r(), which is *not* guaranteed to + * do anything to the buffer handed to it, and which returns a + * pointer to the error string, which may or may not be in + * the buffer. + * + * It is, however, guaranteed to succeed. + * + * At the time of this writing this applies to the following cases, + * each of which allows to use either the GNU implementation or the + * POSIX implementation, and this source tree defines _GNU_SOURCE to + * use the GNU implementation: + * - Hurd + * - Linux with GNU libc + * - Linux with uClibc-ng + */ + static thread_local char errbuf[PCAP_ERRBUF_SIZE]; + return strerror_r(errnum, errbuf, PCAP_ERRBUF_SIZE); +#elif defined(HAVE_POSIX_STRERROR_R) + /* + * We have a POSIX-style strerror_r(), which is guaranteed to fill + * in the buffer, but is not guaranteed to succeed. + * + * At the time of this writing this applies to the following cases: + * - AIX 7 + * - FreeBSD + * - Haiku + * - HP-UX 11 + * - illumos + * - Linux with musl libc + * - macOS + * - NetBSD + * - OpenBSD + * - Solaris 10 & 11 + */ + static thread_local char errbuf[PCAP_ERRBUF_SIZE]; + int err = strerror_r(errnum, errbuf, PCAP_ERRBUF_SIZE); + switch (err) { + case 0: + /* That worked. */ + break; + + case EINVAL: + /* + * UNIX 03 says this isn't guaranteed to produce a + * fallback error message. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Unknown error: %d", errnum); + break; + case ERANGE: + /* + * UNIX 03 says this isn't guaranteed to produce a + * fallback error message. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Message for error %d is too long", errnum); + break; + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "strerror_r(%d, ...) unexpectedly returned %d", + errnum, err); + } + return errbuf; +#else + /* + * At the time of this writing every supported OS implements strerror() + * and at least one thread-safe variant thereof, so this is a very + * unlikely last-resort branch. Particular implementations of strerror() + * may be thread-safe, but this is neither required nor guaranteed. + */ + return (strerror(errnum)); +#endif /* _WIN32 */ +} + +int +pcap_setfilter(pcap_t *p, struct bpf_program *fp) +{ + return (p->setfilter_op(p, fp)); +} + +/* + * Set direction flag, which controls whether we accept only incoming + * packets, only outgoing packets, or both. + * Note that, depending on the platform, some or all direction arguments + * might not be supported. + */ +int +pcap_setdirection(pcap_t *p, pcap_direction_t d) +{ + if (p->setdirection_op == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Setting direction is not supported on this device"); + return (-1); + } else { + switch (d) { + + case PCAP_D_IN: + case PCAP_D_OUT: + case PCAP_D_INOUT: + /* + * Valid direction. + */ + return (p->setdirection_op(p, d)); + + default: + /* + * Invalid direction. + */ + snprintf(p->errbuf, sizeof(p->errbuf), + "Invalid direction"); + return (-1); + } + } +} + +int +pcap_stats(pcap_t *p, struct pcap_stat *ps) +{ + return (p->stats_op(p, ps)); +} + +#ifdef _WIN32 +struct pcap_stat * +pcap_stats_ex(pcap_t *p, int *pcap_stat_size) +{ + return (p->stats_ex_op(p, pcap_stat_size)); +} + +int +pcap_setbuff(pcap_t *p, int dim) +{ + return (p->setbuff_op(p, dim)); +} + +int +pcap_setmode(pcap_t *p, int mode) +{ + return (p->setmode_op(p, mode)); +} + +int +pcap_setmintocopy(pcap_t *p, int size) +{ + return (p->setmintocopy_op(p, size)); +} + +HANDLE +pcap_getevent(pcap_t *p) +{ + return (p->getevent_op(p)); +} + +int +pcap_oid_get_request(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) +{ + return (p->oid_get_request_op(p, oid, data, lenp)); +} + +int +pcap_oid_set_request(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp) +{ + return (p->oid_set_request_op(p, oid, data, lenp)); +} + +pcap_send_queue * +pcap_sendqueue_alloc(u_int memsize) +{ + pcap_send_queue *tqueue; + + /* Allocate the queue */ + tqueue = (pcap_send_queue *)malloc(sizeof(pcap_send_queue)); + if (tqueue == NULL){ + return (NULL); + } + + /* Allocate the buffer */ + tqueue->buffer = (char *)malloc(memsize); + if (tqueue->buffer == NULL) { + free(tqueue); + return (NULL); + } + + tqueue->maxlen = memsize; + tqueue->len = 0; + + return (tqueue); +} + +void +pcap_sendqueue_destroy(pcap_send_queue *queue) +{ + free(queue->buffer); + free(queue); +} + +int +pcap_sendqueue_queue(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) +{ + if (queue->len + sizeof(struct pcap_pkthdr) + pkt_header->caplen > queue->maxlen){ + return (-1); + } + + /* Copy the pcap_pkthdr header*/ + memcpy(queue->buffer + queue->len, pkt_header, sizeof(struct pcap_pkthdr)); + queue->len += sizeof(struct pcap_pkthdr); + + /* copy the packet */ + memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen); + queue->len += pkt_header->caplen; + + return (0); +} + +u_int +pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue, int sync) +{ + return (p->sendqueue_transmit_op(p, queue, sync)); +} + +int +pcap_setuserbuffer(pcap_t *p, int size) +{ + return (p->setuserbuffer_op(p, size)); +} + +int +pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks) +{ + return (p->live_dump_op(p, filename, maxsize, maxpacks)); +} + +int +pcap_live_dump_ended(pcap_t *p, int sync) +{ + return (p->live_dump_ended_op(p, sync)); +} + +PAirpcapHandle +pcap_get_airpcap_handle(pcap_t *p) +{ + PAirpcapHandle handle; + + handle = p->get_airpcap_handle_op(p); + if (handle == NULL) { + (void)snprintf(p->errbuf, sizeof(p->errbuf), + "This isn't an AirPcap device"); + } + return (handle); +} +#endif + +/* + * On some platforms, we need to clean up promiscuous or monitor mode + * when we close a device - and we want that to happen even if the + * application just exits without explicitly closing devices. + * On those platforms, we need to register a "close all the pcaps" + * routine to be called when we exit, and need to maintain a list of + * pcaps that need to be closed to clean up modes. + * + * XXX - not thread-safe. + */ + +/* + * List of pcaps on which we've done something that needs to be + * cleaned up. + * If there are any such pcaps, we arrange to call "pcap_close_all()" + * when we exit, and have it close all of them. + */ +static struct pcap *pcaps_to_close; + +/* + * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to + * be called on exit. + */ +static int did_atexit; + +static void +pcap_close_all(void) +{ + struct pcap *handle; + + while ((handle = pcaps_to_close) != NULL) { + pcap_close(handle); + + /* + * If a pcap module adds a pcap_t to the "close all" + * list by calling pcapint_add_to_pcaps_to_close(), it + * must have a cleanup routine that removes it from the + * list, by calling pcapint_remove_from_pcaps_to_close(), + * and must make that cleanup routine the cleanup_op + * for the pcap_t. + * + * That means that, after pcap_close() - which calls + * the cleanup_op for the pcap_t - the pcap_t must + * have been removed from the list, so pcaps_to_close + * must not be equal to handle. + * + * We check for that, and abort if handle is still + * at the head of the list, to prevent infinite loops. + */ + if (pcaps_to_close == handle) + abort(); + } +} + +int +pcapint_do_addexit(pcap_t *p) +{ + /* + * If we haven't already done so, arrange to have + * "pcap_close_all()" called when we exit. + */ + if (!did_atexit) { + if (atexit(pcap_close_all) != 0) { + /* + * "atexit()" failed; let our caller know. + */ + pcapint_strlcpy(p->errbuf, "atexit failed", PCAP_ERRBUF_SIZE); + return (0); + } + did_atexit = 1; + } + return (1); +} + +void +pcapint_add_to_pcaps_to_close(pcap_t *p) +{ + p->next = pcaps_to_close; + pcaps_to_close = p; +} + +void +pcapint_remove_from_pcaps_to_close(pcap_t *p) +{ + pcap_t *pc, *prevpc; + + for (pc = pcaps_to_close, prevpc = NULL; pc != NULL; + prevpc = pc, pc = pc->next) { + if (pc == p) { + /* + * Found it. Remove it from the list. + */ + if (prevpc == NULL) { + /* + * It was at the head of the list. + */ + pcaps_to_close = pc->next; + } else { + /* + * It was in the middle of the list. + */ + prevpc->next = pc->next; + } + break; + } + } +} + +void +pcapint_breakloop_common(pcap_t *p) +{ + p->break_loop = 1; +} + + +void +pcapint_cleanup_live_common(pcap_t *p) +{ + if (p->opt.device != NULL) { + free(p->opt.device); + p->opt.device = NULL; + } + if (p->buffer != NULL) { + free(p->buffer); + p->buffer = NULL; + } + if (p->dlt_list != NULL) { + free(p->dlt_list); + p->dlt_list = NULL; + p->dlt_count = 0; + } + if (p->tstamp_type_list != NULL) { + free(p->tstamp_type_list); + p->tstamp_type_list = NULL; + p->tstamp_type_count = 0; + } + if (p->tstamp_precision_list != NULL) { + free(p->tstamp_precision_list); + p->tstamp_precision_list = NULL; + p->tstamp_precision_count = 0; + } + pcap_freecode(&p->fcode); +#if !defined(_WIN32) && !defined(MSDOS) + if (p->fd >= 0) { + close(p->fd); + p->fd = -1; + } + p->selectable_fd = -1; +#endif +} + +/* + * API compatible with WinPcap's "send a packet" routine - returns -1 + * on error, 0 otherwise. + * + * XXX - what if we get a short write? + */ +int +pcap_sendpacket(pcap_t *p, const u_char *buf, int size) +{ + if (size <= 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "The number of bytes to be sent must be positive"); + return (PCAP_ERROR); + } + + if (p->inject_op(p, buf, size) == -1) + return (-1); + return (0); +} + +/* + * API compatible with OpenBSD's "send a packet" routine - returns -1 on + * error, number of bytes written otherwise. + */ +int +pcap_inject(pcap_t *p, const void *buf, size_t size) +{ + /* + * We return the number of bytes written, so the number of + * bytes to write must fit in an int. + */ + if (size > INT_MAX) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "More than %d bytes cannot be injected", INT_MAX); + return (PCAP_ERROR); + } + + if (size == 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "The number of bytes to be injected must not be zero"); + return (PCAP_ERROR); + } + + return (p->inject_op(p, buf, (int)size)); +} + +void +pcap_close(pcap_t *p) +{ + p->cleanup_op(p); + free(p); +} + +/* + * Helpers for safely loading code at run time. + * Currently Windows-only. + */ +#ifdef _WIN32 +// +// This wrapper around loadlibrary appends the system folder (usually +// C:\Windows\System32) to the relative path of the DLL, so that the DLL +// is always loaded from an absolute path (it's no longer possible to +// load modules from the application folder). +// This solves the DLL Hijacking issue discovered in August 2010: +// +// https://blog.rapid7.com/2010/08/23/exploiting-dll-hijacking-flaws/ +// https://blog.rapid7.com/2010/08/23/application-dll-load-hijacking/ +// (the purported Rapid7 blog post link in the first of those two links +// is broken; the second of those links works.) +// +// If any links there are broken from all the content shuffling Rapid& +// did, see archived versions of the posts at their original homes, at +// +// https://web.archive.org/web/20110122175058/http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html +// https://web.archive.org/web/20100828112111/http://blog.rapid7.com/?p=5325 +// +pcap_code_handle_t +pcapint_load_code(const char *name) +{ + /* + * XXX - should this work in UTF-16LE rather than in the local + * ANSI code page? + */ + CHAR path[MAX_PATH]; + CHAR fullFileName[MAX_PATH]; + UINT res; + HMODULE hModule = NULL; + + do + { + res = GetSystemDirectoryA(path, MAX_PATH); + + if (res == 0) { + // + // some bad failure occurred; + // + break; + } + + if (res > MAX_PATH) { + // + // the buffer was not big enough + // + SetLastError(ERROR_INSUFFICIENT_BUFFER); + break; + } + + if (res + 1 + strlen(name) + 1 < MAX_PATH) { + memcpy(fullFileName, path, res * sizeof(TCHAR)); + fullFileName[res] = '\\'; + memcpy(&fullFileName[res + 1], name, (strlen(name) + 1) * sizeof(TCHAR)); + + hModule = LoadLibraryA(fullFileName); + } else + SetLastError(ERROR_INSUFFICIENT_BUFFER); + + } while(FALSE); + + return hModule; +} + +pcap_funcptr_t +pcapint_find_function(pcap_code_handle_t code, const char *func) +{ + return (GetProcAddress(code, func)); +} +#endif + +/* + * Given a BPF program, a pcap_pkthdr structure for a packet, and the raw + * data for the packet, check whether the packet passes the filter. + * Returns the return value of the filter program, which will be zero if + * the packet doesn't pass and non-zero if the packet does pass. + */ +int +pcap_offline_filter(const struct bpf_program *fp, const struct pcap_pkthdr *h, + const u_char *pkt) +{ + const struct bpf_insn *fcode = fp->bf_insns; + + if (fcode != NULL) + return (pcapint_filter(fcode, pkt, h->len, h->caplen)); + else + return (0); +} + +static int +pcap_can_set_rfmon_dead(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Rfmon mode doesn't apply on a pcap_open_dead pcap_t"); + return (PCAP_ERROR); +} + +static int +pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_, + u_char *user _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packets aren't available from a pcap_open_dead pcap_t"); + return (-1); +} + +static void +pcap_breakloop_dead(pcap_t *p _U_) +{ + /* + * A "dead" pcap_t is just a placeholder to use in order to + * compile a filter to BPF code or to open a savefile for + * writing. It doesn't support any operations, including + * capturing or reading packets, so there will never be a + * get-packets loop in progress to break out *of*. + * + * As such, this routine doesn't need to do anything. + */ +} + +static int +pcap_inject_dead(pcap_t *p, const void *buf _U_, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packets can't be sent on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_setfilter_dead(pcap_t *p, struct bpf_program *fp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A filter cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_setdirection_dead(pcap_t *p, pcap_direction_t d _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The packet direction cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_set_datalink_dead(pcap_t *p, int dlt _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The link-layer header type cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_getnonblock_dead(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A pcap_open_dead pcap_t does not have a non-blocking mode setting"); + return (-1); +} + +static int +pcap_setnonblock_dead(pcap_t *p, int nonblock _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A pcap_open_dead pcap_t does not have a non-blocking mode setting"); + return (-1); +} + +static int +pcap_stats_dead(pcap_t *p, struct pcap_stat *ps _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from a pcap_open_dead pcap_t"); + return (-1); +} + +#ifdef _WIN32 +static struct pcap_stat * +pcap_stats_ex_dead(pcap_t *p, int *pcap_stat_size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from a pcap_open_dead pcap_t"); + return (NULL); +} + +static int +pcap_setbuff_dead(pcap_t *p, int dim _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The kernel buffer size cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_setmode_dead(pcap_t *p, int mode _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "impossible to set mode on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_setmintocopy_dead(pcap_t *p, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The mintocopy parameter cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static HANDLE +pcap_getevent_dead(pcap_t *p) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A pcap_open_dead pcap_t has no event handle"); + return (INVALID_HANDLE_VALUE); +} + +static int +pcap_oid_get_request_dead(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID get request cannot be performed on a pcap_open_dead pcap_t"); + return (PCAP_ERROR); +} + +static int +pcap_oid_set_request_dead(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID set request cannot be performed on a pcap_open_dead pcap_t"); + return (PCAP_ERROR); +} + +static u_int +pcap_sendqueue_transmit_dead(pcap_t *p, pcap_send_queue *queue _U_, + int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Packets cannot be transmitted on a pcap_open_dead pcap_t"); + return (0); +} + +static int +pcap_setuserbuffer_dead(pcap_t *p, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The user buffer cannot be set on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_live_dump_dead(pcap_t *p, char *filename _U_, int maxsize _U_, + int maxpacks _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +static int +pcap_live_dump_ended_dead(pcap_t *p, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +static PAirpcapHandle +pcap_get_airpcap_handle_dead(pcap_t *p _U_) +{ + return (NULL); +} +#endif /* _WIN32 */ + +static void +pcap_cleanup_dead(pcap_t *p _U_) +{ + /* Nothing to do. */ +} + +pcap_t * +pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, u_int precision) +{ + pcap_t *p; + + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + case PCAP_TSTAMP_PRECISION_NANO: + break; + + default: + /* + * This doesn't really matter, but we don't have any way + * to report particular errors, so the only failure we + * should have is a memory allocation failure. Just + * pick microsecond precision. + */ + precision = PCAP_TSTAMP_PRECISION_MICRO; + break; + } + p = malloc(sizeof(*p)); + if (p == NULL) + return NULL; + memset (p, 0, sizeof(*p)); + p->snapshot = snaplen; + p->linktype = linktype; + p->opt.tstamp_precision = precision; + p->can_set_rfmon_op = pcap_can_set_rfmon_dead; + p->read_op = pcap_read_dead; + p->inject_op = pcap_inject_dead; + p->setfilter_op = pcap_setfilter_dead; + p->setdirection_op = pcap_setdirection_dead; + p->set_datalink_op = pcap_set_datalink_dead; + p->getnonblock_op = pcap_getnonblock_dead; + p->setnonblock_op = pcap_setnonblock_dead; + p->stats_op = pcap_stats_dead; +#ifdef _WIN32 + p->stats_ex_op = pcap_stats_ex_dead; + p->setbuff_op = pcap_setbuff_dead; + p->setmode_op = pcap_setmode_dead; + p->setmintocopy_op = pcap_setmintocopy_dead; + p->getevent_op = pcap_getevent_dead; + p->oid_get_request_op = pcap_oid_get_request_dead; + p->oid_set_request_op = pcap_oid_set_request_dead; + p->sendqueue_transmit_op = pcap_sendqueue_transmit_dead; + p->setuserbuffer_op = pcap_setuserbuffer_dead; + p->live_dump_op = pcap_live_dump_dead; + p->live_dump_ended_op = pcap_live_dump_ended_dead; + p->get_airpcap_handle_op = pcap_get_airpcap_handle_dead; +#endif + p->breakloop_op = pcap_breakloop_dead; + p->cleanup_op = pcap_cleanup_dead; + + /* + * A "dead" pcap_t never requires special BPF code generation. + */ + p->bpf_codegen_flags = 0; + + p->activated = 1; + return (p); +} + +pcap_t * +pcap_open_dead(int linktype, int snaplen) +{ + return (pcap_open_dead_with_tstamp_precision(linktype, snaplen, + PCAP_TSTAMP_PRECISION_MICRO)); +} + +#ifdef YYDEBUG +/* + * Set the internal "debug printout" flag for the filter expression parser. + * The code to print that stuff is present only if YYDEBUG is defined, so + * the flag, and the routine to set it, are defined only if YYDEBUG is + * defined. + * + * This is intended for libpcap developers, not for general use. + * If you want to set these in a program, you'll have to declare this + * routine yourself, with the appropriate DLL import attribute on Windows; + * it's not declared in any header file, and won't be declared in any + * header file provided by libpcap. + */ +PCAP_API void pcap_set_parser_debug(int value); + +PCAP_API_DEF void +pcap_set_parser_debug(int value) +{ + pcap_debug = value; +} +#endif diff --git a/src/libpcap-1.10.5/pcap.h b/src/libpcap-1.10.5/pcap.h new file mode 100644 index 0000000000..174e32d25f --- /dev/null +++ b/src/libpcap-1.10.5/pcap.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/src/libpcap-1.10.5/pcap/bluetooth.h b/src/libpcap-1.10.5/pcap/bluetooth.h new file mode 100644 index 0000000000..15dc5a827d --- /dev/null +++ b/src/libpcap-1.10.5/pcap/bluetooth.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * bluetooth data struct + * By Paolo Abeni + */ + +#ifndef lib_pcap_bluetooth_h +#define lib_pcap_bluetooth_h + +#include + +/* + * Header prepended libpcap to each bluetooth h4 frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + uint32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + +/* + * Header prepended libpcap to each bluetooth linux monitor frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_linux_monitor_header { + uint16_t adapter_id; + uint16_t opcode; +} pcap_bluetooth_linux_monitor_header; + +#endif diff --git a/src/libpcap-1.10.5/pcap/bpf.h b/src/libpcap-1.10.5/pcap/bpf.h new file mode 100644 index 0000000000..3970d0a184 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/bpf.h @@ -0,0 +1,291 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * At least two programs found by Google Code Search explicitly includes + * (even though / includes it for you), + * so moving that stuff to would break the build for some + * programs. + */ + +/* + * If we've already included , don't re-define this stuff. + * We assume BSD-style multiple-include protection in , + * which is true of all but the oldest versions of FreeBSD and NetBSD, + * or Tru64 UNIX-style multiple-include protection (or, at least, + * Tru64 UNIX 5.x-style; I don't have earlier versions available to check), + * or AIX-style multiple-include protection (or, at least, AIX 5.x-style; + * I don't have earlier versions available to check), or QNX-style + * multiple-include protection (as per GitHub pull request #394). + * + * We trust that they will define structures and macros and types in + * a fashion that's source-compatible and binary-compatible with our + * definitions. + * + * We do not check for BPF_MAJOR_VERSION, as that's defined by + * , which is directly or indirectly included in some + * programs that also include pcap.h, and doesn't + * define stuff we need. We *do* protect against + * defining various macros for BPF code itself; says + * + * Try and keep these values and structures similar to BSD, especially + * the BPF code definitions which need to match so you can share filters + * + * so we trust that it will define them in a fashion that's source-compatible + * and binary-compatible with our definitions. + * + * This also provides our own multiple-include protection. + */ +#if !defined(_NET_BPF_H_) && !defined(_NET_BPF_H_INCLUDED) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) +#define lib_pcap_bpf_h + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + * + * Tcpdump's print-pflog.c uses this, so we define it here. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * The instruction encodings. + * + * Please inform tcpdump-workers@lists.tcpdump.org if you use any + * of the reserved values, so that we can note that they're used + * (and perhaps implement it in the reference BPF implementation + * and encourage its implementation elsewhere). + */ + +/* + * The upper 8 bits of the opcode aren't used. BSD/OS used 0x8000. + */ + +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +/* 0x18 reserved; used by BSD/OS */ +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 +/* 0xc0 reserved; used by BSD/OS */ +/* 0xe0 reserved; used by BSD/OS */ + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_MOD 0x90 +#define BPF_XOR 0xa0 +/* 0xb0 reserved */ +/* 0xc0 reserved */ +/* 0xd0 reserved */ +/* 0xe0 reserved */ +/* 0xf0 reserved */ + +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +/* 0x50 reserved; used on BSD/OS */ +/* 0x60 reserved */ +/* 0x70 reserved */ +/* 0x80 reserved */ +/* 0x90 reserved */ +/* 0xa0 reserved */ +/* 0xb0 reserved */ +/* 0xc0 reserved */ +/* 0xd0 reserved */ +/* 0xe0 reserved */ +/* 0xf0 reserved */ +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 +/* 0x18 reserved */ + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +/* 0x08 reserved */ +/* 0x10 reserved */ +/* 0x18 reserved */ +/* #define BPF_COP 0x20 NetBSD "coprocessor" extensions */ +/* 0x28 reserved */ +/* 0x30 reserved */ +/* 0x38 reserved */ +/* #define BPF_COPX 0x40 NetBSD "coprocessor" extensions */ +/* also used on BSD/OS */ +/* 0x48 reserved */ +/* 0x50 reserved */ +/* 0x58 reserved */ +/* 0x60 reserved */ +/* 0x68 reserved */ +/* 0x70 reserved */ +/* 0x78 reserved */ +#define BPF_TXA 0x80 +/* 0x88 reserved */ +/* 0x90 reserved */ +/* 0x98 reserved */ +/* 0xa0 reserved */ +/* 0xa8 reserved */ +/* 0xb0 reserved */ +/* 0xb8 reserved */ +/* 0xc0 reserved; used on BSD/OS */ +/* 0xc8 reserved */ +/* 0xd0 reserved */ +/* 0xd8 reserved */ +/* 0xe0 reserved */ +/* 0xe8 reserved */ +/* 0xf0 reserved */ +/* 0xf8 reserved */ + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + * + * In case somebody's included , or something else that + * gives the kernel's definitions of BPF statements, get rid of its + * definitions, so we can supply ours instead. If some kernel's + * definitions aren't *binary-compatible* with what BPF has had + * since it first sprung from the brows of Van Jacobson and Steve + * McCanne, that kernel should be fixed. + */ +#ifdef BPF_STMT +#undef BPF_STMT +#endif +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#ifdef BPF_JUMP +#undef BPF_JUMP +#endif +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +PCAP_AVAILABLE_0_4 +PCAP_API u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); + +PCAP_AVAILABLE_0_6 +PCAP_API int bpf_validate(const struct bpf_insn *f, int len); + +PCAP_AVAILABLE_0_4 +PCAP_API char *bpf_image(const struct bpf_insn *, int); + +PCAP_AVAILABLE_0_6 +PCAP_API void bpf_dump(const struct bpf_program *, int); + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(_NET_BPF_H_) && !defined(_BPF_H_) && !defined(_H_BPF) && !defined(lib_pcap_bpf_h) */ diff --git a/src/libpcap-1.10.5/pcap/can_socketcan.h b/src/libpcap-1.10.5/pcap/can_socketcan.h new file mode 100644 index 0000000000..662bfe22cc --- /dev/null +++ b/src/libpcap-1.10.5/pcap/can_socketcan.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_can_socketcan_h +#define lib_pcap_can_socketcan_h + +#include + +/* + * SocketCAN header for CAN and CAN FD frames, as per + * Documentation/networking/can.rst in the Linux source. + */ +typedef struct { + uint32_t can_id; + uint8_t payload_length; + uint8_t fd_flags; + uint8_t reserved1; + uint8_t reserved2; +} pcap_can_socketcan_hdr; + +/* Bits in the fd_flags field */ +#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */ +#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */ +#define CANFD_FDF 0x04 /* mark CAN FD for dual use of CAN format */ + +/* + * SocketCAN header for CAN XL frames, as per Linux's can.h header. + * This is different from pcap_can_socketcan_hdr; the flags field + * overlaps with the payload_length field in pcap_can_socketcan_hdr - + * the payload_length field in a CAN or CAN FD frame never has the + * 0x80 bit set, and the flags field in a CAN XL frame always has + * it set, allowing code reading the frame to determine whether + * it's CAN XL or not. + */ +typedef struct { + uint32_t priority_vcid; + uint8_t flags; + uint8_t sdu_type; + uint16_t payload_length; + uint32_t acceptance_field; +} pcap_can_socketcan_xl_hdr; + +/* Bits in the flags field */ +#define CANXL_SEC 0x01 /* Simple Extended Context */ +#define CANXL_XLF 0x80 /* mark to distinguish CAN XL from CAN/CAN FD frames */ + +#endif diff --git a/src/libpcap-1.10.5/pcap/compiler-tests.h b/src/libpcap-1.10.5/pcap/compiler-tests.h new file mode 100644 index 0000000000..2d98a70705 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/compiler-tests.h @@ -0,0 +1,189 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_compiler_tests_h +#define lib_pcap_compiler_tests_h + +/* + * This was introduced by Clang: + * + * https://clang.llvm.org/docs/LanguageExtensions.html#has-attribute + * + * in some version (which version?); it has been picked up by GCC 5.0. + */ +#ifndef __has_attribute + /* + * It's a macro, so you can check whether it's defined to check + * whether it's supported. + * + * If it's not, define it to always return 0, so that we move on to + * the fallback checks. + */ + #define __has_attribute(x) 0 +#endif + +/* + * Note that the C90 spec's "6.8.1 Conditional inclusion" and the + * C99 spec's and C11 spec's "6.10.1 Conditional inclusion" say: + * + * Prior to evaluation, macro invocations in the list of preprocessing + * tokens that will become the controlling constant expression are + * replaced (except for those macro names modified by the defined unary + * operator), just as in normal text. If the token "defined" is + * generated as a result of this replacement process or use of the + * "defined" unary operator does not match one of the two specified + * forms prior to macro replacement, the behavior is undefined. + * + * so you shouldn't use defined() in a #define that's used in #if or + * #elif. Some versions of Clang, for example, will warn about this. + * + * Instead, we check whether the pre-defined macros for particular + * compilers are defined and, if not, define the "is this version XXX + * or a later version of this compiler" macros as 0. + */ + +/* + * Check whether this is GCC major.minor or a later release, or some + * compiler that claims to be "just like GCC" of that version or a + * later release. + */ + +#if ! defined(__GNUC__) + /* Not GCC and not "just like GCC" */ + #define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) 0 +#else + /* GCC or "just like GCC" */ + #define PCAP_IS_AT_LEAST_GNUC_VERSION(major, minor) \ + (__GNUC__ > (major) || \ + (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +#endif + +/* + * Check whether this is Clang major.minor or a later release. + */ + +#if !defined(__clang__) + /* Not Clang */ + #define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) 0 +#else + /* Clang */ + #define PCAP_IS_AT_LEAST_CLANG_VERSION(major, minor) \ + (__clang_major__ > (major) || \ + (__clang_major__ == (major) && __clang_minor__ >= (minor))) +#endif + +/* + * Check whether this is Sun C/SunPro C/Oracle Studio major.minor + * or a later release. + * + * The version number in __SUNPRO_C is encoded in hex BCD, with the + * uppermost hex digit being the major version number, the next + * one or two hex digits being the minor version number, and + * the last digit being the patch version. + * + * It represents the *compiler* version, not the product version; + * see + * + * https://sourceforge.net/p/predef/wiki/Compilers/ + * + * for a partial mapping, which we assume continues for later + * 12.x product releases. + */ + +#if ! defined(__SUNPRO_C) + /* Not Sun/Oracle C */ + #define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) 0 +#else + /* Sun/Oracle C */ + #define PCAP_SUNPRO_VERSION_TO_BCD(major, minor) \ + (((minor) >= 10) ? \ + (((major) << 12) | (((minor)/10) << 8) | (((minor)%10) << 4)) : \ + (((major) << 8) | ((minor) << 4))) + #define PCAP_IS_AT_LEAST_SUNC_VERSION(major,minor) \ + (__SUNPRO_C >= PCAP_SUNPRO_VERSION_TO_BCD((major), (minor))) +#endif + +/* + * Check whether this is IBM XL C major.minor or a later release. + * + * The version number in __xlC__ has the major version in the + * upper 8 bits and the minor version in the lower 8 bits. + * On AIX __xlC__ is always defined, __ibmxl__ becomes defined in XL C 16.1. + * On Linux since XL C 13.1.6 __xlC__ is not defined by default anymore, but + * __ibmxl__ is defined since at least XL C 13.1.1. + */ + +#if ! defined(__xlC__) && ! defined(__ibmxl__) + /* Not XL C */ + #define PCAP_IS_AT_LEAST_XL_C_VERSION(major,minor) 0 +#else + /* XL C */ + #if defined(__ibmxl__) + /* + * Later Linux version of XL C; use __ibmxl_version__ to test + * the version. + */ + #define PCAP_IS_AT_LEAST_XL_C_VERSION(major, minor) \ + (__ibmxl_version__ > (major) || \ + (__ibmxl_version__ == (major) && __ibmxl_release__ >= (minor))) + #else /* __ibmxl__ */ + /* + * __ibmxl__ not defined; use __xlC__ to test the version. + */ + #define PCAP_IS_AT_LEAST_XL_C_VERSION(major, minor) \ + (__xlC__ >= (((major) << 8) | (minor))) + #endif /* __ibmxl__ */ +#endif + +/* + * Check whether this is HP aC++/HP C major.minor or a later release. + * + * The version number in __HP_aCC is encoded in zero-padded decimal BCD, + * with the "A." stripped off, the uppermost two decimal digits being + * the major version number, the next two decimal digits being the minor + * version number, and the last two decimal digits being the patch version. + * (Strip off the A., remove the . between the major and minor version + * number, and add two digits of patch.) + */ + +#if ! defined(__HP_aCC) + /* Not HP C */ + #define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) 0 +#else + /* HP C */ + #define PCAP_IS_AT_LEAST_HP_C_VERSION(major,minor) \ + (__HP_aCC >= ((major)*10000 + (minor)*100)) +#endif + +#endif /* lib_pcap_compiler_tests_h */ diff --git a/src/libpcap-1.10.5/pcap/dlt.h b/src/libpcap-1.10.5/pcap/dlt.h new file mode 100644 index 0000000000..7f5f5aa4ad --- /dev/null +++ b/src/libpcap-1.10.5/pcap/dlt.h @@ -0,0 +1,1593 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + */ + +#ifndef lib_pcap_dlt_h +#define lib_pcap_dlt_h + +/* + * Link-layer header type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + * + * See + * + * https://www.tcpdump.org/linktypes.html + * + * for detailed descriptions of some of these link-layer header types. + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + * + * DLT_LOW_MATCHING_MIN is the lowest such value; DLT_LOW_MATCHING_MAX + * is the highest such value. + */ +#define DLT_LOW_MATCHING_MIN 0 + +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * In case the code that includes this file (directly or indirectly) + * has also included OS files that happen to define DLT_LOW_MATCHING_MAX, + * with a different value (perhaps because that OS hasn't picked up + * the latest version of our DLT definitions), we undefine the + * previous value of DLT_LOW_MATCHING_MAX. + * + * (They shouldn't, because only those 10 values were assigned in + * the Good Old Days, before DLT_ code assignment became a bit of + * a free-for-all. Perhaps 11 is DLT_ATM_RFC1483 everywhere 11 + * is used at all, but 12 is DLT_RAW on some platforms but not + * OpenBSD, and the fun continues for several other values.) + */ +#ifdef DLT_LOW_MATCHING_MAX +#undef DLT_LOW_MATCHING_MAX +#endif + +#define DLT_LOW_MATCHING_MAX DLT_FDDI /* highest value in this "matching" range */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. The last + * release was in October 2003; if anybody cares about making this + * work on BSD/OS, give us a pull request for a change to make it work. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * NetBSD uses 15 for HIPPI. + * + * From a quick look at sys/net/if_hippi.h and sys/net/if_hippisubr.c + * in an older version of NetBSD , the header appears to be: + * + * a 1-byte ULP field (ULP-id)? + * + * a 1-byte flags field; + * + * a 2-byte "offsets" field; + * + * a 4-byte "D2 length" field (D2_Size?); + * + * a 4-byte "destination switch" field (or a 1-byte field + * containing the Forwarding Class, Double_Wide, and Message_Type + * sub fields, followed by a 3-byte Destination_Switch_Address + * field?, HIPPI-LE 3.4-style?); + * + * a 4-byte "source switch" field (or a 1-byte field containing the + * Destination_Address_type and Source_Address_Type fields, followed + * by a 3-byte Source_Switch_Address field, HIPPI-LE 3.4-style?); + * + * a 2-byte reserved field; + * + * a 6-byte destination address field; + * + * a 2-byte "local admin" field; + * + * a 6-byte source address field; + * + * followed by an 802.2 LLC header. + * + * This looks somewhat like something derived from the HIPPI-FP 4.4 + * Header_Area, followed an HIPPI-FP 4.4 D1_Area containing a D1 data set + * with the header in HIPPI-LE 3.4 (ANSI X3.218-1993), followed by an + * HIPPI-FP 4.4 D2_Area (with no Offset) containing the 802.2 LLC header + * and payload? Or does the "offsets" field contain the D2_Offset, + * with that many bytes of offset before the payload? + * + * See http://wotug.org/parallel/standards/hippi/ for an archive of + * HIPPI specifications. + * + * RFC 2067 imposes some additional restrictions. It says that the + * Offset is always zero + * + * HIPPI is long-gone, and the source files found in an older version + * of NetBSD don't appear to be in the main CVS branch, so we may never + * see a capture with this link-layer type. + */ +#if defined(__NetBSD__) +#define DLT_HIPPI 15 /* HIPPI */ +#endif + +/* + * NetBSD uses 16 for DLT_HDLC; see below. + * BSD/OS uses it for PPP; see above. + * As far as I know, no other OS uses it for anything; don't use it + * for anything else. + */ + +/* + * 17 was used for DLT_PFLOG in OpenBSD; it no longer is. + * + * It was DLT_LANE8023 in SuSE 6.3, so we defined LINKTYPE_PFLOG + * as 117 so that pflog captures would use a link-layer header type + * value that didn't collide with any other values. On all + * platforms other than OpenBSD, we defined DLT_PFLOG as 117, + * and we mapped between LINKTYPE_PFLOG and DLT_PFLOG. + * + * OpenBSD eventually switched to using 117 for DLT_PFLOG as well. + * + * Don't use 17 for anything else. + */ + +/* + * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and + * macOS; don't use it for anything else. (FreeBSD uses 121, which + * collides with DLT_HHDLC, even though it doesn't use 18 for + * anything and doesn't appear to have ever used it for anything.) + * + * We define it as 18 on those platforms; it is, unfortunately, used + * for DLT_CIP in SUSE 6.3, so we don't define it as 18 on all + * platforms. We define it as 121 on FreeBSD and as the same + * value that we assigned to LINKTYPE_PFSYNC on all remaining + * platforms. + */ +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) +#define DLT_PFSYNC 18 +#endif + +#define DLT_ATM_CLIP 19 /* Linux Classical IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer header type LINKTYPE_ values corresponding to DLT_ types + * that differ between platforms; don't use those values for new DLT_ + * new types. + */ + +/* + * Values starting with 104 are used for newly-assigned link-layer + * header type values; for those link-layer header types, the DLT_ + * value returned by pcap_datalink() and passed to pcap_open_dead(), + * and the LINKTYPE_ value that appears in capture files, are the + * same. + * + * DLT_HIGH_MATCHING_MIN is the lowest such value; DLT_HIGH_MATCHING_MAX is + * the highest such value. + */ +#define DLT_HIGH_MATCHING_MIN 104 + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD; instead, we + * use the same value as LINKTYPE_LOOP. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD; instead, we use the same value as LINKTYPE_ENC. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values 110 and 111 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * NetBSD uses 16 for (Cisco) "HDLC framing". For other platforms, + * we define it to have the same value as LINKTYPE_NETBSD_HDLC. + */ +#if defined(__NetBSD__) +#define DLT_HDLC 16 /* Cisco HDLC */ +#else +#define DLT_HDLC 112 +#endif + +/* + * Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG. + */ +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Sigh. + * + * 121 was reserved for Siemens HiPath HDLC on 2002-01-25, as + * requested by Tomas Kukosa. + * + * On 2004-02-25, a FreeBSD checkin to sys/net/bpf.h was made that + * assigned 121 as DLT_PFSYNC. In current versions, its libpcap + * does DLT_ <-> LINKTYPE_ mapping, mapping DLT_PFSYNC to a + * LINKTYPE_PFSYNC value of 246, so it should write out DLT_PFSYNC + * dump files with 246 as the link-layer header type. (Earlier + * versions might not have done mapping, in which case they would + * have written them out with a link-layer header type of 121.) + * + * OpenBSD, from which pf came, however, uses 18 for DLT_PFSYNC; + * its libpcap does no DLT_ <-> LINKTYPE_ mapping, so it would + * write out DLT_PFSYNC dump files with use 18 as the link-layer + * header type. + * + * NetBSD, DragonFly BSD, and Darwin also use 18 for DLT_PFSYNC; in + * current versions, their libpcaps do DLT_ <-> LINKTYPE_ mapping, + * mapping DLT_PFSYNC to a LINKTYPE_PFSYNC value of 246, so they + * should write out DLT_PFSYNC dump files with 246 as the link-layer + * header type. (Earlier versions might not have done mapping, + * in which case they'd work the same way OpenBSD does, writing + * them out with a link-layer header type of 18.) + * + * We'll define DLT_PFSYNC as: + * + * 18 on NetBSD, OpenBSD, DragonFly BSD, and Darwin; + * + * 121 on FreeBSD; + * + * 246 everywhere else. + * + * We'll define DLT_HHDLC as 121 on everything except for FreeBSD; + * anybody who wants to compile, on FreeBSD, code that uses DLT_HHDLC + * is out of luck. + * + * We'll define LINKTYPE_PFSYNC as 246 on *all* platforms, so that + * savefiles written using *this* code won't use 18 or 121 for PFSYNC, + * they'll all use 246. + * + * Code that uses pcap_datalink() to determine the link-layer header + * type of a savefile won't, when built and run on FreeBSD, be able + * to distinguish between LINKTYPE_PFSYNC and LINKTYPE_HHDLC capture + * files, as pcap_datalink() will give 121 for both of them. Code + * that doesn't, such as the code in Wireshark, will be able to + * distinguish between them. + * + * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e., + * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD, + * DragonFly BSD, and macOS - to DLT_PFSYNC, so code built with FreeBSD's + * libpcap won't treat those files as DLT_PFSYNC files. + * + * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC; + * this means they can read DLT_HHDLC files, if any exist, but won't + * treat pcap files written by any older versions of FreeBSD libpcap that + * didn't map to 246 as DLT_PFSYNC files. + */ +#ifdef __FreeBSD__ +#define DLT_PFSYNC 121 +#else +#define DLT_HHDLC 121 +#endif + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at https://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependent on the direction of the packet (incoming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * BACnet MS/TP frames. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accommodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * https://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * https://web.archive.org/web/20040616233302/https://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * This used to be "USB packets, beginning with a USB setup header; + * requested by Paolo Abeni ." + * + * However, that header didn't work all that well - it left out some + * useful information - and was abandoned in favor of the DLT_USB_LINUX + * header. + * + * This is now used by FreeBSD for its BPF taps for USB; that has its + * own headers. So it is written, so it is done. + * + * For source-code compatibility, we also define DLT_USB to have this + * value. We do it numerically so that, if code that includes this + * file (directly or indirectly) also includes an OS header that also + * defines DLT_USB as 186, we don't get a redefinition warning. + * (NetBSD 7 does that.) + */ +#define DLT_USB_FREEBSD 186 +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + * For this one, we expect the FCS to be present at the end of the frame; + * if the frame has no FCS, DLT_IEEE802_15_4_NOFCS should be used. + * + * We keep the name DLT_IEEE802_15_4 as an alias for backwards + * compatibility, but, again, this should *only* be used for 802.15.4 + * frames that include the FCS. + */ +#define DLT_IEEE802_15_4_WITHFCS 195 +#define DLT_IEEE802_15_4 DLT_IEEE802_15_4_WITHFCS + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (https://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with a 2-byte header, followed by + * the I2C slave address, followed by the netFn and LUN, etc.. + * Requested by Chanthy Toeung . + * + * XXX - this used to be called DLT_IPMB, back when we got the + * impression from the email thread requesting it that the packet + * had no extra 2-byte header. We've renamed it; if anybody used + * DLT_IPMB and assumed no 2-byte header, this will cause the compile + * to fail, at which point we'll have to figure out what to do about + * the two header types using the same DLT_/LINKTYPE_ value. If that + * doesn't happen, we'll assume nobody used it and that the redefinition + * is safe. + */ +#define DLT_IPMB_KONTRON 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * PPP, with a one-byte direction pseudo-header prepended - zero means + * "received by this host", non-zero (any non-zero value) means "sent by + * this host" - as per Will Barker . + * + * Don't confuse this with DLT_PPP_WITH_DIRECTION, which is an old + * name for what is now called DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIR 204 + +/* + * Cisco HDLC, with a one-byte direction pseudo-header prepended - zero + * means "received by this host", non-zero (any non-zero value) means + * "sent by this host" - as per Will Barker . + */ +#define DLT_C_HDLC_WITH_DIR 205 + +/* + * Frame Relay, with a one-byte direction pseudo-header prepended - zero + * means "received by this host" (DCE -> DTE), non-zero (any non-zero + * value) means "sent by this host" (DTE -> DCE) - as per Will Barker + * . + */ +#define DLT_FRELAY_WITH_DIR 206 + +/* + * LAPB, with a one-byte direction pseudo-header prepended - zero means + * "received by this host" (DCE -> DTE), non-zero (any non-zero value) + * means "sent by this host" (DTE -> DCE)- as per Will Barker + * . + */ +#define DLT_LAPB_WITH_DIR 207 + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - https://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + +/* + * David Gibson requested this for + * captures from the Linux kernel /dev/input/eventN devices. This + * is used to communicate keystrokes and mouse movements from the + * Linux kernel to display systems, such as Xorg. + */ +#define DLT_LINUX_EVDEV 216 + +/* + * GSM Um and Abis interfaces, preceded by a "gsmtap" header. + * + * Requested by Harald Welte . + */ +#define DLT_GSMTAP_UM 217 +#define DLT_GSMTAP_ABIS 218 + +/* + * MPLS, with an MPLS label as the link-layer header. + * Requested by Michele Marchetto on behalf + * of OpenBSD. + */ +#define DLT_MPLS 219 + +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define DLT_USB_LINUX_MMAPPED 220 + +/* + * DECT packets, with a pseudo-header; requested by + * Matthias Wenzel . + */ +#define DLT_DECT 221 + +/* + * From: "Lidwa, Eric (GSFC-582.0)[SGT INC]" + * Date: Mon, 11 May 2009 11:18:30 -0500 + * + * DLT_AOS. We need it for AOS Space Data Link Protocol. + * I have already written dissectors for but need an OK from + * legal before I can submit a patch. + * + */ +#define DLT_AOS 222 + +/* + * WirelessHART (Highway Addressable Remote Transducer) + * From the HART Communication Foundation + * IEC/PAS 62591 + * + * Requested by Sam Roberts . + */ +#define DLT_WIHART 223 + +/* + * Fibre Channel FC-2 frames, beginning with a Frame_Header. + * Requested by Kahou Lei . + */ +#define DLT_FC_2 224 + +/* + * Fibre Channel FC-2 frames, beginning with an encoding of the + * SOF, and ending with an encoding of the EOF. + * + * The encodings represent the frame delimiters as 4-byte sequences + * representing the corresponding ordered sets, with K28.5 + * represented as 0xBC, and the D symbols as the corresponding + * byte values; for example, SOFi2, which is K28.5 - D21.5 - D1.2 - D21.2, + * is represented as 0xBC 0xB5 0x55 0x55. + * + * Requested by Kahou Lei . + */ +#define DLT_FC_2_WITH_FRAME_DELIMS 225 + +/* + * Solaris ipnet pseudo-header; requested by Darren Reed . + * + * The pseudo-header starts with a one-byte version number; for version 2, + * the pseudo-header is: + * + * struct dl_ipnetinfo { + * uint8_t dli_version; + * uint8_t dli_family; + * uint16_t dli_htype; + * uint32_t dli_pktlen; + * uint32_t dli_ifindex; + * uint32_t dli_grifindex; + * uint32_t dli_zsrc; + * uint32_t dli_zdst; + * }; + * + * dli_version is 2 for the current version of the pseudo-header. + * + * dli_family is a Solaris address family value, so it's 2 for IPv4 + * and 26 for IPv6. + * + * dli_htype is a "hook type" - 0 for incoming packets, 1 for outgoing + * packets, and 2 for packets arriving from another zone on the same + * machine. + * + * dli_pktlen is the length of the packet data following the pseudo-header + * (so the captured length minus dli_pktlen is the length of the + * pseudo-header, assuming the entire pseudo-header was captured). + * + * dli_ifindex is the interface index of the interface on which the + * packet arrived. + * + * dli_grifindex is the group interface index number (for IPMP interfaces). + * + * dli_zsrc is the zone identifier for the source of the packet. + * + * dli_zdst is the zone identifier for the destination of the packet. + * + * A zone number of 0 is the global zone; a zone number of 0xffffffff + * means that the packet arrived from another host on the network, not + * from another zone on the same machine. + * + * An IPv4 or IPv6 datagram follows the pseudo-header; dli_family indicates + * which of those it is. + */ +#define DLT_IPNET 226 + +/* + * CAN (Controller Area Network) frames, with a pseudo-header as supplied + * by Linux SocketCAN, and with multi-byte numerical fields in that header + * in big-endian byte order. + * + * See Documentation/networking/can.txt in the Linux source. + * + * Requested by Felix Obenhuber . + */ +#define DLT_CAN_SOCKETCAN 227 + +/* + * Raw IPv4/IPv6; different from DLT_RAW in that the DLT_ value specifies + * whether it's v4 or v6. Requested by Darren Reed . + */ +#define DLT_IPV4 228 +#define DLT_IPV6 229 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), and with no FCS at the end of the frame; requested by + * Jon Smirl . + */ +#define DLT_IEEE802_15_4_NOFCS 230 + +/* + * Raw D-Bus: + * + * https://www.freedesktop.org/wiki/Software/dbus + * + * messages: + * + * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages + * + * starting with the endianness flag, followed by the message type, etc., + * but without the authentication handshake before the message sequence: + * + * https://dbus.freedesktop.org/doc/dbus-specification.html#auth-protocol + * + * Requested by Martin Vidner . + */ +#define DLT_DBUS 231 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define DLT_JUNIPER_VS 232 +#define DLT_JUNIPER_SRX_E2E 233 +#define DLT_JUNIPER_FIBRECHANNEL 234 + +/* + * DVB-CI (DVB Common Interface for communication between a PC Card + * module and a DVB receiver). See + * + * https://www.kaiser.cx/pcap-dvbci.html + * + * for the specification. + * + * Requested by Martin Kaiser . + */ +#define DLT_DVB_CI 235 + +/* + * Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but + * *not* the same as, 27.010). Requested by Hans-Christoph Schemmel + * . + */ +#define DLT_MUX27010 236 + +/* + * STANAG 5066 D_PDUs. Requested by M. Baris Demiray + * . + */ +#define DLT_STANAG_5066_D_PDU 237 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + */ +#define DLT_JUNIPER_ATM_CEMIC 238 + +/* + * NetFilter LOG messages + * (payload of netlink NFNL_SUBSYS_ULOG/NFULNL_MSG_PACKET packets) + * + * Requested by Jakub Zawadzki + */ +#define DLT_NFLOG 239 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and always + * with the payload including the FCS, as supplied by their + * netANALYZER hardware and software. + * + * Requested by Holger P. Frommer + */ +#define DLT_NETANALYZER 240 + +/* + * Hilscher Gesellschaft fuer Systemautomation mbH link-layer type + * for Ethernet packets with a 4-byte pseudo-header and FCS and + * with the Ethernet header preceded by 7 bytes of preamble and + * 1 byte of SFD, as supplied by their netANALYZER hardware and + * software. + * + * Requested by Holger P. Frommer + */ +#define DLT_NETANALYZER_TRANSPARENT 241 + +/* + * IP-over-InfiniBand, as specified by RFC 4391. + * + * Requested by Petr Sumbera . + */ +#define DLT_IPOIB 242 + +/* + * MPEG-2 transport stream (ISO 13818-1/ITU-T H.222.0). + * + * Requested by Guy Martin . + */ +#define DLT_MPEG_2_TS 243 + +/* + * ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as + * used by their ng40 protocol tester. + * + * Requested by Jens Grimmer . + */ +#define DLT_NG40 244 + +/* + * Pseudo-header giving adapter number and flags, followed by an NFC + * (Near-Field Communications) Logical Link Control Protocol (LLCP) PDU, + * as specified by NFC Forum Logical Link Control Protocol Technical + * Specification LLCP 1.1. + * + * Requested by Mike Wakerly . + */ +#define DLT_NFC_LLCP 245 + +/* + * 246 is used as LINKTYPE_PFSYNC; do not use it for any other purpose. + * + * DLT_PFSYNC has different values on different platforms, and all of + * them collide with something used elsewhere. On platforms that + * don't already define it, define it as 246. + */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__APPLE__) +#define DLT_PFSYNC 246 +#endif + +/* + * Raw InfiniBand packets, starting with the Local Routing Header. + * + * Requested by Oren Kladnitsky . + */ +#define DLT_INFINIBAND 247 + +/* + * SCTP, with no lower-level protocols (i.e., no IPv4 or IPv6). + * + * Requested by Michael Tuexen . + */ +#define DLT_SCTP 248 + +/* + * USB packets, beginning with a USBPcap header. + * + * Requested by Tomasz Mon + */ +#define DLT_USBPCAP 249 + +/* + * Schweitzer Engineering Laboratories "RTAC" product serial-line + * packets. + * + * Requested by Chris Bontje . + */ +#define DLT_RTAC_SERIAL 250 + +/* + * Bluetooth Low Energy air interface link-layer packets. + * + * Requested by Mike Kershaw . + */ +#define DLT_BLUETOOTH_LE_LL 251 + +/* + * DLT type for upper-protocol layer PDU saves from Wireshark. + * + * the actual contents are determined by two TAGs, one or more of + * which is stored with each packet: + * + * EXP_PDU_TAG_DISSECTOR_NAME the name of the Wireshark dissector + * that can make sense of the data stored. + * + * EXP_PDU_TAG_HEUR_DISSECTOR_NAME the name of the Wireshark heuristic + * dissector that can make sense of the + * data stored. + */ +#define DLT_WIRESHARK_UPPER_PDU 252 + +/* + * DLT type for the netlink protocol (nlmon devices). + */ +#define DLT_NETLINK 253 + +/* + * Bluetooth Linux Monitor headers for the BlueZ stack. + */ +#define DLT_BLUETOOTH_LINUX_MONITOR 254 + +/* + * Bluetooth Basic Rate/Enhanced Data Rate baseband packets, as + * captured by Ubertooth. + */ +#define DLT_BLUETOOTH_BREDR_BB 255 + +/* + * Bluetooth Low Energy link layer packets, as captured by Ubertooth. + */ +#define DLT_BLUETOOTH_LE_LL_WITH_PHDR 256 + +/* + * PROFIBUS data link layer. + */ +#define DLT_PROFIBUS_DL 257 + +/* + * Apple's DLT_PKTAP headers. + * + * Sadly, the folks at Apple either had no clue that the DLT_USERn values + * are for internal use within an organization and partners only, and + * didn't know that the right way to get a link-layer header type is to + * ask tcpdump.org for one, or knew and didn't care, so they just + * used DLT_USER2, which causes problems for everything except for + * their version of tcpdump. + * + * So I'll just give them one; hopefully this will show up in a + * libpcap release in time for them to get this into 10.10 Big Sur + * or whatever Mavericks' successor is called. LINKTYPE_PKTAP + * will be 258 *even on macOS*; that is *intentional*, so that + * PKTAP files look the same on *all* OSes (different OSes can have + * different numerical values for a given DLT_, but *MUST NOT* have + * different values for what goes in a file, as files can be moved + * between OSes!). + * + * When capturing, on a system with a Darwin-based OS, on a device + * that returns 149 (DLT_USER2 and Apple's DLT_PKTAP) with this + * version of libpcap, the DLT_ value for the pcap_t will be DLT_PKTAP, + * and that will continue to be DLT_USER2 on Darwin-based OSes. That way, + * binary compatibility with Mavericks is preserved for programs using + * this version of libpcap. This does mean that if you were using + * DLT_USER2 for some capture device on macOS, you can't do so with + * this version of libpcap, just as you can't with Apple's libpcap - + * on macOS, they define DLT_PKTAP to be DLT_USER2, so programs won't + * be able to distinguish between PKTAP and whatever you were using + * DLT_USER2 for. + * + * If the program saves the capture to a file using this version of + * libpcap's pcap_dump code, the LINKTYPE_ value in the file will be + * LINKTYPE_PKTAP, which will be 258, even on Darwin-based OSes. + * That way, the file will *not* be a DLT_USER2 file. That means + * that the latest version of tcpdump, when built with this version + * of libpcap, and sufficiently recent versions of Wireshark will + * be able to read those files and interpret them correctly; however, + * Apple's version of tcpdump in OS X 10.9 won't be able to handle + * them. (Hopefully, Apple will pick up this version of libpcap, + * and the corresponding version of tcpdump, so that tcpdump will + * be able to handle the old LINKTYPE_USER2 captures *and* the new + * LINKTYPE_PKTAP captures.) + */ +#ifdef __APPLE__ +#define DLT_PKTAP DLT_USER2 +#else +#define DLT_PKTAP 258 +#endif + +/* + * Ethernet packets preceded by a header giving the last 6 octets + * of the preamble specified by 802.3-2012 Clause 65, section + * 65.1.3.2 "Transmit". + */ +#define DLT_EPON 259 + +/* + * IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" + * in the PICMG HPM.2 specification. + */ +#define DLT_IPMI_HPM_2 260 + +/* + * per Joshua Wright , formats for Zwave captures. + */ +#define DLT_ZWAVE_R1_R2 261 +#define DLT_ZWAVE_R3 262 + +/* + * per Steve Karg , formats for Wattstopper + * Digital Lighting Management room bus serial protocol captures. + */ +#define DLT_WATTSTOPPER_DLM 263 + +/* + * ISO 14443 contactless smart card messages. + */ +#define DLT_ISO_14443 264 + +/* + * Radio data system (RDS) groups. IEC 62106. + * Per Jonathan Brucker . + */ +#define DLT_RDS 265 + +/* + * USB packets, beginning with a Darwin (macOS, etc.) header. + */ +#define DLT_USB_DARWIN 266 + +/* + * OpenBSD DLT_OPENFLOW. + */ +#define DLT_OPENFLOW 267 + +/* + * SDLC frames containing SNA PDUs. + */ +#define DLT_SDLC 268 + +/* + * per "Selvig, Bjorn" used for + * TI protocol sniffer. + */ +#define DLT_TI_LLN_SNIFFER 269 + +/* + * per: Erik de Jong for + * https://github.com/eriknl/LoRaTap/releases/tag/v0.1 + */ +#define DLT_LORATAP 270 + +/* + * per: Stefanha at gmail.com for + * https://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html + * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h + * for: https://qemu-project.org/Features/VirtioVsock + */ +#define DLT_VSOCK 271 + +/* + * Nordic Semiconductor Bluetooth LE sniffer. + */ +#define DLT_NORDIC_BLE 272 + +/* + * Excentis DOCSIS 3.1 RF sniffer (XRA-31) + * per: bruno.verstuyft at excentis.com + * https://www.xra31.com/xra-header + */ +#define DLT_DOCSIS31_XRA31 273 + +/* + * mPackets, as specified by IEEE 802.3br Figure 99-4, starting + * with the preamble and always ending with a CRC field. + */ +#define DLT_ETHERNET_MPACKET 274 + +/* + * DisplayPort AUX channel monitoring data as specified by VESA + * DisplayPort(DP) Standard preceded by a pseudo-header. + * per dirk.eibach at gdsys.cc + */ +#define DLT_DISPLAYPORT_AUX 275 + +/* + * Linux cooked sockets v2. + */ +#define DLT_LINUX_SLL2 276 + +/* + * Sercos Monitor, per Manuel Jacob + */ +#define DLT_SERCOS_MONITOR 277 + +/* + * OpenVizsla http://openvizsla.org is open source USB analyzer hardware. + * It consists of FPGA with attached USB phy and FTDI chip for streaming + * the data to the host PC. + * + * Current OpenVizsla data encapsulation format is described here: + * https://github.com/matwey/libopenvizsla/wiki/OpenVizsla-protocol-description + * + */ +#define DLT_OPENVIZSLA 278 + +/* + * The Elektrobit High Speed Capture and Replay (EBHSCR) protocol is produced + * by a PCIe Card for interfacing high speed automotive interfaces. + * + * The specification for this frame format can be found at: + * https://www.elektrobit.com/ebhscr + * + * for Guenter.Ebermann at elektrobit.com + * + */ +#define DLT_EBHSCR 279 + +/* + * The https://fd.io vpp graph dispatch tracer produces pcap trace files + * in the format documented here: + * https://fdio-vpp.readthedocs.io/en/latest/gettingstarted/developers/vnet.html#graph-dispatcher-pcap-tracing + */ +#define DLT_VPP_DISPATCH 280 + +/* + * Broadcom Ethernet switches (ROBO switch) 4 bytes proprietary tagging format. + */ +#define DLT_DSA_TAG_BRCM 281 +#define DLT_DSA_TAG_BRCM_PREPEND 282 + +/* + * IEEE 802.15.4 with pseudo-header and optional meta-data TLVs, PHY payload + * exactly as it appears in the spec (no padding, no nothing), and FCS if + * specified by FCS Type TLV; requested by James Ko . + * Specification at https://github.com/jkcko/ieee802.15.4-tap + */ +#define DLT_IEEE802_15_4_TAP 283 + +/* + * Marvell (Ethertype) Distributed Switch Architecture proprietary tagging format. + */ +#define DLT_DSA_TAG_DSA 284 +#define DLT_DSA_TAG_EDSA 285 + +/* + * Payload of lawful intercept packets using the ELEE protocol; + * https://socket.hr/draft-dfranusic-opsawg-elee-00.xml + * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://socket.hr/draft-dfranusic-opsawg-elee-00.xml&modeAsFormat=html/ascii + */ +#define DLT_ELEE 286 + +/* + * Serial frames transmitted between a host and a Z-Wave chip. + */ +#define DLT_Z_WAVE_SERIAL 287 + +/* + * USB 2.0, 1.1, and 1.0 packets as transmitted over the cable. + */ +#define DLT_USB_2_0 288 + +/* + * ATSC Link-Layer Protocol (A/330) packets. + */ +#define DLT_ATSC_ALP 289 + +/* + * In case the code that includes this file (directly or indirectly) + * has also included OS files that happen to define DLT_HIGH_MATCHING_MAX, + * with a different value (perhaps because that OS hasn't picked up + * the latest version of our DLT definitions), we undefine the + * previous value of DLT_HIGH_MATCHING_MAX. + */ +#ifdef DLT_HIGH_MATCHING_MAX +#undef DLT_HIGH_MATCHING_MAX +#endif +#define DLT_HIGH_MATCHING_MAX 289 /* highest value in the "matching" range */ + +#endif /* !defined(lib_pcap_dlt_h) */ diff --git a/src/libpcap-1.10.5/pcap/funcattrs.h b/src/libpcap-1.10.5/pcap/funcattrs.h new file mode 100644 index 0000000000..f6baf85192 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/funcattrs.h @@ -0,0 +1,359 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_funcattrs_h +#define lib_pcap_funcattrs_h + +#include + +/* + * Attributes to apply to functions and their arguments, using various + * compiler-specific extensions. + */ + +/* + * PCAP_API_DEF must be used when defining *data* exported from + * libpcap. It can be used when defining *functions* exported + * from libpcap, but it doesn't have to be used there. It + * should not be used in declarations in headers. + * + * PCAP_API must be used when *declaring* data or functions + * exported from libpcap; PCAP_API_DEF won't work on all platforms. + */ + +#if defined(_WIN32) + /* + * For Windows: + * + * when building libpcap: + * + * if we're building it as a DLL, we have to declare API + * functions with __declspec(dllexport); + * + * if we're building it as a static library, we don't want + * to do so. + * + * when using libpcap: + * + * if we're using the DLL, calls to its functions are a + * little more efficient if they're declared with + * __declspec(dllimport); + * + * if we're not using the dll, we don't want to declare + * them that way. + * + * So: + * + * if pcap_EXPORTS is defined, we define PCAP_API_DEF as + * __declspec(dllexport); + * + * if PCAP_DLL is defined, we define PCAP_API_DEF as + * __declspec(dllimport); + * + * otherwise, we define PCAP_API_DEF as nothing. + */ + #if defined(pcap_EXPORTS) + /* + * We're compiling libpcap as a DLL, so we should export functions + * in our API. + */ + #define PCAP_API_DEF __declspec(dllexport) + #elif defined(PCAP_DLL) + /* + * We're using libpcap as a DLL, so the calls will be a little more + * efficient if we explicitly import the functions. + */ + #define PCAP_API_DEF __declspec(dllimport) + #else + /* + * Either we're building libpcap as a static library, or we're using + * it as a static library, or we don't know for certain that we're + * using it as a dynamic library, so neither import nor export the + * functions explicitly. + */ + #define PCAP_API_DEF + #endif +#elif defined(MSDOS) + /* XXX - does this need special treatment? */ + #define PCAP_API_DEF +#else /* UN*X */ + #ifdef pcap_EXPORTS + /* + * We're compiling libpcap as a (dynamic) shared library, so we should + * export functions in our API. The compiler might be configured not + * to export functions from a shared library by default, so we might + * have to explicitly mark functions as exported. + */ + #if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4) \ + || PCAP_IS_AT_LEAST_XL_C_VERSION(12,0) + /* + * GCC 3.4 and later, or some compiler asserting compatibility with + * GCC 3.4 and later, or XL C 13.0 and later, so we have + * __attribute__((visibility()). + */ + #define PCAP_API_DEF __attribute__((visibility("default"))) + #elif PCAP_IS_AT_LEAST_SUNC_VERSION(5,5) + /* + * Sun C 5.5 and later, so we have __global. + * (Sun C 5.9 and later also have __attribute__((visibility()), + * but there's no reason to prefer it with Sun C.) + */ + #define PCAP_API_DEF __global + #else + /* + * We don't have anything to say. + */ + #define PCAP_API_DEF + #endif + #else + /* + * We're not building libpcap. + */ + #define PCAP_API_DEF + #endif +#endif /* _WIN32/MSDOS/UN*X */ + +#define PCAP_API PCAP_API_DEF extern + +/* + * Definitions to 1) indicate what version of libpcap first had a given + * API and 2) allow upstream providers whose build environments allow + * APIs to be designated as "first available in this release" to do so + * by appropriately defining them. + * + * On macOS, Apple can tweak this to make various APIs "weakly exported + * symbols" to make it easier for software that's distributed in binary + * form and that uses libpcap to run on multiple macOS versions and use + * new APIs when available. (Yes, such third-party software exists - + * Wireshark provides binary packages for macOS, for example. tcpdump + * doesn't count, as that's provided by Apple, so each release can + * come with a version compiled to use the APIs present in that release.) + * + * We don't tweak it that way ourselves because, if you're building + * and installing libpcap on macOS yourself, the APIs will be available + * no matter what OS version you're installing it on. + * + * For other platforms, we don't define them, leaving it up to + * others to do so based on their OS versions, if appropriate. + * + * We start with libpcap 0.4, as that was the last LBL release, and + * I've never seen earlier releases. + */ +#ifdef __APPLE__ +/* + * Apple - insert #include here, and replace the two + * #defines below with: + * + * #define PCAP_API_AVAILABLE API_AVAILABLE + * + * and adjust availabilities as necessary, including adding information + * about operating systems other than macOS. + */ +#define PCAP_API_AVAILABLE(...) +#define PCAP_AVAILABLE_0_4 PCAP_API_AVAILABLE(macos(10.0)) +#define PCAP_AVAILABLE_0_5 PCAP_API_AVAILABLE(macos(10.0)) +#define PCAP_AVAILABLE_0_6 PCAP_API_AVAILABLE(macos(10.1)) +#define PCAP_AVAILABLE_0_7 PCAP_API_AVAILABLE(macos(10.4)) +#define PCAP_AVAILABLE_0_8 PCAP_API_AVAILABLE(macos(10.4)) +#define PCAP_AVAILABLE_0_9 PCAP_API_AVAILABLE(macos(10.5)) +#define PCAP_AVAILABLE_1_0 PCAP_API_AVAILABLE(macos(10.6)) +/* #define PCAP_AVAILABLE_1_1 no routines added to the API */ +#define PCAP_AVAILABLE_1_2 PCAP_API_AVAILABLE(macos(10.9)) +/* #define PCAP_AVAILABLE_1_3 no routines added to the API */ +/* #define PCAP_AVAILABLE_1_4 no routines added to the API */ +#define PCAP_AVAILABLE_1_5 PCAP_API_AVAILABLE(macos(10.10)) +/* #define PCAP_AVAILABLE_1_6 no routines added to the API */ +#define PCAP_AVAILABLE_1_7 PCAP_API_AVAILABLE(macos(10.12)) +#define PCAP_AVAILABLE_1_8 PCAP_API_AVAILABLE(macos(10.13)) +#define PCAP_AVAILABLE_1_9 PCAP_API_AVAILABLE(macos(10.13)) +/* + * The remote capture APIs are, in 1.9 and 1.10, usually only + * available in the library if the library was built with + * remote capture enabled. + * + * However, macOS Sonoma provides stub versions of those routine, + * which return an error. This means that we need a separate + * availability indicator macro for those routines, so that + * progras built on macOS Sonoma that attempt to use weak + * importing and availability tests to use those routines + * if they're available will get those routines weakly imported, + * so that if they're run on releases prior to Sonoma, they + * won't get an error from dyld about those routines being + * missing in libpcap. (If they don't use run-time availability + * tests, they will, instead, get crashes if they call one of + * those routines, as the addresses of those routines will be + * set to 0 by dyld, meaning the program will dereference a + * null pointer and crash when trying to call them.) + * + * (Not that it's useful to use those routines *anyway*, as they're + * stubs that always fail. The stubs were necessary in order to + * support weak exporting at all.) + */ +#define PCAP_AVAILABLE_1_9_REMOTE PCAP_API_AVAILABLE(macos(14.0)) +#define PCAP_AVAILABLE_1_10 PCAP_API_AVAILABLE(macos(12.1)) +#define PCAP_AVAILABLE_1_10_REMOTE PCAP_API_AVAILABLE(macos(14.0)) +#define PCAP_AVAILABLE_1_11 /* not released yet, so not in macOS yet */ +#else /* __APPLE__ */ +#define PCAP_AVAILABLE_0_4 +#define PCAP_AVAILABLE_0_5 +#define PCAP_AVAILABLE_0_6 +#define PCAP_AVAILABLE_0_7 +#define PCAP_AVAILABLE_0_8 +#define PCAP_AVAILABLE_0_9 +#define PCAP_AVAILABLE_1_0 +/* #define PCAP_AVAILABLE_1_1 no routines added to the API */ +#define PCAP_AVAILABLE_1_2 +/* #define PCAP_AVAILABLE_1_3 no routines added to the API */ +/* #define PCAP_AVAILABLE_1_4 no routines added to the API */ +#define PCAP_AVAILABLE_1_5 +/* #define PCAP_AVAILABLE_1_6 no routines added to the API */ +#define PCAP_AVAILABLE_1_7 +#define PCAP_AVAILABLE_1_8 +#define PCAP_AVAILABLE_1_9 +#define PCAP_AVAILABLE_1_9_REMOTE +#define PCAP_AVAILABLE_1_10 +#define PCAP_AVAILABLE_1_10_REMOTE +#define PCAP_AVAILABLE_1_11 +#endif /* __APPLE__ */ + +/* + * PCAP_NORETURN, before a function declaration, means "this function + * never returns". (It must go before the function declaration, e.g. + * "extern PCAP_NORETURN func(...)" rather than after the function + * declaration, as the MSVC version has to go before the declaration.) + * + * PCAP_NORETURN_DEF, before a function *definition*, means "this + * function never returns"; it would be used only for static functions + * that are defined before any use, and thus have no declaration. + * (MSVC doesn't support that; I guess the "decl" in "__declspec" + * means "declaration", and __declspec doesn't work with definitions.) + */ +#if __has_attribute(noreturn) \ + || PCAP_IS_AT_LEAST_GNUC_VERSION(2,5) \ + || PCAP_IS_AT_LEAST_SUNC_VERSION(5,9) \ + || PCAP_IS_AT_LEAST_XL_C_VERSION(7,0) \ + || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10) \ + || __TINYC__ + /* + * Compiler with support for __attribute((noreturn)), or GCC 2.5 and + * later, or some compiler asserting compatibility with GCC 2.5 and + * later, or Solaris Studio 12 (Sun C 5.9) and later, or IBM XL C 7.0 + * and later (do any earlier versions of XL C support this?), or HP aCC + * A.06.10 and later, or current TinyCC. + */ + #define PCAP_NORETURN __attribute((noreturn)) + #define PCAP_NORETURN_DEF __attribute((noreturn)) +#elif defined(_MSC_VER) + /* + * MSVC. + */ + #define PCAP_NORETURN __declspec(noreturn) + #define PCAP_NORETURN_DEF +#else + #define PCAP_NORETURN + #define PCAP_NORETURN_DEF +#endif + +/* + * PCAP_PRINTFLIKE(x,y), after a function declaration, means "this function + * does printf-style formatting, with the xth argument being the format + * string and the yth argument being the first argument for the format + * string". + */ +#if __has_attribute(__format__) \ + || PCAP_IS_AT_LEAST_GNUC_VERSION(2,3) \ + || PCAP_IS_AT_LEAST_XL_C_VERSION(7,0) \ + || PCAP_IS_AT_LEAST_HP_C_VERSION(6,10) + /* + * Compiler with support for it, or GCC 2.3 and later, or some compiler + * asserting compatibility with GCC 2.3 and later, or IBM XL C 7.0 + * and later (do any earlier versions of XL C support this?), + * or HP aCC A.06.10 and later. + */ + #define PCAP_PRINTFLIKE(x,y) __attribute__((__format__(__printf__,x,y))) +#else + #define PCAP_PRINTFLIKE(x,y) +#endif + +/* + * PCAP_DEPRECATED(func, msg), after a function declaration, marks the + * function as deprecated. + * + * The argument is a string giving the warning message to use if the + * compiler supports that. + */ +#if __has_attribute(deprecated) \ + || PCAP_IS_AT_LEAST_GNUC_VERSION(4,5) \ + || PCAP_IS_AT_LEAST_SUNC_VERSION(5,13) + /* + * Compiler that supports __has_attribute and __attribute__((deprecated)), + * or GCC 4.5 and later, or Sun/Oracle C 12.4 (Sun C 5.13) and later. + * + * Those support __attribute__((deprecated(msg))) (we assume, perhaps + * incorrectly, that anything that supports __has_attribute() is + * recent enough to support __attribute__((deprecated(msg)))). + */ + #define PCAP_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif PCAP_IS_AT_LEAST_GNUC_VERSION(3,1) + /* + * GCC 3.1 through 4.4. + * + * Those support __attribute__((deprecated)) but not + * __attribute__((deprecated(msg))). + */ + #define PCAP_DEPRECATED(msg) __attribute__((deprecated)) +#elif defined(_MSC_VER) && !defined(BUILDING_PCAP) + /* + * MSVC, and we're not building libpcap itself; it's VS 2015 + * and later, so we have __declspec(deprecated(...)). + * + * If we *are* building libpcap, we don't want this, as it'll warn + * us even if we *define* the function. + */ + #define PCAP_DEPRECATED(msg) _declspec(deprecated(msg)) +#else + #define PCAP_DEPRECATED(msg) +#endif + +/* + * For flagging arguments as format strings in MSVC. + */ +#ifdef _MSC_VER + #include + #define PCAP_FORMAT_STRING(p) _Printf_format_string_ p +#else + #define PCAP_FORMAT_STRING(p) p +#endif + +#endif /* lib_pcap_funcattrs_h */ diff --git a/src/libpcap-1.10.5/pcap/ipnet.h b/src/libpcap-1.10.5/pcap/ipnet.h new file mode 100644 index 0000000000..5330847099 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/ipnet.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define IPH_AF_INET 2 /* Matches Solaris's AF_INET */ +#define IPH_AF_INET6 26 /* Matches Solaris's AF_INET6 */ + +#define IPNET_OUTBOUND 1 +#define IPNET_INBOUND 2 diff --git a/src/libpcap-1.10.5/pcap/namedb.h b/src/libpcap-1.10.5/pcap/namedb.h new file mode 100644 index 0000000000..28a60a4c71 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/namedb.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#include /* FILE */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they're already being used by + * some applications (such as tcpdump) and already being + * marked as exported in some OSes offering libpcap (such + * as Debian). + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif + +PCAP_AVAILABLE_0_4 +PCAP_API struct pcap_etherent *pcap_next_etherent(FILE *); + +PCAP_AVAILABLE_0_4 +PCAP_API u_char *pcap_ether_hostton(const char*); + +PCAP_AVAILABLE_0_4 +PCAP_API u_char *pcap_ether_aton(const char *); + +PCAP_AVAILABLE_0_4 +PCAP_API +PCAP_DEPRECATED("this is not reentrant; use 'pcap_nametoaddrinfo' instead") +bpf_u_int32 **pcap_nametoaddr(const char *); + +PCAP_AVAILABLE_0_7 +PCAP_API struct addrinfo *pcap_nametoaddrinfo(const char *); + +PCAP_AVAILABLE_0_4 +PCAP_API bpf_u_int32 pcap_nametonetaddr(const char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_nametoport(const char *, int *, int *); + +PCAP_AVAILABLE_0_9 +PCAP_API int pcap_nametoportrange(const char *, int *, int *, int *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_nametoproto(const char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_nametoeproto(const char *); + +PCAP_AVAILABLE_0_9 +PCAP_API int pcap_nametollc(const char *); + +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entries in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpcap-1.10.5/pcap/nflog.h b/src/libpcap-1.10.5/pcap/nflog.h new file mode 100644 index 0000000000..919c88d2bd --- /dev/null +++ b/src/libpcap-1.10.5/pcap/nflog.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013, Petar Alilovic, + * Faculty of Electrical Engineering and Computing, University of Zagreb + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef lib_pcap_nflog_h +#define lib_pcap_nflog_h + +#include + +/* + * Structure of an NFLOG header and TLV parts, as described at + * https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html + * + * The NFLOG header is big-endian. + * + * The TLV length and type are in host byte order. The value is either + * big-endian or is an array of bytes in some externally-specified byte + * order (text string, link-layer address, link-layer header, packet + * data, etc.). + */ +typedef struct nflog_hdr { + uint8_t nflog_family; /* address family */ + uint8_t nflog_version; /* version */ + uint16_t nflog_rid; /* resource ID */ +} nflog_hdr_t; + +typedef struct nflog_tlv { + uint16_t tlv_length; /* tlv length */ + uint16_t tlv_type; /* tlv type */ + /* value follows this */ +} nflog_tlv_t; + +typedef struct nflog_packet_hdr { + uint16_t hw_protocol; /* hw protocol */ + uint8_t hook; /* netfilter hook */ + uint8_t pad; /* padding to 32 bits */ +} nflog_packet_hdr_t; + +typedef struct nflog_hwaddr { + uint16_t hw_addrlen; /* address length */ + uint16_t pad; /* padding to 32-bit boundary */ + uint8_t hw_addr[8]; /* address, up to 8 bytes */ +} nflog_hwaddr_t; + +typedef struct nflog_timestamp { + uint64_t sec; + uint64_t usec; +} nflog_timestamp_t; + +/* + * TLV types. + */ +#define NFULA_PACKET_HDR 1 /* nflog_packet_hdr_t */ +#define NFULA_MARK 2 /* packet mark from skbuff */ +#define NFULA_TIMESTAMP 3 /* nflog_timestamp_t for skbuff's time stamp */ +#define NFULA_IFINDEX_INDEV 4 /* ifindex of device on which packet received (possibly bridge group) */ +#define NFULA_IFINDEX_OUTDEV 5 /* ifindex of device on which packet transmitted (possibly bridge group) */ +#define NFULA_IFINDEX_PHYSINDEV 6 /* ifindex of physical device on which packet received (not bridge group) */ +#define NFULA_IFINDEX_PHYSOUTDEV 7 /* ifindex of physical device on which packet transmitted (not bridge group) */ +#define NFULA_HWADDR 8 /* nflog_hwaddr_t for hardware address */ +#define NFULA_PAYLOAD 9 /* packet payload */ +#define NFULA_PREFIX 10 /* text string - null-terminated, count includes NUL */ +#define NFULA_UID 11 /* UID owning socket on which packet was sent/received */ +#define NFULA_SEQ 12 /* sequence number of packets on this NFLOG socket */ +#define NFULA_SEQ_GLOBAL 13 /* sequence number of packets on all NFLOG sockets */ +#define NFULA_GID 14 /* GID owning socket on which packet was sent/received */ +#define NFULA_HWTYPE 15 /* ARPHRD_ type of skbuff's device */ +#define NFULA_HWHEADER 16 /* skbuff's MAC-layer header */ +#define NFULA_HWLEN 17 /* length of skbuff's MAC-layer header */ + +#endif diff --git a/src/libpcap-1.10.5/pcap/pcap-inttypes.h b/src/libpcap-1.10.5/pcap/pcap-inttypes.h new file mode 100644 index 0000000000..efaf608138 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/pcap-inttypes.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef pcap_pcap_inttypes_h +#define pcap_pcap_inttypes_h + +/* + * If we're compiling with Visual Studio, make sure the C99 integer + * types are defined, by hook or by crook. + * + * XXX - verify that we have at least C99 support on UN*Xes? + * + * What about MinGW or various DOS toolchains? We're currently assuming + * sufficient C99 support there. + */ +#if defined(_MSC_VER) + /* + * Compiler is MSVC. + */ + #if _MSC_VER >= 1800 + /* + * VS 2013 or newer; we have . + */ + #include + #else + /* + * Earlier VS; we have to define this stuff ourselves. + * We don't support building libpcap with earlier versions of VS, + * but SDKs for Npcap have to support building applications using + * earlier versions of VS, so we work around this by defining + * those types ourselves, as some files use them. + */ + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + typedef unsigned int uint32_t; + typedef signed int int32_t; + #ifdef _MSC_EXTENSIONS + typedef unsigned _int64 uint64_t; + typedef _int64 int64_t; + #else /* _MSC_EXTENSIONS */ + typedef unsigned long long uint64_t; + typedef long long int64_t; + #endif + #endif +#else /* defined(_MSC_VER) */ + /* + * Not Visual Studio. + * Include to get the integer types and PRI[doux]64 values + * defined. + * + * If the compiler is MinGW, we assume we have - and + * support for %zu in the formatted printing functions. + * + * If the target is UN*X, we assume we have a C99-or-later development + * environment, and thus have - and support for %zu in + * the formatted printing functions. + * + * If the target is MS-DOS, we assume we have - and support + * for %zu in the formatted printing functions. + * + * I.e., assume we have and that it suffices. + */ + + /* + * XXX - somehow make sure we have enough C99 support with other + * compilers and support libraries? + */ + + #include +#endif /* defined(_MSC_VER) */ + +#endif /* pcap/pcap-inttypes.h */ diff --git a/src/libpcap-1.10.5/pcap/pcap.h b/src/libpcap-1.10.5/pcap/pcap.h new file mode 100644 index 0000000000..e014335bdf --- /dev/null +++ b/src/libpcap-1.10.5/pcap/pcap.h @@ -0,0 +1,1270 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Remote packet capture mechanisms and extensions from WinPcap: + * + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +/* + * Some software that uses libpcap/WinPcap/Npcap defines _MSC_VER before + * including pcap.h if it's not defined - and it defines it to 1500. + * (I'm looking at *you*, lwIP!) + * + * Attempt to detect this, and undefine _MSC_VER so that we can *reliably* + * use it to know what compiler is being used and, if it's Visual Studio, + * what version is being used. + */ +#if defined(_MSC_VER) + /* + * We assume here that software such as that doesn't define _MSC_FULL_VER + * as well and that it defines _MSC_VER with a value > 1200. + * + * DO NOT BREAK THESE ASSUMPTIONS. IF YOU FEEL YOU MUST DEFINE _MSC_VER + * WITH A COMPILER THAT'S NOT MICROSOFT'S C COMPILER, PLEASE CONTACT + * US SO THAT WE CAN MAKE IT SO THAT YOU DON'T HAVE TO DO THAT. THANK + * YOU. + * + * OK, is _MSC_FULL_VER defined? + */ + #if !defined(_MSC_FULL_VER) + /* + * According to + * + * https://sourceforge.net/p/predef/wiki/Compilers/ + * + * with "Visual C++ 6.0 Processor Pack"/Visual C++ 6.0 SP6 and + * later, _MSC_FULL_VER is defined, so either this is an older + * version of Visual C++ or it's not Visual C++ at all. + * + * For Visual C++ 6.0, _MSC_VER is defined as 1200. + */ + #if _MSC_VER > 1200 + /* + * If this is Visual C++, _MSC_FULL_VER should be defined, so we + * assume this isn't Visual C++, and undo the lie that it is. + */ + #undef _MSC_VER + #endif + #endif +#endif + +#include + +#include + +#if defined(_WIN32) + #include /* u_int, u_char etc. */ + #include /* _get_osfhandle() */ +#elif defined(MSDOS) + #include /* u_int, u_char etc. */ + #include +#else /* UN*X */ + #include /* u_int, u_char etc. */ + #include +#endif /* _WIN32/MSDOS/UN*X */ + +#include /* for PCAP_SOCKET, as the active-mode rpcap APIs use it */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Version number of the current version of the pcap file format. + * + * NOTE: this is *NOT* the version number of the libpcap library. + * To fetch the version information for the version of libpcap + * you're using, use pcap_lib_version(). + */ +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * Documentation: https://www.tcpdump.org/manpages/pcap-savefile.5.txt. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes by forking the branch at + * + * https://github.com/the-tcpdump-group/libpcap/tree/master + * + * and issuing a pull request, so that future versions of libpcap and + * programs that use it (such as tcpdump) will be able to read your new + * capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* not used - SHOULD be filled with 0 */ + bpf_u_int32 sigfigs; /* not used - SHOULD be filled with 0 */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Subfields of the field containing the link-layer header type. + * + * Link-layer header types are assigned for both pcap and + * pcapng, and the same value must work with both. In pcapng, + * the link-layer header type field in an Interface Description + * Block is 16 bits, so only the bottommost 16 bits of the + * link-layer header type in a pcap file can be used for the + * header type value. + * + * In libpcap, the upper 16 bits, from the top down, are divided into: + * + * A 4-bit "FCS length" field, to allow the FCS length to + * be specified, just as it can be specified in the if_fcslen + * field of the pcapng IDB. The field is in units of 16 bits, + * i.e. 1 means 16 bits of FCS, 2 means 32 bits of FCS, etc.. + * + * A reserved bit, which must be zero. + * + * An "FCS length present" flag; if 0, the "FCS length" field + * should be ignored, and if 1, the "FCS length" field should + * be used. + * + * 10 reserved bits, which must be zero. They were originally + * intended to be used as a "class" field, allowing additional + * classes of link-layer types to be defined, with a class value + * of 0 indicating that the link-layer type is a LINKTYPE_ value. + * A value of 0x224 was, at one point, used by NetBSD to define + * "raw" packet types, with the lower 16 bits containing a + * NetBSD AF_ value; see + * + * https://marc.info/?l=tcpdump-workers&m=98296750229149&w=2 + * + * It's unknown whether those were ever used in capture files, + * or if the intent was just to use it as a link-layer type + * for BPF programs; NetBSD's libpcap used to support them in + * the BPF code generator, but it no longer does so. If it + * was ever used in capture files, or if classes other than + * "LINKTYPE_ value" are ever useful in capture files, we could + * re-enable this, and use the reserved 16 bits following the + * link-layer type in pcapng files to hold the class information + * there. (Note, BTW, that LINKTYPE_RAW/DLT_RAW is now being + * interpreted by libpcap, tcpdump, and Wireshark as "raw IP", + * including both IPv4 and IPv6, with the version number in the + * header being checked to see which it is, not just "raw IPv4"; + * there are LINKTYPE_IPV4/DLT_IPV4 and LINKTYPE_IPV6/DLT_IPV6 + * values if "these are IPv{4,6} and only IPv{4,6} packets" + * types are needed.) + * + * Or we might be able to use it for other purposes. + */ +#define LT_LINKTYPE(x) ((x) & 0x0000FFFF) +#define LT_LINKTYPE_EXT(x) ((x) & 0xFFFF0000) +#define LT_RESERVED1(x) ((x) & 0x03FF0000) +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length of this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface -- only supported on some platforms */ +#ifdef _WIN32 + u_int ps_capt; /* number of packets that reach the application */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* _WIN32 */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ +#define PCAP_IF_UP 0x00000002 /* interface is up */ +#define PCAP_IF_RUNNING 0x00000004 /* interface is running */ +#define PCAP_IF_WIRELESS 0x00000008 /* interface is wireless (*NOT* necessarily Wi-Fi!) */ +#define PCAP_IF_CONNECTION_STATUS 0x00000030 /* connection status: */ +#define PCAP_IF_CONNECTION_STATUS_UNKNOWN 0x00000000 /* unknown */ +#define PCAP_IF_CONNECTION_STATUS_CONNECTED 0x00000010 /* connected */ +#define PCAP_IF_CONNECTION_STATUS_DISCONNECTED 0x00000020 /* disconnected */ +#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE 0x00000030 /* not applicable */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ +#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10 /* this device doesn't support setting the time stamp type */ +#define PCAP_ERROR_PROMISC_PERM_DENIED -11 /* you don't have permission to capture in promiscuous mode */ +#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12 /* the requested time stamp precision is not supported */ +#define PCAP_ERROR_CAPTURE_NOTSUP -13 /* capture mechanism not available */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ +#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP 3 /* the requested time stamp type is not supported */ + +/* + * Value to pass to pcap_compile() as the netmask if you don't know what + * the netmask is. + */ +#define PCAP_NETMASK_UNKNOWN 0xffffffff + +/* + * Initialize pcap. If this isn't called, pcap is initialized to + * a mode source-compatible and binary-compatible with older versions + * that lack this routine. + */ + +/* + * Initialization options. + * All bits not listed here are reserved for expansion. + * + * On UNIX-like systems, the local character encoding is assumed to be + * UTF-8, so no character encoding transformations are done. + * + * On Windows, the local character encoding is the local ANSI code page. + */ +#define PCAP_CHAR_ENC_LOCAL 0x00000000U /* strings are in the local character encoding */ +#define PCAP_CHAR_ENC_UTF_8 0x00000001U /* strings are in UTF-8 */ + +PCAP_AVAILABLE_1_10 +PCAP_API int pcap_init(unsigned int, char *); + +/* + * We're deprecating pcap_lookupdev() for various reasons (not + * thread-safe, can behave weirdly with WinPcap). Callers + * should use pcap_findalldevs() and use the first device. + */ +PCAP_AVAILABLE_0_4 +PCAP_DEPRECATED("use 'pcap_findalldevs' and use the first device") +PCAP_API char *pcap_lookupdev(char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +PCAP_AVAILABLE_1_0 +PCAP_API pcap_t *pcap_create(const char *, char *); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_set_snaplen(pcap_t *, int); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_set_promisc(pcap_t *, int); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_can_set_rfmon(pcap_t *); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_set_rfmon(pcap_t *, int); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_set_timeout(pcap_t *, int); + +PCAP_AVAILABLE_1_2 +PCAP_API int pcap_set_tstamp_type(pcap_t *, int); + +PCAP_AVAILABLE_1_5 +PCAP_API int pcap_set_immediate_mode(pcap_t *, int); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_set_buffer_size(pcap_t *, int); + +PCAP_AVAILABLE_1_5 +PCAP_API int pcap_set_tstamp_precision(pcap_t *, int); + +PCAP_AVAILABLE_1_5 +PCAP_API int pcap_get_tstamp_precision(pcap_t *); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_activate(pcap_t *); + +PCAP_AVAILABLE_1_2 +PCAP_API int pcap_list_tstamp_types(pcap_t *, int **); + +PCAP_AVAILABLE_1_2 +PCAP_API void pcap_free_tstamp_types(int *); + +PCAP_AVAILABLE_1_2 +PCAP_API int pcap_tstamp_type_name_to_val(const char *); + +PCAP_AVAILABLE_1_2 +PCAP_API const char *pcap_tstamp_type_val_to_name(int); + +PCAP_AVAILABLE_1_2 +PCAP_API const char *pcap_tstamp_type_val_to_description(int); + +#ifdef __linux__ +PCAP_AVAILABLE_1_9 +PCAP_API int pcap_set_protocol_linux(pcap_t *, int); +#endif + +/* + * Time stamp types. + * Not all systems and interfaces will necessarily support all of these. + * + * A system that supports PCAP_TSTAMP_HOST is offering time stamps + * provided by the host machine, rather than by the capture device, + * but not committing to any characteristics of the time stamp. + * + * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine, + * that's low-precision but relatively cheap to fetch; it's normally done + * using the system clock, so it's normally synchronized with times you'd + * fetch from system calls. + * + * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine, + * that's high-precision; it might be more expensive to fetch. It is + * synchronized with the system clock. + * + * PCAP_TSTAMP_HOST_HIPREC_UNSYNCED is a time stamp, provided by the host + * machine, that's high-precision; it might be more expensive to fetch. + * It is not synchronized with the system clock, and might have + * problems with time stamps for packets received on different CPUs, + * depending on the platform. It might be more likely to be strictly + * monotonic than PCAP_TSTAMP_HOST_HIPREC. + * + * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the + * capture device; it's synchronized with the system clock. + * + * PCAP_TSTAMP_ADAPTER_UNSYNCED is a high-precision time stamp supplied by + * the capture device; it's not synchronized with the system clock. + * + * Note that time stamps synchronized with the system clock can go + * backwards, as the system clock can go backwards. If a clock is + * not in sync with the system clock, that could be because the + * system clock isn't keeping accurate time, because the other + * clock isn't keeping accurate time, or both. + * + * Note that host-provided time stamps generally correspond to the + * time when the time-stamping code sees the packet; this could + * be some unknown amount of time after the first or last bit of + * the packet is received by the network adapter, due to batching + * of interrupts for packet arrival, queueing delays, etc.. + */ +#define PCAP_TSTAMP_HOST 0 /* host-provided, unknown characteristics */ +#define PCAP_TSTAMP_HOST_LOWPREC 1 /* host-provided, low precision, synced with the system clock */ +#define PCAP_TSTAMP_HOST_HIPREC 2 /* host-provided, high precision, synced with the system clock */ +#define PCAP_TSTAMP_ADAPTER 3 /* device-provided, synced with the system clock */ +#define PCAP_TSTAMP_ADAPTER_UNSYNCED 4 /* device-provided, not synced with the system clock */ +#define PCAP_TSTAMP_HOST_HIPREC_UNSYNCED 5 /* host-provided, high precision, not synced with the system clock */ + +/* + * Time stamp resolution types. + * Not all systems and interfaces will necessarily support all of these + * resolutions when doing live captures; all of them can be requested + * when reading a savefile. + */ +#define PCAP_TSTAMP_PRECISION_MICRO 0 /* use timestamps with microsecond precision, default */ +#define PCAP_TSTAMP_PRECISION_NANO 1 /* use timestamps with nanosecond precision */ + +PCAP_AVAILABLE_0_4 +PCAP_API pcap_t *pcap_open_live(const char *, int, int, int, char *); + +PCAP_AVAILABLE_0_6 +PCAP_API pcap_t *pcap_open_dead(int, int); + +PCAP_AVAILABLE_1_5 +PCAP_API pcap_t *pcap_open_dead_with_tstamp_precision(int, int, u_int); + +PCAP_AVAILABLE_1_5 +PCAP_API pcap_t *pcap_open_offline_with_tstamp_precision(const char *, u_int, char *); + +PCAP_AVAILABLE_0_4 +PCAP_API pcap_t *pcap_open_offline(const char *, char *); + +#ifdef _WIN32 + PCAP_AVAILABLE_1_5 + PCAP_API pcap_t *pcap_hopen_offline_with_tstamp_precision(intptr_t, u_int, char *); + + PCAP_API pcap_t *pcap_hopen_offline(intptr_t, char *); + /* + * If we're building libpcap, these are internal routines in savefile.c, + * so we must not define them as macros. + * + * If we're not building libpcap, given that the version of the C runtime + * with which libpcap was built might be different from the version + * of the C runtime with which an application using libpcap was built, + * and that a FILE structure may differ between the two versions of the + * C runtime, calls to _fileno() must use the version of _fileno() in + * the C runtime used to open the FILE *, not the version in the C + * runtime with which libpcap was built. (Maybe once the Universal CRT + * rules the world, this will cease to be a problem.) + */ + #ifndef BUILDING_PCAP + #define pcap_fopen_offline_with_tstamp_precision(f,p,b) \ + pcap_hopen_offline_with_tstamp_precision(_get_osfhandle(_fileno(f)), p, b) + #define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) + #endif +#else /*_WIN32*/ + PCAP_AVAILABLE_1_5 + PCAP_API pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); + + PCAP_AVAILABLE_0_9 + PCAP_API pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*_WIN32*/ + +PCAP_AVAILABLE_0_4 +PCAP_API void pcap_close(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_loop(pcap_t *, int, pcap_handler, u_char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); + +PCAP_AVAILABLE_0_4 +PCAP_API const u_char *pcap_next(pcap_t *, struct pcap_pkthdr *); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); + +PCAP_AVAILABLE_0_8 +PCAP_API void pcap_breakloop(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_setfilter(pcap_t *, struct bpf_program *); + +PCAP_AVAILABLE_0_9 +PCAP_API int pcap_setdirection(pcap_t *, pcap_direction_t); + +PCAP_AVAILABLE_0_7 +PCAP_API int pcap_getnonblock(pcap_t *, char *); + +PCAP_AVAILABLE_0_7 +PCAP_API int pcap_setnonblock(pcap_t *, int, char *); + +PCAP_AVAILABLE_0_9 +PCAP_API int pcap_inject(pcap_t *, const void *, size_t); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_sendpacket(pcap_t *, const u_char *, int); + +PCAP_AVAILABLE_1_0 +PCAP_API const char *pcap_statustostr(int); + +PCAP_AVAILABLE_0_4 +PCAP_API const char *pcap_strerror(int); + +PCAP_AVAILABLE_0_4 +PCAP_API char *pcap_geterr(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API void pcap_perror(pcap_t *, const char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); + +PCAP_AVAILABLE_0_5 +PCAP_DEPRECATED("use pcap_open_dead(), pcap_compile() and pcap_close()") +PCAP_API int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); + +/* XXX - this took two arguments in 0.4 and 0.5 */ +PCAP_AVAILABLE_0_6 +PCAP_API void pcap_freecode(struct bpf_program *); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_offline_filter(const struct bpf_program *, + const struct pcap_pkthdr *, const u_char *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_datalink(pcap_t *); + +PCAP_AVAILABLE_1_0 +PCAP_API int pcap_datalink_ext(pcap_t *); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_list_datalinks(pcap_t *, int **); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_set_datalink(pcap_t *, int); + +PCAP_AVAILABLE_0_8 +PCAP_API void pcap_free_datalinks(int *); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_datalink_name_to_val(const char *); + +PCAP_AVAILABLE_0_8 +PCAP_API const char *pcap_datalink_val_to_name(int); + +PCAP_AVAILABLE_0_8 +PCAP_API const char *pcap_datalink_val_to_description(int); + +PCAP_AVAILABLE_1_9 +PCAP_API const char *pcap_datalink_val_to_description_or_dlt(int); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_snapshot(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_is_swapped(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_major_version(pcap_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_minor_version(pcap_t *); + +PCAP_AVAILABLE_1_9 +PCAP_API int pcap_bufsize(pcap_t *); + +/* XXX */ +PCAP_AVAILABLE_0_4 +PCAP_API FILE *pcap_file(pcap_t *); + +#ifdef _WIN32 +/* + * This probably shouldn't have been kept in WinPcap; most if not all + * UN*X code that used it won't work on Windows. We deprecate it; if + * anybody really needs access to whatever HANDLE may be associated + * with a pcap_t (there's no guarantee that there is one), we can add + * a Windows-only pcap_handle() API that returns the HANDLE. + */ +PCAP_AVAILABLE_0_4 +PCAP_DEPRECATED("request a 'pcap_handle' that returns a HANDLE if you need it") +PCAP_API int pcap_fileno(pcap_t *); +#else /* _WIN32 */ +PCAP_AVAILABLE_0_4 +PCAP_API int pcap_fileno(pcap_t *); +#endif /* _WIN32 */ + +#ifdef _WIN32 + PCAP_API int pcap_wsockinit(void); +#endif + +PCAP_AVAILABLE_0_4 +PCAP_API pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); + +#ifdef _WIN32 + PCAP_AVAILABLE_0_9 + PCAP_API pcap_dumper_t *pcap_dump_hopen(pcap_t *, intptr_t); + + /* + * If we're building libpcap, this is an internal routine in sf-pcap.c, so + * we must not define it as a macro. + * + * If we're not building libpcap, given that the version of the C runtime + * with which libpcap was built might be different from the version + * of the C runtime with which an application using libpcap was built, + * and that a FILE structure may differ between the two versions of the + * C runtime, calls to _fileno() must use the version of _fileno() in + * the C runtime used to open the FILE *, not the version in the C + * runtime with which libpcap was built. (Maybe once the Universal CRT + * rules the world, this will cease to be a problem.) + */ + #ifndef BUILDING_PCAP + #define pcap_dump_fopen(p,f) \ + pcap_dump_hopen(p, _get_osfhandle(_fileno(f))) + #endif +#else /*_WIN32*/ + PCAP_AVAILABLE_0_9 + PCAP_API pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +#endif /*_WIN32*/ + +PCAP_AVAILABLE_1_7 +PCAP_API pcap_dumper_t *pcap_dump_open_append(pcap_t *, const char *); + +PCAP_AVAILABLE_0_8 +PCAP_API FILE *pcap_dump_file(pcap_dumper_t *); + +PCAP_AVAILABLE_0_9 +PCAP_API long pcap_dump_ftell(pcap_dumper_t *); + +PCAP_AVAILABLE_1_9 +PCAP_API int64_t pcap_dump_ftell64(pcap_dumper_t *); + +PCAP_AVAILABLE_0_8 +PCAP_API int pcap_dump_flush(pcap_dumper_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API void pcap_dump_close(pcap_dumper_t *); + +PCAP_AVAILABLE_0_4 +PCAP_API void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +PCAP_AVAILABLE_0_7 +PCAP_API int pcap_findalldevs(pcap_if_t **, char *); + +PCAP_AVAILABLE_0_7 +PCAP_API void pcap_freealldevs(pcap_if_t *); + +/* + * We return a pointer to the version string, rather than exporting the + * version string directly. + * + * On at least some UNIXes, if you import data from a shared library into + * a program, the data is bound into the program binary, so if the string + * in the version of the library with which the program was linked isn't + * the same as the string in the version of the library with which the + * program is being run, various undesirable things may happen (warnings, + * the string being the one from the version of the library with which the + * program was linked, or even weirder things, such as the string being the + * one from the library but being truncated). + * + * On Windows, the string is constructed at run time. + */ +PCAP_AVAILABLE_0_8 +PCAP_API const char *pcap_lib_version(void); + +#if defined(_WIN32) + + /* + * Win32 definitions + */ + + /*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). + */ + struct pcap_send_queue + { + u_int maxlen; /* Maximum size of the queue, in bytes. This + variable contains the size of the buffer field. */ + u_int len; /* Current size of the queue, in bytes. */ + char *buffer; /* Buffer containing the packets to be sent. */ + }; + + typedef struct pcap_send_queue pcap_send_queue; + + /*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function + */ + #if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) + #define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ + typedef struct _AirpcapHandle *PAirpcapHandle; + #endif + + PCAP_API int pcap_setbuff(pcap_t *p, int dim); + PCAP_API int pcap_setmode(pcap_t *p, int mode); + PCAP_API int pcap_setmintocopy(pcap_t *p, int size); + + PCAP_API HANDLE pcap_getevent(pcap_t *p); + + PCAP_AVAILABLE_1_8 + PCAP_API int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *); + + PCAP_AVAILABLE_1_8 + PCAP_API int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *); + + PCAP_API pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + + PCAP_API void pcap_sendqueue_destroy(pcap_send_queue* queue); + + PCAP_API int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + + PCAP_API u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + + PCAP_API struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + + PCAP_API int pcap_setuserbuffer(pcap_t *p, int size); + + PCAP_API int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + + PCAP_API int pcap_live_dump_ended(pcap_t *p, int sync); + + PCAP_API int pcap_start_oem(char* err_str, int flags); + + PCAP_API PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + + #define MODE_CAPT 0 + #define MODE_STAT 1 + #define MODE_MON 2 + +#elif defined(MSDOS) + + /* + * MS-DOS definitions + */ + + PCAP_API int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); + PCAP_API void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); + PCAP_API u_long pcap_mac_packets (void); + +#else /* UN*X */ + + /* + * UN*X definitions + */ + + PCAP_AVAILABLE_0_8 + PCAP_API int pcap_get_selectable_fd(pcap_t *); + + PCAP_AVAILABLE_1_9 + PCAP_API const struct timeval *pcap_get_required_select_timeout(pcap_t *); + +#endif /* _WIN32/MSDOS/UN*X */ + +/* + * Remote capture definitions. + * + * These routines are only present if libpcap has been configured to + * include remote capture support. + */ + +/* + * The maximum buffer size in which address, port, interface names are kept. + * + * In case the adapter name or such is larger than this value, it is truncated. + * This is not used by the user; however it must be aware that an hostname / interface + * name longer than this value will be truncated. + */ +#define PCAP_BUF_SIZE 1024 + +/* + * The type of input source, passed to pcap_open(). + */ +#define PCAP_SRC_FILE 2 /* local savefile */ +#define PCAP_SRC_IFLOCAL 3 /* local network interface */ +#define PCAP_SRC_IFREMOTE 4 /* interface on a remote host, using RPCAP */ + +/* + * The formats allowed by pcap_open() are the following: + * - file://path_and_filename [opens a local file] + * - rpcap://devicename [opens the selected device available on the local host, without using the RPCAP protocol] + * - rpcap://host/devicename [opens the selected device available on a remote host] + * - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + * - adaptername [to open a local adapter; kept for compatibility, but it is strongly discouraged] + * - (NULL) [to open the first local adapter; kept for compatibility, but it is strongly discouraged] + * + * The formats allowed by the pcap_findalldevs_ex() are the following: + * - file://folder/ [lists all the files in the given folder] + * - rpcap:// [lists all local adapters] + * - rpcap://host:port/ [lists the devices available on a remote host] + * + * In all the above, "rpcaps://" can be substituted for "rpcap://" to enable + * SSL (if it has been compiled in). + * + * Referring to the 'host' and 'port' parameters, they can be either numeric or literal. Since + * IPv6 is fully supported, these are the allowed formats: + * + * - host (literal): e.g. host.foo.bar + * - host (numeric IPv4): e.g. 10.11.12.13 + * - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + * - host (numeric IPv6): e.g. [1:2:3::4] + * - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + * + * Here you find some allowed examples: + * - rpcap://host.foo.bar/devicename [everything literal, no port number] + * - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + * - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + * - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + * - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + * - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + * - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + * - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + */ + +/* + * URL schemes for capture source. + */ +/* + * This string indicates that the user wants to open a capture from a + * local file. + */ +#define PCAP_SRC_FILE_STRING "file://" +/* + * This string indicates that the user wants to open a capture from a + * network interface. This string does not necessarily involve the use + * of the RPCAP protocol. If the interface required resides on the local + * host, the RPCAP protocol is not involved and the local functions are used. + */ +#define PCAP_SRC_IF_STRING "rpcap://" + +/* + * Flags to pass to pcap_open(). + */ + +/* + * Specifies whether promiscuous mode is to be used. + */ +#define PCAP_OPENFLAG_PROMISCUOUS 0x00000001 + +/* + * Specifies, for an RPCAP capture, whether the data transfer (in + * case of a remote capture) has to be done with UDP protocol. + * + * If it is '1' if you want a UDP data connection, '0' if you want + * a TCP data connection; control connection is always TCP-based. + * A UDP connection is much lighter, but it does not guarantee that all + * the captured packets arrive to the client workstation. Moreover, + * it could be harmful in case of network congestion. + * This flag is meaningless if the source is not a remote interface. + * In that case, it is simply ignored. + */ +#define PCAP_OPENFLAG_DATATX_UDP 0x00000002 + +/* + * Specifies whether the remote probe will capture its own generated + * traffic. + * + * In case the remote probe uses the same interface to capture traffic + * and to send data back to the caller, the captured traffic includes + * the RPCAP traffic as well. If this flag is turned on, the RPCAP + * traffic is excluded from the capture, so that the trace returned + * back to the collector is does not include this traffic. + * + * Has no effect on local interfaces or savefiles. + */ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 0x00000004 + +/* + * Specifies whether the local adapter will capture its own generated traffic. + * + * This flag tells the underlying capture driver to drop the packets + * that were sent by itself. This is useful when building applications + * such as bridges that should ignore the traffic they just sent. + * + * Supported only on Windows. + */ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 0x00000008 + +/* + * This flag configures the adapter for maximum responsiveness. + * + * In presence of a large value for nbytes, WinPcap waits for the arrival + * of several packets before copying the data to the user. This guarantees + * a low number of system calls, i.e. lower processor usage, i.e. better + * performance, which is good for applications like sniffers. If the user + * sets the PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will + * copy the packets as soon as the application is ready to receive them. + * This is suggested for real time applications (such as, for example, + * a bridge) that need the best responsiveness. + * + * The equivalent with pcap_create()/pcap_activate() is "immediate mode". + */ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 0x00000010 + +/* + * Remote authentication methods. + * These are used in the 'type' member of the pcap_rmtauth structure. + */ + +/* + * NULL authentication. + * + * The 'NULL' authentication has to be equal to 'zero', so that old + * applications can just put every field of struct pcap_rmtauth to zero, + * and it does work. + */ +#define RPCAP_RMTAUTH_NULL 0 +/* + * Username/password authentication. + * + * With this type of authentication, the RPCAP protocol will use the username/ + * password provided to authenticate the user on the remote machine. If the + * authentication is successful (and the user has the right to open network + * devices) the RPCAP connection will continue; otherwise it will be dropped. + * + * *******NOTE********: unless TLS is being used, the username and password + * are sent over the network to the capture server *IN CLEAR TEXT*. Don't + * use this, without TLS (i.e., with rpcap:// rather than rpcaps://) on + * a network that you don't completely control! (And be *really* careful + * in your definition of "completely"!) + */ +#define RPCAP_RMTAUTH_PWD 1 + +/* + * This structure keeps the information needed to authenticate the user + * on a remote machine. + * + * The remote machine can either grant or refuse the access according + * to the information provided. + * In case the NULL authentication is required, both 'username' and + * 'password' can be NULL pointers. + * + * This structure is meaningless if the source is not a remote interface; + * in that case, the functions which requires such a structure can accept + * a NULL pointer as well. + */ +struct pcap_rmtauth +{ + /* + * \brief Type of the authentication required. + * + * In order to provide maximum flexibility, we can support different types + * of authentication based on the value of this 'type' variable. The currently + * supported authentication methods are defined into the + * \link remote_auth_methods Remote Authentication Methods Section\endlink. + */ + int type; + /* + * \brief Zero-terminated string containing the username that has to be + * used on the remote machine for authentication. + * + * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + * and it can be NULL. + */ + char *username; + /* + * \brief Zero-terminated string containing the password that has to be + * used on the remote machine for authentication. + * + * This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + * and it can be NULL. + */ + char *password; +}; + +/* + * This routine can open a savefile, a local device, or a device on + * a remote machine running an RPCAP server. + * + * For opening a savefile, the pcap_open_offline routines can be used, + * and will work just as well; code using them will work on more + * platforms than code using pcap_open() to open savefiles. + * + * For opening a local device, pcap_open_live() can be used; it supports + * most of the capabilities that pcap_open() supports, and code using it + * will work on more platforms than code using pcap_open(). pcap_create() + * and pcap_activate() can also be used; they support all capabilities + * that pcap_open() supports, except for the Windows-only + * PCAP_OPENFLAG_NOCAPTURE_LOCAL, and support additional capabilities. + * + * For opening a remote capture, pcap_open() is currently the only + * API available. + */ +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API pcap_t *pcap_open(const char *source, int snaplen, int flags, + int read_timeout, struct pcap_rmtauth *auth, char *errbuf); + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API int pcap_createsrcstr(char *source, int type, const char *host, + const char *port, const char *name, char *errbuf); + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API int pcap_parsesrcstr(const char *source, int *type, char *host, + char *port, char *name, char *errbuf); + +/* + * This routine can scan a directory for savefiles, list local capture + * devices, or list capture devices on a remote machine running an RPCAP + * server. + * + * For scanning for savefiles, it can be used on both UN*X systems and + * Windows systems; for each directory entry it sees, it tries to open + * the file as a savefile using pcap_open_offline(), and only includes + * it in the list of files if the open succeeds, so it filters out + * files for which the user doesn't have read permission, as well as + * files that aren't valid savefiles readable by libpcap. + * + * For listing local capture devices, it's just a wrapper around + * pcap_findalldevs(); code using pcap_findalldevs() will work on more + * platforms than code using pcap_findalldevs_ex(). + * + * For listing remote capture devices, pcap_findalldevs_ex() is currently + * the only API available. + */ +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API int pcap_findalldevs_ex(const char *source, + struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); + +/* + * Sampling methods. + * + * These allow pcap_loop(), pcap_dispatch(), pcap_next(), and pcap_next_ex() + * to see only a sample of packets, rather than all packets. + * + * Currently, they work only on Windows local captures. + */ + +/* + * Specifies that no sampling is to be done on the current capture. + * + * In this case, no sampling algorithms are applied to the current capture. + */ +#define PCAP_SAMP_NOSAMP 0 + +/* + * Specifies that only 1 out of N packets must be returned to the user. + * + * In this case, the 'value' field of the 'pcap_samp' structure indicates the + * number of packets (minus 1) that must be discarded before one packet got + * accepted. + * In other words, if 'value = 10', the first packet is returned to the + * caller, while the following 9 are discarded. + */ +#define PCAP_SAMP_1_EVERY_N 1 + +/* + * Specifies that we have to return 1 packet every N milliseconds. + * + * In this case, the 'value' field of the 'pcap_samp' structure indicates + * the 'waiting time' in milliseconds before one packet got accepted. + * In other words, if 'value = 10', the first packet is returned to the + * caller; the next returned one will be the first packet that arrives + * when 10ms have elapsed. + */ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/* + * This structure defines the information related to sampling. + * + * In case the sampling is requested, the capturing device should read + * only a subset of the packets coming from the source. The returned packets + * depend on the sampling parameters. + * + * WARNING: The sampling process is applied *after* the filtering process. + * In other words, packets are filtered first, then the sampling process + * selects a subset of the 'filtered' packets and it returns them to the + * caller. + */ +struct pcap_samp +{ + /* + * Method used for sampling; see above. + */ + int method; + + /* + * This value depends on the sampling method defined. + * For its meaning, see above. + */ + int value; +}; + +/* + * New functions. + */ +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API struct pcap_samp *pcap_setsampling(pcap_t *p); + +/* + * RPCAP active mode. + */ + +/* Maximum length of an host name (needed for the RPCAP active mode) */ +#define RPCAP_HOSTLIST_SIZE 1024 + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API PCAP_SOCKET pcap_remoteact_accept(const char *address, const char *port, + const char *hostlist, char *connectinghost, + struct pcap_rmtauth *auth, char *errbuf); + +PCAP_AVAILABLE_1_10_REMOTE +PCAP_API PCAP_SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, + const char *hostlist, char *connectinghost, + struct pcap_rmtauth *auth, int uses_ssl, char *errbuf); + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API int pcap_remoteact_list(char *hostlist, char sep, int size, + char *errbuf); + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API int pcap_remoteact_close(const char *host, char *errbuf); + +PCAP_AVAILABLE_1_9_REMOTE +PCAP_API void pcap_remoteact_cleanup(void); + +#ifdef __cplusplus +} +#endif + +#endif /* lib_pcap_pcap_h */ diff --git a/src/libpcap-1.10.5/pcap/sll.h b/src/libpcap-1.10.5/pcap/sll.h new file mode 100644 index 0000000000..3d8c902075 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/sll.h @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +#include + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + uint16_t sll_pkttype; /* packet type */ + uint16_t sll_hatype; /* link-layer address type */ + uint16_t sll_halen; /* link-layer address length */ + uint8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + uint16_t sll_protocol; /* protocol */ +}; + +/* + * A DLT_LINUX_SLL2 fake link-layer header. + */ +#define SLL2_HDR_LEN 20 /* total header length */ + +struct sll2_header { + uint16_t sll2_protocol; /* protocol */ + uint16_t sll2_reserved_mbz; /* reserved - must be zero */ + uint32_t sll2_if_index; /* 1-based interface index */ + uint16_t sll2_hatype; /* link-layer address type */ + uint8_t sll2_pkttype; /* packet type */ + uint8_t sll2_halen; /* link-layer address length */ + uint8_t sll2_addr[SLL_ADDRLEN]; /* link-layer address */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for + * "sll2_pkttype"; these correspond to the PACKET_ values on Linux, + * which are defined by a header under include/uapi in the current + * kernel source, and are thus not going to change on Linux. We + * define them here so that they're available even on systems other + * than Linux. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for + * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but + * are defined here so that they're available even on systems other than + * Linux. We assume, for now, that the ETH_P_ values won't change in + * Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ +#define LINUX_SLL_P_CAN 0x000C /* CAN frames, with SocketCAN pseudo-headers */ +#define LINUX_SLL_P_CANFD 0x000D /* CAN FD frames, with SocketCAN pseudo-headers */ +#define LINUX_SLL_P_CANXL 0x000E /* CAN XL frames, with SocketCAN pseudo-headers */ + +#endif diff --git a/src/libpcap-1.10.5/pcap/socket.h b/src/libpcap-1.10.5/pcap/socket.h new file mode 100644 index 0000000000..b1a864b532 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/socket.h @@ -0,0 +1,128 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_socket_h +#define lib_pcap_socket_h + +/* + * Some minor differences between sockets on various platforms. + * We include whatever sockets are needed for Internet-protocol + * socket access on UN*X and Windows. + */ +#ifdef _WIN32 + /* Need windef.h for defines used in winsock2.h under MingW32 */ + #ifdef __MINGW32__ + #include + #endif + #include + #include + + /*! + * \brief In Winsock, a socket handle is of type SOCKET; in UN*X, it's + * a file descriptor, and therefore a signed integer. + * We define PCAP_SOCKET to be a signed integer on UN*X and a + * SOCKET on Windows, so that it can be used on both platforms. + * + * We used to use SOCKET rather than PCAP_SOCKET, but that collided + * with other software, such as barnyard2, which had their own + * definitions of SOCKET, so we changed it to PCAP_SOCKET. + * + * On Windows, this shouldn't break any APIs, as any code using + * the two active-mode APIs that return a socket handle would + * probably be assigning their return values to a SOCKET, and + * as, on Windows, we're defining PCAP_SOCKET as SOCKET, there + * would be no type clash. + */ + #ifndef PCAP_SOCKET + #define PCAP_SOCKET SOCKET + #endif + + /* + * Winsock doesn't have this POSIX type; it's used for the + * tv_usec value of struct timeval. + */ + typedef long suseconds_t; +#else /* _WIN32 */ + #include + #include + #include /* for struct addrinfo/getaddrinfo() */ + #include /* for sockaddr_in, in BSD at least */ + #include + + /*! + * \brief In Winsock, a socket handle is of type SOCKET; in UN*Xes, + * it's a file descriptor, and therefore a signed integer. + * We define PCAP_SOCKET to be a signed integer on UN*X and a + * SOCKET on Windows, so that it can be used on both platforms. + * + * We used to use SOCKET rather than PCAP_SOCKET, but that collided + * with other software, such as barnyard2, which had their own + * definitions of SOCKET, so we changed it to PCAP_SOCKET. + * + * On UN*Xes, this might break code that uses one of the two + * active-mode APIs that return a socket handle if those programs + * were written to assign the return values of those APIs to a + * SOCKET, as we're no longer defining SOCKET. However, as + * those APIs are only provided if libpcap is built with remote + * capture support - which is not the default - and as they're + * somewhat painful to use, there's probably little if any code + * that needs to compile for UN*X and that uses them. If there + * *is* any such code, it could do + * + * #ifndef PCAP_SOCKET + * #ifdef _WIN32 + * #define PCAP_SOCKET SOCKET + * #else + * #defube PCAP_SOCKET int + * #endif + * #endif + * + * and use PCAP_SOCKET. + */ + #ifndef PCAP_SOCKET + #define PCAP_SOCKET int + #endif + + /*! + * \brief In Winsock, the error return if socket() fails is INVALID_SOCKET; + * in UN*X, it's -1. + * We define INVALID_SOCKET to be -1 on UN*X, so that it can be used on + * both platforms. + */ + #ifndef INVALID_SOCKET + #define INVALID_SOCKET -1 + #endif +#endif /* _WIN32 */ + +#endif /* lib_pcap_socket_h */ diff --git a/src/libpcap-1.10.5/pcap/usb.h b/src/libpcap-1.10.5/pcap/usb.h new file mode 100644 index 0000000000..48dc9064c5 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/usb.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Basic USB data struct + * By Paolo Abeni + */ + +#ifndef lib_pcap_usb_h +#define lib_pcap_usb_h + +#include + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each Control S-type packet in DLT_USB captures. + */ +typedef struct _usb_setup { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} pcap_usb_setup; + +/* + * Information from the URB for Isochronous transfers. + */ +typedef struct _iso_rec { + int32_t error_count; + int32_t numdesc; +} iso_rec; + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + uint64_t id; + uint8_t event_type; + uint8_t transfer_type; + uint8_t endpoint_number; + uint8_t device_address; + uint16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + uint32_t urb_len; + uint32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + +/* + * Header prepended by linux kernel to each event for the 2.6.31 + * and later kernels; for the 2.6.21 through 2.6.30 kernels, the + * "iso_rec" information, and the fields starting with "interval" + * are zeroed-out padding fields. + * + * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures. + */ +typedef struct _usb_header_mmapped { + uint64_t id; + uint8_t event_type; + uint8_t transfer_type; + uint8_t endpoint_number; + uint8_t device_address; + uint16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + uint32_t urb_len; + uint32_t data_len; /* amount of urb data really present in this event*/ + union { + pcap_usb_setup setup; + iso_rec iso; + } s; + int32_t interval; /* for Interrupt and Isochronous events */ + int32_t start_frame; /* for Isochronous events */ + uint32_t xfer_flags; /* copy of URB's transfer flags */ + uint32_t ndesc; /* number of isochronous descriptors */ +} pcap_usb_header_mmapped; + +/* + * Maximum number of descriptors supported. + * It's currently 128 in the Linux binary USB monitoring code. + */ +#define USB_MAXDESC 128 + +/* + * Isochronous descriptors; for isochronous transfers there might be + * one or more of these at the beginning of the packet data. The + * number of descriptors is given by the "ndesc" field in the header; + * as indicated, in older kernels that don't put the descriptors at + * the beginning of the packet, that field is zeroed out, so that field + * can be trusted even in captures from older kernels. + */ +typedef struct _usb_isodesc { + int32_t status; + uint32_t offset; + uint32_t len; + uint8_t pad[4]; +} usb_isodesc; + +#endif diff --git a/src/libpcap-1.10.5/pcap/vlan.h b/src/libpcap-1.10.5/pcap/vlan.h new file mode 100644 index 0000000000..b29dd73cd3 --- /dev/null +++ b/src/libpcap-1.10.5/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +#include + +struct vlan_tag { + uint16_t vlan_tpid; /* ETH_P_8021Q */ + uint16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/src/libpcap-1.10.5/pcap_activate.3pcap b/src/libpcap-1.10.5/pcap_activate.3pcap new file mode 100644 index 0000000000..9594641323 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_activate.3pcap @@ -0,0 +1,135 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_ACTIVATE 3PCAP "3 June 2024" +.SH NAME +pcap_activate \- activate a capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_activate(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_activate () +is used to activate a packet capture handle to look +at packets on the network, with the options that were set on the handle +being in effect. +.SH RETURN VALUE +.BR pcap_activate () +returns +.B 0 +on success without warnings, a non-zero positive value on +success with warnings, and a negative value on error. +A non-zero return value indicates what warning or error condition +occurred. +.LP +The possible warning values are: +.TP +.B PCAP_WARNING_PROMISC_NOTSUP +Promiscuous mode was requested, but the capture source doesn't support +promiscuous mode. +.TP +.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP +The time stamp type specified in a previous +.BR pcap_set_tstamp_type (3PCAP) +call isn't supported by the capture source (the time stamp type is +left as the default), +.TP +.B PCAP_WARNING +Another warning condition occurred; +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display a message describing the warning +condition. +.LP +The possible error values are: +.TP +.B PCAP_ERROR_ACTIVATED +The handle has already been activated. +.TP +.B PCAP_ERROR_NO_SUCH_DEVICE +The capture source specified when the handle was created doesn't +exist. +.TP +.B PCAP_ERROR_PERM_DENIED +The process doesn't have permission to open the capture source. +.TP +.B PCAP_ERROR_PROMISC_PERM_DENIED +The process has permission to open the capture source but doesn't +have permission to put it into promiscuous mode. +.TP +.B PCAP_ERROR_RFMON_NOTSUP +Monitor mode was specified but the capture source doesn't support +monitor mode. +.TP +.B PCAP_ERROR_IFACE_NOT_UP +The capture source device is not up. +.TP +.B PCAP_ERROR_CAPTURE_NOTSUP +Packet capture is not supported on the capture source. +.TP +.B PCAP_ERROR +Another error occurred. +.BR pcap_geterr () +or +.BR pcap_perror () +may be called with +.I p +as an argument to fetch or display a message describing the error. +.LP +If +.BR PCAP_WARNING_PROMISC_NOTSUP , +.BR PCAP_ERROR_NO_SUCH_DEVICE , +.BR PCAP_ERROR_PERM_DENIED , +or +.B PCAP_ERROR_CAPTURE_NOTSUP +is returned, +.BR pcap_geterr () +or +.BR pcap_perror () +may be called with +.I p +as an argument to fetch or display an message giving additional details +about the problem that might be useful for debugging the problem if it's +unexpected. +.LP +Additional warning and error codes may be added in the future; a program +should check for positive, negative, and zero return codes, and treat +all positive return codes as warnings and all negative return +codes as errors. +.BR pcap_statustostr (3PCAP) +can be called, with a warning or error code as an argument, to fetch a +message describing the warning or error code. +.LP +If +.BR pcap_activate () +fails, the +.B pcap_t * +is not closed and freed; it should be closed using +.BR pcap_close (3PCAP). +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_breakloop.3pcap b/src/libpcap-1.10.5/pcap_breakloop.3pcap new file mode 100644 index 0000000000..b5e5988373 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_breakloop.3pcap @@ -0,0 +1,148 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_BREAKLOOP 3PCAP "8 December 2022" +.SH NAME +pcap_breakloop \- force a pcap_dispatch() or pcap_loop() call to return +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_breakloop(pcap_t *); +.ft +.fi +.SH DESCRIPTION +.BR pcap_breakloop () +sets a flag that will force +.BR pcap_dispatch (3PCAP) +or +.BR pcap_loop (3PCAP) +to return rather than looping; they will return the number of packets +that have been processed so far, or +.B PCAP_ERROR_BREAK +if no packets have been processed so far. If the loop is currently +blocked waiting for packets to arrive, +.BR pcap_breakloop () +will also, on some platforms, wake up the thread that is blocked. In +this version of libpcap, the only platforms on which a wakeup is caused +by +.BR pcap_breakloop () +are Linux and Windows, and the wakeup will only be caused when capturing +on network interfaces; it will not be caused on other operating systems, +and will not be caused on any OS when capturing on other types of +devices. +.PP +This routine is safe to use inside a signal handler on UNIX or a console +control handler on Windows, or in a thread other than the one in which +the loop is running, as it merely sets a flag that is checked within the +loop and, on some platforms, performs a signal-safe and thread-safe API +call. +.PP +The flag is checked in loops reading packets from the OS - a signal by +itself will not necessarily terminate those loops - as well as in loops +processing a set of packets returned by the OS. +.ft B +Note that if you are catching signals on UNIX systems that support +restarting system calls after a signal, and calling pcap_breakloop() +in the signal handler, you must specify, when catching those signals, +that system calls should NOT be restarted by that signal. Otherwise, +if the signal interrupted a call reading packets in a live capture, +when your signal handler returns after calling pcap_breakloop(), the +call will be restarted, and the loop will not terminate until more +packets arrive and the call completes. +.ft R +.PP +.ft B +Note also that, in a multi-threaded application, if one thread is +blocked in pcap_dispatch(), pcap_loop(), pcap_next(3PCAP), or +pcap_next_ex(3PCAP), a call to pcap_breakloop() in a different thread +will only unblock that thread on the platforms and capture devices +listed above. +.ft R +.PP +If a non-zero packet buffer timeout is set on the +.BR pcap_t , +and you are capturing on a network interface, the thread will be +unblocked with the timeout expires. This is not guaranteed to happen +unless at least one packet has arrived; the only platforms on which it +happens are macOS, the BSDs, Solaris 11, AIX, Tru64 UNIX, and Windows. +.PP +If you want to ensure that the loop will eventually be unblocked on any +other platforms, or unblocked when capturing on a device other than a +network interface, you will need to use whatever mechanism the OS +provides for breaking a thread out of blocking calls in order to unblock +the thread, such as thread cancellation or thread signalling in systems +that support POSIX threads. +.PP +.ft B +Note that if pcap_breakloop() unblocks the thread capturing packets, and +you are running on a platform that supports packet buffering, there may +be packets in the buffer that arrived before pcap_breakloop() were +called but that weren't yet provided to libpcap, those packets will not +have been processed by pcap_dispatch() or pcap_loop(). If +pcap_breakloop() was called in order to terminate the capture process, +then, in order to process those packets, you would have to call +pcap_dispatch() one time in order to process the last batch of packets. +This may block until the packet buffer timeout expires, so a non-zero +packet buffer timeout must be used. +.ft R +.PP +Note that +.BR pcap_next () +and +.BR pcap_next_ex () +will, on some platforms, loop reading packets from the OS; that loop +will not necessarily be terminated by a signal, so +.BR pcap_breakloop () +should be used to terminate packet processing even if +.BR pcap_next () +or +.BR pcap_next_ex () +is being used. +.PP +.BR pcap_breakloop () +does not guarantee that no further packets will be processed by +.BR pcap_dispatch () +or +.BR pcap_loop () +after it is called; at most one more packet might be processed. +.PP +If +.B PCAP_ERROR_BREAK +is returned from +.BR pcap_dispatch () +or +.BR pcap_loop (), +the flag is cleared, so a subsequent call will resume reading packets. +If a positive number is returned, the flag is not cleared, so a +subsequent call will return +.B PCAP_ERROR_BREAK +and clear the flag. +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 0.8.1. +.PP +In releases prior to libpcap 1.10.0, +.BR pcap_breakloop () +will not wake up a blocked thread on any platform. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_can_set_rfmon.3pcap b/src/libpcap-1.10.5/pcap_can_set_rfmon.3pcap new file mode 100644 index 0000000000..be03956bb9 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_can_set_rfmon.3pcap @@ -0,0 +1,80 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CAN_SET_RFMON 3PCAP "31 July 2016" +.SH NAME +pcap_can_set_rfmon \- check whether monitor mode can be set for a +not-yet-activated capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_can_set_rfmon(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_can_set_rfmon () +checks whether monitor mode could be set on a capture handle when +the handle is activated. +.SH RETURN VALUE +.BR pcap_can_set_rfmon () +returns +.B 0 +if monitor mode could not be set, +.B 1 +if monitor mode could be set, and a negative value on error. +A negative return value indicates what error condition occurred. +The possible error values are: +.TP +.B PCAP_ERROR_NO_SUCH_DEVICE +The capture source specified when the handle was created doesn't +exist. +.TP +.B PCAP_ERROR_PERM_DENIED +The process doesn't have permission to check whether monitor mode +could be supported. +.TP +.B PCAP_ERROR_ACTIVATED +The capture handle has already been activated. +.TP +.B PCAP_ERROR +Another error occurred. +.BR pcap_geterr (3PCAP) +or +.BR \%pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display a message describing the error. +.LP +Additional error codes may be added in the future; a program should +check for +.BR 0 , +.BR 1 , +and negative, return codes, and treat all negative +return codes as errors. +.BR pcap_statustostr (3PCAP) +can be called, with a warning or error code as an argument, to fetch a +message describing the warning or error code. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP), +.BR pcap_set_rfmon (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_close.3pcap b/src/libpcap-1.10.5/pcap_close.3pcap new file mode 100644 index 0000000000..c4ac3fad8e --- /dev/null +++ b/src/libpcap-1.10.5/pcap_close.3pcap @@ -0,0 +1,39 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CLOSE 3PCAP "3 January 2014" +.SH NAME +pcap_close \- close a capture device or savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_close(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_close () +closes the files associated with +.I p +and deallocates resources. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_compile.3pcap.in b/src/libpcap-1.10.5/pcap_compile.3pcap.in new file mode 100644 index 0000000000..12aa8fe62a --- /dev/null +++ b/src/libpcap-1.10.5/pcap_compile.3pcap.in @@ -0,0 +1,92 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_COMPILE 3PCAP "22 August 2018" +.SH NAME +pcap_compile \- compile a filter expression +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_compile(pcap_t *p, struct bpf_program *fp, + const char *str, int optimize, bpf_u_int32 netmask); +.ft +.fi +.SH DESCRIPTION +.BR pcap_compile () +is used to compile the string +.I str +into a filter program. See +.BR \%pcap-filter (@MAN_MISC_INFO@) +for the syntax of that string. +.I fp +is a pointer to a +.I bpf_program +struct and is filled in by +.BR pcap_compile (). +.I optimize +controls whether optimization on the resulting code is performed. +.I netmask +specifies the IPv4 netmask of the network on which packets are being +captured; it is used only when checking for IPv4 broadcast addresses in +the filter program. If the netmask of the network on which packets are +being captured isn't known to the program, or if packets are being +captured on the Linux "any" pseudo-interface that can capture on more +than one network, a value of +.B PCAP_NETMASK_UNKNOWN +can be supplied; tests +for IPv4 broadcast addresses will fail to compile, but all other tests in +the filter program will be OK. +.LP +NOTE: in libpcap 1.8.0 and later, +.BR pcap_compile () +can be used in multiple threads within a single process. However, in +earlier versions of libpcap, it is +.I not +safe to use +.BR pcap_compile () +in multiple threads in a single process without some form of mutual +exclusion allowing only one thread to call it at any given time. +.SH RETURN VALUE +.BR pcap_compile () +returns +.B 0 +on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH BACKWARD COMPATIBILITY +.PP +The +.B PCAP_NETMASK_UNKNOWN +constant became available in libpcap release 1.1.0. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_setfilter (3PCAP), +.BR pcap_freecode (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_create.3pcap b/src/libpcap-1.10.5/pcap_create.3pcap new file mode 100644 index 0000000000..f08ac5c2b8 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_create.3pcap @@ -0,0 +1,72 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_CREATE 3PCAP "30 November 2023" +.SH NAME +pcap_create \- create a live capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_create(const char *source, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_create () +is used to create a packet capture handle to look +at packets on the network. +.I source +is a string that specifies the network device to open; on Linux systems +with 2.2 or later kernels, a +.I source +argument of "any" or +.B NULL +can be used to capture packets from all interfaces. +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.PP +The returned handle must be activated with +.BR pcap_activate (3PCAP) +before packets can be captured +with it; options for the capture, such as promiscuous mode, can be set +on the handle before activating it. +.SH RETURN VALUE +.BR pcap_create () +returns a +.B pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_datalink.3pcap.in b/src/libpcap-1.10.5/pcap_datalink.3pcap.in new file mode 100644 index 0000000000..abb7375084 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_datalink.3pcap.in @@ -0,0 +1,71 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK 3PCAP "7 April 2014" +.SH NAME +pcap_datalink \- get the link-layer header type +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_datalink(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_datalink () +returns the link-layer header type for the live capture or ``savefile'' +specified by +.IR p . +.PP +It must not be called on a pcap descriptor created by +.BR \%pcap_create (3PCAP) +that has not yet been activated by +.BR \%pcap_activate (3PCAP). +.PP +.I https://www.tcpdump.org/linktypes.html +lists the values +.BR pcap_datalink () +can return and describes the packet formats that +correspond to those values. +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +or +.B DLT_LINUX_SLL2 +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.BR pcap_datalink () +returns the link-layer header type on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap-linktype (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_datalink_name_to_val.3pcap b/src/libpcap-1.10.5/pcap_datalink_name_to_val.3pcap new file mode 100644 index 0000000000..d2cb103106 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_datalink_name_to_val.3pcap @@ -0,0 +1,49 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK_NAME_TO_VAL 3PCAP "25 July 2018" +.SH NAME +pcap_datalink_name_to_val \- get the link-layer header type value +corresponding to a header type name +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_datalink_name_to_val(const char *name); +.ft +.fi +.SH DESCRIPTION +.BR pcap_datalink_name_to_val () +translates a link-layer header type name, which is a +.B DLT_ +name with the +.B DLT_ +removed, to the corresponding link-layer header type value. The +translation is case-insensitive. +.SH RETURN VALUE +.BR pcap_datalink_name_to_val () +returns the type value on success and +.B PCAP_ERROR +if the name is not a known +type name. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_datalink_val_to_name.3pcap b/src/libpcap-1.10.5/pcap_datalink_val_to_name.3pcap new file mode 100644 index 0000000000..41790950af --- /dev/null +++ b/src/libpcap-1.10.5/pcap_datalink_val_to_name.3pcap @@ -0,0 +1,76 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DATALINK_VAL_TO_NAME 3PCAP "4 May 2022" +.SH NAME +pcap_datalink_val_to_name, pcap_datalink_val_to_description, +pcap_datalink_val_to_description_or_dlt \- get a +name or description for a link-layer header type value +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_datalink_val_to_name(int dlt); +const char *pcap_datalink_val_to_description(int dlt); +const char *pcap_datalink_val_to_description_or_dlt(int dlt); +.ft +.fi +.SH DESCRIPTION +.BR pcap_datalink_val_to_name () +translates a link-layer header type value to the corresponding +link-layer header type name, which is the +.B DLT_ +name for the link-layer header type value with the +.B DLT_ +removed. +.B NULL +is returned if the type value does not correspond to a known +.B DLT_ +value. +.PP +.BR pcap_datalink_val_to_description () +translates a link-layer header type value to a short description of that +link-layer header type. +.B NULL +is returned if the type value does not correspond to a known +.B DLT_ +value. +.PP +.BR pcap_datalink_val_to_description_or_dlt () +translates a link-layer header type value to a short description of that +link-layer header type just like +.BR pcap_datalink_val_to_description (). +If the type value does not correspond to a known +.B DLT_ +value, the string "DLT n" is returned, where n is the value of +the dlt argument. +.SH BACKWARD COMPATIBILITY +The +.BR pcap_datalink_val_to_description_or_dlt () +function first became available in libpcap release 1.9.1. In previous +releases, +.BR pcap_datalink_val_to_description () +would have to be called and, if it returned +.BR NULL , +a default string would have to be constructed. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump.3pcap b/src/libpcap-1.10.5/pcap_dump.3pcap new file mode 100644 index 0000000000..e38c96ce05 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump.3pcap @@ -0,0 +1,49 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP 3PCAP "8 March 2015" +.SH NAME +pcap_dump \- write a packet to a capture file +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_dump(u_char *user, struct pcap_pkthdr *h, + u_char *sp); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump () +outputs a packet to the ``savefile'' opened with +.BR pcap_dump_open (3PCAP). +Note that its calling arguments are suitable for use with +.BR pcap_dispatch (3PCAP) +or +.BR pcap_loop (3PCAP). +If called directly, the +.I user +parameter is of type +.B pcap_dumper_t +as returned by +.BR pcap_dump_open (). +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump_close.3pcap b/src/libpcap-1.10.5/pcap_dump_close.3pcap new file mode 100644 index 0000000000..a62eb34dbf --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump_close.3pcap @@ -0,0 +1,39 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_CLOSE 3PCAP "3 January 2014" +.SH NAME +pcap_dump_close \- close a savefile being written to +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_dump_close(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump_close () +closes the ``savefile.'' +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_dump_open (3PCAP), +.BR pcap_dump (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump_file.3pcap b/src/libpcap-1.10.5/pcap_dump_file.3pcap new file mode 100644 index 0000000000..9fd6c7ecc3 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump_file.3pcap @@ -0,0 +1,38 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FILE 3PCAP "3 January 2014" +.SH NAME +pcap_dump_file \- get the standard I/O stream for a savefile being written +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +FILE *pcap_dump_file(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump_file () +returns the standard I/O stream of the ``savefile'' opened by +.BR pcap_dump_open (3PCAP). +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump_flush.3pcap b/src/libpcap-1.10.5/pcap_dump_flush.3pcap new file mode 100644 index 0000000000..c6e0f86ed7 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump_flush.3pcap @@ -0,0 +1,48 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FLUSH 3PCAP "25 July 2018" +.SH NAME +pcap_dump_flush \- flush to a savefile packets dumped +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_dump_flush(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump_flush () +flushes the output buffer to the ``savefile,'' so that any packets +written with +.BR pcap_dump (3PCAP) +but not yet written to the ``savefile'' will be written. +.SH RETURN VALUE +.BR pcap_dump_flush () +returns +.B 0 +on success and +.B PCAP_ERROR +on failure. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_dump_open (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump_ftell.3pcap b/src/libpcap-1.10.5/pcap_dump_ftell.3pcap new file mode 100644 index 0000000000..062d60957a --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump_ftell.3pcap @@ -0,0 +1,64 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_FTELL 3PCAP "25 July 2018" +.SH NAME +pcap_dump_ftell, pcap_dump_ftell64 \- get the current file offset for a savefile being written +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +long pcap_dump_ftell(pcap_dumper_t *p); +.ft B +int64_t pcap_dump_ftell64(pcap_dumper_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump_ftell () +returns the current file position for the ``savefile'', representing the +number of bytes written by +.BR pcap_dump_open (3PCAP) +and +.BR pcap_dump (3PCAP). +.B PCAP_ERROR +is returned on error. If the current file position does not fit in a +.BR long , +it will be truncated; this can happen on 32-bit UNIX-like systems with +large file support and on Windows. +.BR pcap_dump_ftell64 () +returns the current file position in a +.BR int64_t , +so if file offsets that don't fit in a +.B long +but that fit in a +.B int64_t +are supported, this will return the file offset without truncation. +.B PCAP_ERROR +is returned on error. +.SH BACKWARD COMPATIBILITY +The function +.BR pcap_dump_ftell64 () +became available in libpcap release 1.9.0. In previous releases, there +was no mechanism to obtain a file offset that is too large to fit in a +.BR long . +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_dump_open.3pcap.in b/src/libpcap-1.10.5/pcap_dump_open.3pcap.in new file mode 100644 index 0000000000..555484ffcd --- /dev/null +++ b/src/libpcap-1.10.5/pcap_dump_open.3pcap.in @@ -0,0 +1,108 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_DUMP_OPEN 3PCAP "3 July 2020" +.SH NAME +pcap_dump_open, pcap_dump_open_append, pcap_dump_fopen \- open a file to +which to write packets +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.nf +.LP +.ft B +pcap_dumper_t *pcap_dump_open(pcap_t *p, const char *fname); +pcap_dumper_t *pcap_dump_open_append(pcap_t *p, const char *fname); +pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *fp); +.ft +.fi +.SH DESCRIPTION +.BR pcap_dump_open () +is called to open a ``savefile'' for writing. +.I fname +specifies the name of the file to open. The file will have +the same format as those used by +.BR tcpdump (1) +and +.BR tcpslice (1). +If the file does not exist, it will be created; if the file exists, it +will be truncated and overwritten. +The name "-" is a synonym +for +.BR stdout . +.PP +.BR pcap_dump_fopen () +is called to write data to an existing open stream +.IR fp ; +this stream will be closed by a subsequent call to +.BR pcap_dump_close (3PCAP). +The stream is assumed to be at the beginning of a file that has been +newly created or truncated, so that writes will start at the beginning +of the file. +Note that on Windows, that stream should be opened in binary mode. +.PP +.I p +is a capture or ``savefile'' handle returned by an earlier call to +.BR pcap_create (3PCAP) +and activated by an earlier call to +.BR \%pcap_activate (3PCAP), +or returned by an earlier call to +.BR \%pcap_open_offline (3PCAP), +.BR pcap_open_live (3PCAP), +or +.BR pcap_open_dead (3PCAP). +The time stamp precision, link-layer type, and snapshot length from +.I p +are used as the link-layer type and snapshot length of the output file. +.PP +.BR pcap_dump_open_append () +is like +.BR pcap_dump_open () +but, if the file already exists, and is a pcap file with the same byte +order as the host opening the file, and has the same time stamp +precision, link-layer header type, and snapshot length as +.IR p , +it will write new packets at the end of the file. +.SH RETURN VALUE +A pointer to a +.B pcap_dumper_t +structure to use in subsequent +.BR pcap_dump (3PCAP) +and +.BR pcap_dump_close (3PCAP) +calls is returned on success. +.B NULL +is returned on failure. +If +.B NULL +is returned, +.BR pcap_geterr (3PCAP) +can be used to get the error text. +.SH BACKWARD COMPATIBILITY +.PP +The +.BR pcap_dump_open_append () +function became available in libpcap release 1.7.2. In previous +releases, there is no support for appending packets to an existing +savefile. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR \%pcap-savefile (@MAN_FILE_FORMATS@) diff --git a/src/libpcap-1.10.5/pcap_file.3pcap b/src/libpcap-1.10.5/pcap_file.3pcap new file mode 100644 index 0000000000..74029732d3 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_file.3pcap @@ -0,0 +1,59 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FILE 3PCAP "3 January 2014" +.SH NAME +pcap_file \- get the standard I/O stream for a savefile being read +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +FILE *pcap_file(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_file () +returns the standard I/O stream of the ``savefile,'' if a ``savefile'' +was opened with +.BR pcap_open_offline (3PCAP), +or +.BR NULL , +if a network device was opened with +.BR pcap_create (3PCAP) +and +.BR \%pcap_activate (3PCAP), +or with +.BR pcap_open_live (3PCAP). +.PP +Note that the Packet Capture library is usually built with large file +support, so the standard I/O stream of the ``savefile'' might refer to +a file larger than 2 gigabytes; applications that use +.BR pcap_file () +should, if possible, use calls that support large files on the return +value of +.BR pcap_file () +or the value returned by +.BR fileno (3) +when passed the return value of +.BR pcap_file (). +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_fileno.3pcap b/src/libpcap-1.10.5/pcap_fileno.3pcap new file mode 100644 index 0000000000..6d0edf88dc --- /dev/null +++ b/src/libpcap-1.10.5/pcap_fileno.3pcap @@ -0,0 +1,65 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FILENO 3PCAP "25 July 2018" +.SH NAME +pcap_fileno \- get the file descriptor for a live capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_fileno(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +If +.I p +refers to a network device that was opened for a live capture using +a combination of +.BR pcap_create (3PCAP) +and +.BR pcap_activate (3PCAP), +or using +.BR pcap_open_live (3PCAP), +.BR pcap_fileno () +returns the file descriptor from which captured packets are read. +.LP +If +.I p +refers to a ``savefile'' that was opened using functions such as +.BR pcap_open_offline (3PCAP) +or +.BR pcap_fopen_offline (3PCAP), +a ``dead'' +.B pcap_t +opened using +.BR pcap_open_dead (3PCAP), +or a +.B pcap_t +that was created with +.BR pcap_create () +but that has not yet been activated with +.BR pcap_activate (), +it returns +.BR PCAP_ERROR . +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_findalldevs.3pcap b/src/libpcap-1.10.5/pcap_findalldevs.3pcap new file mode 100644 index 0000000000..987d2a7447 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_findalldevs.3pcap @@ -0,0 +1,262 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FINDALLDEVS 3PCAP "9 August 2024" +.SH NAME +pcap_findalldevs, pcap_freealldevs \- get a list of capture devices, and +free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf); +void pcap_freealldevs(pcap_if_t *alldevs); +.ft +.fi +.SH DESCRIPTION +.BR pcap_findalldevs () +constructs a list of network devices that can be opened with +.BR pcap_create (3PCAP) +and +.BR pcap_activate (3PCAP) +or with +.BR pcap_open_live (3PCAP). +(Note that there may be network devices that cannot be opened by the +process calling +.BR pcap_findalldevs (), +because, for example, that process does not have sufficient privileges +to open them for capturing; if so, those devices will not appear on the +list.) +.I alldevsp +is a pointer to a +.BR "pcap_if_t *" ; +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.PP +If +.BR pcap_findalldevs () +succeeds, the pointer pointed to by +.I alldevsp +is set to point to the first element of the list, or to +.B NULL +if no devices were found (this is considered success). +Each element of the list is of type +.BR pcap_if_t , +and has the following members: +.RS +.TP +.B next +if not +.BR NULL , +a pointer to the next element in the list; +.B NULL +for the last element of the list +.TP +.B name +a pointer to a string giving a name for the device to pass to +.BR pcap_open_live () +.TP +.B description +if not +.BR NULL , +a pointer to a string giving a human-readable description of the device +.TP +.B addresses +a pointer to the first element of a list of network addresses for the +device, +or +.B NULL +if the device has no addresses +.TP +.B flags +device flags: +.RS +.TP +.B PCAP_IF_LOOPBACK +set if the device is a loopback interface +.TP +.B PCAP_IF_UP +set if the device is up +.TP +.B PCAP_IF_RUNNING +set if the device is running +.TP +.B PCAP_IF_WIRELESS +set if the device is a wireless interface; this includes IrDA as well as +radio-based networks such as IEEE 802.15.4 and IEEE 802.11, so it +doesn't just mean Wi-Fi +.TP +.B PCAP_IF_CONNECTION_STATUS +a bitmask for an indication of whether the adapter is connected or not; +for wireless interfaces, "connected" means "associated with a network" +.TP +The possible values for the connection status bits are: +.TP +.B PCAP_IF_CONNECTION_STATUS_UNKNOWN +it's unknown whether the adapter is connected or not +.TP +.B PCAP_IF_CONNECTION_STATUS_CONNECTED +the adapter is connected +.TP +.B PCAP_IF_CONNECTION_STATUS_DISCONNECTED +the adapter is disconnected +.TP +.B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE +the notion of "connected" and "disconnected" don't apply to this +interface; for example, it doesn't apply to a loopback device +.RE +.RE +.PP +Each element of the list of addresses is of type +.BR pcap_addr_t , +and has the following members: +.RS +.TP +.B next +if not +.BR NULL , +a pointer to the next element in the list; +.B NULL +for the last element of the list +.TP +.B addr +a pointer to a +.B "struct sockaddr" +containing an address +.TP +.B netmask +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the netmask corresponding to the address pointed to by +.B addr +.TP +.B broadaddr +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the broadcast address corresponding to the address pointed +to by +.BR addr ; +may be +.B NULL +if the device doesn't support broadcasts +.TP +.B dstaddr +if not +.BR NULL , +a pointer to a +.B "struct sockaddr" +that contains the destination address corresponding to the address pointed +to by +.BR addr ; +may be +.B NULL +if the device isn't a point-to-point interface +.RE +.PP +Note that the addresses in the list of addresses might be IPv4 +addresses, IPv6 addresses, or some other type of addresses, so you must +check the +.B sa_family +member of the +.B "struct sockaddr" +before interpreting the contents of the address; do not assume that the +addresses are all IPv4 addresses, or even all IPv4 or IPv6 addresses. +IPv4 addresses have the value +.BR AF_INET , +IPv6 addresses have the value +.B AF_INET6 +(which older operating systems that don't support IPv6 might not +define), and other addresses have other values. Whether other addresses +are returned, and what types they might have is platform-dependent. +Namely, link-layer addresses, such as Ethernet MAC addresses, have the value +.B AF_PACKET +(on Linux) or +.B AF_LINK +(on AIX, FreeBSD, Haiku, illumos, macOS, NetBSD and OpenBSD) or are not +returned at all (on GNU/Hurd and Solaris). +.PP +For IPv4 addresses, the +.B "struct sockaddr" +pointer can be interpreted as if it pointed to a +.BR "struct sockaddr_in" ; +for IPv6 addresses, it can be interpreted as if it pointed to a +.BR "struct sockaddr_in6". +For link-layer addresses, it can be interpreted as if it pointed to a +.B "struct sockaddr_ll" +(for +.BR AF_PACKET ) +or a +.B "struct sockaddr_dl" +(for +.BR AF_LINK ). +.PP +The list of devices must be freed with +.BR pcap_freealldevs (3PCAP), +which frees the list pointed to by +.IR alldevs . +.SH RETURN VALUE +.BR pcap_findalldevs () +returns +.B 0 +on success and +.B PCAP_ERROR +on failure; as indicated, finding no +devices is considered success, rather than failure, so +.B 0 +will be +returned in that case. If +.B PCAP_ERROR +is returned, +.I errbuf +is filled in with an appropriate error message, +and the pointer pointed to by +.I alldevsp +is set to +.BR NULL . +.SH BACKWARD COMPATIBILITY +.PP +The +.B PCAP_IF_UP +and +.B PCAP_IF_RUNNING +constants became available in libpcap release 1.6.1. The +.BR PCAP_IF_WIRELESS , +.BR PCAP_IF_CONNECTION_STATUS , +.BR PCAP_IF_CONNECTION_STATUS_UNKNOWN , +.BR PCAP_IF_CONNECTION_STATUS_CONNECTED , +.BR PCAP_IF_CONNECTION_STATUS_DISCONNECTED , +and +.B PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE +constants became available in libpcap release 1.9.0. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_freecode.3pcap b/src/libpcap-1.10.5/pcap_freecode.3pcap new file mode 100644 index 0000000000..65915fa1c7 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_freecode.3pcap @@ -0,0 +1,43 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_FREECODE 3PCAP "3 January 2014" +.SH NAME +pcap_freecode \- free a BPF program +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +void pcap_freecode(struct bpf_program *); +.ft +.fi +.SH DESCRIPTION +.BR pcap_freecode () +is used to free up allocated memory pointed to by a +.I bpf_program +struct generated by +.BR pcap_compile (3PCAP) +when that BPF program is no longer needed, for example after it +has been made the filter program for a pcap structure by a call to +.BR pcap_setfilter (3PCAP). +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_get_required_select_timeout.3pcap b/src/libpcap-1.10.5/pcap_get_required_select_timeout.3pcap new file mode 100644 index 0000000000..37af180352 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_get_required_select_timeout.3pcap @@ -0,0 +1,170 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_GET_REQUIRED_SELECT_TIMEOUT 3PCAP "29 January 2020" +.SH NAME +pcap_get_required_select_timeout \- get a timeout to be used when doing +select() for a live capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const struct timeval *pcap_get_required_select_timeout(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_get_required_select_timeout () +returns, on UNIX, a pointer to a +.B struct timeval +containing a value that must be used as the minimum timeout in +.BR select (2), +.BR poll (2), +.BR epoll_wait (2), +and +.BR kevent (2) +calls, or +.B NULL +if there is no such timeout. +If a +.RB non- NULL +value is returned, it must be used regardless of whether +.BR pcap_get_selectable_fd (3PCAP) +returns +.B \-1 +for any descriptor on which those calls are being done. +.BR pcap_get_required_select_timeout () +should be called for all +.BR pcap_t s +before a call to +.BR select (), +.BR poll (), +.BR epoll_wait (), +or +.BR kevent (), +and any timeouts used for those calls should be updated as appropriate +given the new value of the timeout. +.PP +For +.BR kevent (), +one +.B EVFILT_TIMER +filter per selectable descriptor can be used, rather than using the +timeout argument to +.BR kevent (); +if the +.B EVFILT_TIMER +event for a particular selectable descriptor signals an event, +.BR pcap_dispatch (3PCAP) +should be called for the corresponding +.BR pcap_t . +.PP +On Linux systems with +.BR timerfd_create (2), +one timer object created by +.BR timerfd_create () +per selectable descriptor can be used, rather than using the timeout +argument to +.BR epoll_wait (); +if the +timer object for a particular selectable descriptor signals an event, +.BR pcap_dispatch (3PCAP) +should be called for the corresponding +.BR pcap_t . +.PP +Otherwise, a timeout value no larger than +the smallest of all timeouts returned by +.BR \%pcap_get_required_select_timeout () +for devices from which packets will be captured and any other timeouts +to be used in the call should be used as the timeout for the call, and, +when the call returns, +.BR pcap_dispatch (3PCAP) +should be called for all +.BR pcap_t s +for which a +.RB non- NULL +timeout was returned, regardless of whether it's indicated as having +anything to read from it or not. +.PP +All devices with a +.RB non- NULL +timeout must be put in non-blocking mode with +.BR pcap_setnonblock (3PCAP). +.PP +Note that a device on which a read can be done without blocking may, +on some platforms, not have any packets to read if the packet buffer +timeout has expired. A call to +.BR pcap_dispatch () +or +.BR pcap_next_ex (3PCAP) +will return +.B 0 +in this case, but will not block. +.PP +.BR pcap_get_required_select_timeout () +is not available on Windows. +.SH RETURN VALUE +A pointer to a +.B struct timeval +is returned if the timeout is required; otherwise +.B NULL +is returned. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.9.0. In previous +releases, +.BR select (), +.BR poll (), +.BR epoll_wait (), +and +.BR kevent () +could not be used for devices that don't provide a selectable file +descriptor (in other words, on any capture source for that +.BR pcap_get_selectable_fd () +returns +.BR \-1 ). +.PP +In libpcap release 1.10.0 and later, the timeout value can change from +call to call, so +.BR pcap_get_required_select_timeout () +must be called before each call to +.BR select (), +.BR poll (), +.BR epoll_wait (), +or +.BR kevent (), +and the new value must be used to calculate timeouts for the call. Code +that does that will also work with libpcap 1.9.x releases, so code +using +.BR pcap_get_required_select_timeout () +should be changed to call it for each call to +.BR select (), +.BR poll (), +.BR epoll_wait (), +or +.BR kevent () +even if the code must also work with libpcap 1.9.x. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_get_selectable_fd (3PCAP), +.BR select (2), +.BR poll (2), +.BR epoll_wait (2), +.BR kqueue (2) diff --git a/src/libpcap-1.10.5/pcap_get_selectable_fd.3pcap b/src/libpcap-1.10.5/pcap_get_selectable_fd.3pcap new file mode 100644 index 0000000000..ed333038a0 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_get_selectable_fd.3pcap @@ -0,0 +1,152 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_GET_SELECTABLE_FD 3PCAP "29 January 2020" +.SH NAME +pcap_get_selectable_fd \- get a file descriptor on which a select() can +be done for a live capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_get_selectable_fd(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_get_selectable_fd () +returns, on UNIX, a file descriptor number for a file descriptor on +which one can +do a +.BR select (2), +.BR poll (2), +.BR epoll_wait (2), +.BR kevent (2), +or other such call +to wait for it to be possible to read packets without blocking, if such +a descriptor exists, or +.BR \-1 , +if no such descriptor exists. +.PP +Some network devices opened with +.BR pcap_create (3PCAP) +and +.BR pcap_activate (3PCAP), +or with +.BR pcap_open_live (3PCAP), +do not support those calls (for example, regular network devices on +FreeBSD 4.3 and 4.4, and Endace DAG devices), so +.B \-1 +is returned for +those devices. In that case, those calls must be given a timeout less +than or equal to the timeout returned by +.BR pcap_get_required_select_timeout (3PCAP) +for the device for which +.BR pcap_get_selectable_fd () +returned +.BR \-1 , +the device must be put in non-blocking mode with a call to +.BR \%pcap_setnonblock (3PCAP), +and an attempt must always be made to read packets from the device +when the call returns. If +.BR \%pcap_get_required_select_timeout () +returns +.BR NULL , +it is not possible to wait for packets to arrive on the device in an +event loop. +.PP +Note that a device on which a read can be done without blocking may, +on some platforms, not have any packets to read if the packet buffer +timeout has expired. A call to +.BR pcap_dispatch (3PCAP) +or +.BR pcap_next_ex (3PCAP) +will return 0 in this case, but will not block. +.PP +Note that in: +.IP +FreeBSD prior to FreeBSD 4.6; +.IP +NetBSD prior to NetBSD 3.0; +.IP +OpenBSD prior to OpenBSD 2.4; +.IP +Mac OS X prior to Mac OS X 10.7; +.PP +.BR select (), +.BR poll (), +and +.BR kevent () +do not work correctly on BPF devices; +.BR pcap_get_selectable_fd () +will return a file descriptor on most of those versions (the exceptions +being FreeBSD 4.3 and 4.4), but a simple +.BR select (), +.BR poll (), +or +.BR kevent () +call will not indicate that the descriptor is readable until a full +buffer's worth of packets is received, even if the packet timeout +expires before then. To work around this, code that uses +those calls to wait for packets to arrive must put the +.B pcap_t +in non-blocking mode, and must arrange that the call +have a timeout less than or equal to the packet buffer timeout, +and must try to read packets after that timeout expires, regardless of +whether the call indicated that the file descriptor for the +.B pcap_t +is ready to be read or not. (That workaround will not work in FreeBSD +4.3 and later; however, in FreeBSD 4.6 and later, those calls +work correctly on BPF devices, so the workaround isn't necessary, +although it does no harm.) +.PP +Note also that +.BR poll () +and +.BR kevent () +doesn't work on character special files, including BPF devices, in Mac +OS X 10.4 and 10.5, so, while +.BR select () +can be used on the descriptor returned by +.BR pcap_get_selectable_fd (), +.BR poll () +and +.BR kevent () +cannot be used on it those versions of Mac OS X. +.BR poll (), +but not +.BR kevent (), +works on that descriptor in Mac OS X releases prior to +10.4; +.BR poll () +and +.BR kevent () +work on that descriptor in Mac OS X 10.6 and later. +.PP +.BR pcap_get_selectable_fd () +is not available on Windows. +.SH RETURN VALUE +A selectable file descriptor is returned if one exists; otherwise, +.B \-1 +is returned. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR kqueue (2) diff --git a/src/libpcap-1.10.5/pcap_get_tstamp_precision.3pcap.in b/src/libpcap-1.10.5/pcap_get_tstamp_precision.3pcap.in new file mode 100644 index 0000000000..46451446ba --- /dev/null +++ b/src/libpcap-1.10.5/pcap_get_tstamp_precision.3pcap.in @@ -0,0 +1,56 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"All rights reserved. +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. The names of the authors may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\"THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +.TH PCAP_GET_TSTAMP_PRECISION 3PCAP "23 August 2018" +.SH NAME +pcap_get_tstamp_precision \- get the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_get_tstamp_precision(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_get_tstamp_precision () +returns the precision of the time stamp returned in packet captures on the pcap +descriptor. +.SH RETURN VALUE +.BR pcap_get_tstamp_precision () +returns +.B PCAP_TSTAMP_PRECISION_MICRO +or +.BR PCAP_TSTAMP_PRECISION_NANO , +which indicates +that pcap captures contains time stamps in microseconds or nanoseconds +respectively. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.5.1. In previous +releases, time stamps from a capture device or savefile are always given +in seconds and microseconds. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_set_tstamp_precision (3PCAP), +.BR \%pcap-tstamp (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_geterr.3pcap b/src/libpcap-1.10.5/pcap_geterr.3pcap new file mode 100644 index 0000000000..72e23e38e0 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_geterr.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_GETERR 3PCAP "15 January 2016" +.SH NAME +pcap_geterr, pcap_perror \- get or print libpcap error message text +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +char *pcap_geterr(pcap_t *p); +void pcap_perror(pcap_t *p, const char *prefix); +.ft +.fi +.SH DESCRIPTION +.BR pcap_geterr () +returns the error text pertaining to the last pcap library error. +.BR NOTE : +the pointer it returns will no longer point to a valid error message +string after the +.B pcap_t +passed to it is closed; you must use or copy the string before closing +the +.BR pcap_t . +.PP +.BR pcap_perror () +prints the text of the last pcap library error on +.BR stderr , +prefixed by +.IR prefix . +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_init.3pcap b/src/libpcap-1.10.5/pcap_init.3pcap new file mode 100644 index 0000000000..3bef7dcddc --- /dev/null +++ b/src/libpcap-1.10.5/pcap_init.3pcap @@ -0,0 +1,102 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_INIT 3PCAP "30 November 2023" +.SH NAME +pcap_init \- initialize the library +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_init(unsigned int opts, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_init () +is used to initialize the Packet Capture library. +.I opts +specifies options for the library; +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.PP +Currently, the options that can be specified in +.I opts +are: +.TP +.B PCAP_CHAR_ENC_LOCAL +Treat all strings supplied as arguments, and return all strings to the +caller, as being in the local character encoding. +.TP +.B PCAP_CHAR_ENC_UTF_8 +Treat all strings supplied as arguments, and return all strings to the +caller, as being in UTF-8. +.PP +On UNIX-like systems, the local character encoding is assumed to be +UTF-8, so no character encoding transformations are done. +.PP +On Windows, the local character encoding is the local ANSI code page. +.PP +If +.BR pcap_init () +is not called, strings are treated as being in the local ANSI code page +on Windows, +.BR pcap_lookupdev (3PCAP) +will succeed if there is a device on which to capture, and +.BR pcap_create (3PCAP) +makes an attempt to check whether the string passed as an argument is a +UTF-16LE string - note that this attempt is unsafe, as it may run past +the end of the string - to handle +.BR pcap_lookupdev () +returning a UTF-16LE string. Programs that don't call +.BR pcap_init () +should, on Windows, call +.BR pcap_wsockinit () +to initialize Winsock; this is not necessary if +.BR pcap_init () +is called, as +.BR pcap_init () +will initialize Winsock itself on Windows. +.SH RETURN VALUE +.BR pcap_init () +returns +.B 0 +on success and +.B PCAP_ERROR +on failure. +If +.B PCAP_ERROR +is returned, +.I errbuf +is filled in with an appropriate error message. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.9.0. In previous +releases, on Windows, all strings supplied as arguments, and all strings +returned to the caller, are in the local character encoding. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_inject.3pcap b/src/libpcap-1.10.5/pcap_inject.3pcap new file mode 100644 index 0000000000..83eae1c384 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_inject.3pcap @@ -0,0 +1,102 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_INJECT 3PCAP "5 March 2022" +.SH NAME +pcap_inject, pcap_sendpacket \- transmit a packet +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_inject(pcap_t *p, const void *buf, size_t size); +int pcap_sendpacket(pcap_t *p, const u_char *buf, int size); +.ft +.fi +.SH DESCRIPTION +.BR pcap_inject () +sends a raw packet through the network interface; +.I buf +points to the data of the packet, including the link-layer header, and +.I size +is the number of bytes in the packet. +.PP +Note that, even if you successfully open the network interface, you +might not have permission to send packets on it, or it might not support +sending packets; as +.BR pcap_open_live (3PCAP) +doesn't have a flag to indicate whether to open for capturing, sending, +or capturing and sending, you cannot request an open that supports +sending and be notified at open time whether sending will be possible. +Note also that some devices might not support sending packets. +.PP +Note that, on some platforms, the link-layer header of the packet that's +sent might not be the same as the link-layer header of the packet +supplied to +.BR pcap_inject (), +as the source link-layer address, if the header contains such an +address, might be changed to be the address assigned to the interface on +which the packet it sent, if the platform doesn't support sending +completely raw and unchanged packets. Even worse, some drivers on some +platforms might change the link-layer type field to whatever value +libpcap used when attaching to the device, even on platforms that +.I do +nominally support sending completely raw and unchanged packets. +.PP +.BR pcap_sendpacket () +is like +.BR pcap_inject (), +but it returns +.B 0 +on success, rather than returning the number of bytes +written. +.RB ( pcap_inject () +comes from OpenBSD; +.BR pcap_sendpacket () +comes from WinPcap/Npcap. Both are provided for compatibility.) +.SH RETURN VALUE +.BR pcap_inject () +returns the number of bytes written on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, and +.B PCAP_ERROR +on other errors. +.PP +.BR pcap_sendpacket () +returns +.B 0 +on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, and +.B PCAP_ERROR +on other errors. +.PP +If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_is_swapped.3pcap b/src/libpcap-1.10.5/pcap_is_swapped.3pcap new file mode 100644 index 0000000000..260601a970 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_is_swapped.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_IS_SWAPPED 3PCAP "7 April 2014" +.SH NAME +pcap_is_swapped \- find out whether a savefile has the native byte order +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_is_swapped(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_is_swapped () +returns true (\fB1\fP) if +.I p +refers to a ``savefile'' that uses a different byte order +than the current system. For a live capture, it always returns false +(\fB0\fP). +.PP +It must not be called on a pcap descriptor created by +.BR \%pcap_create (3PCAP) +that has not yet been activated by +.BR \%pcap_activate (3PCAP). +.SH RETURN VALUE +.BR pcap_is_swapped () +returns true (\fB1\fP) or false (\fB0\fP) on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_lib_version.3pcap b/src/libpcap-1.10.5/pcap_lib_version.3pcap new file mode 100644 index 0000000000..73ed2b8864 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_lib_version.3pcap @@ -0,0 +1,39 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIB_VERSION 3PCAP "3 January 2014" +.SH NAME +pcap_lib_version \- get the version information for libpcap +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_lib_version(void); +.ft +.fi +.SH DESCRIPTION +.BR pcap_lib_version () +returns a pointer to a string giving information about the version of +the libpcap library being used; note that it contains more information +than just a version number. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_list_datalinks.3pcap.in b/src/libpcap-1.10.5/pcap_list_datalinks.3pcap.in new file mode 100644 index 0000000000..d6e314997a --- /dev/null +++ b/src/libpcap-1.10.5/pcap_list_datalinks.3pcap.in @@ -0,0 +1,73 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIST_DATALINKS 3PCAP "25 July 2018" +.SH NAME +pcap_list_datalinks, pcap_free_datalinks \- get a list of link-layer header +types supported by a capture device, and free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_list_datalinks(pcap_t *p, int **dlt_buf); +void pcap_free_datalinks(int *dlt_list); +.ft +.fi +.SH DESCRIPTION +.BR pcap_list_datalinks () +is used to get a list of the supported link-layer header types of the +interface associated with the pcap descriptor. +.BR pcap_list_datalinks () +allocates an array to hold the list and sets +.IR *dlt_buf +to point to that array. +.LP +The caller is responsible for freeing the array with +.BR pcap_free_datalinks (), +which frees the list of link-layer header types pointed to by +.IR dlt_list . +.LP +It must not be called on a pcap descriptor created by +.BR \%pcap_create (3PCAP) +that has not yet been activated by +.BR \%pcap_activate (3PCAP). +.SH RETURN VALUE +.BR pcap_list_datalinks () +returns the number of link-layer header types in the array on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +and +.B PCAP_ERROR +on other errors. +If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR \%pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_datalink_val_to_name (3PCAP), +.BR pcap-linktype (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_list_tstamp_types.3pcap.in b/src/libpcap-1.10.5/pcap_list_tstamp_types.3pcap.in new file mode 100644 index 0000000000..8b6174f4c4 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_list_tstamp_types.3pcap.in @@ -0,0 +1,82 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LIST_TSTAMP_TYPES 3PCAP "8 September 2019" +.SH NAME +pcap_list_tstamp_types, pcap_free_tstamp_types \- get a list of time +stamp types supported by a capture device, and free that list +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp); +void pcap_free_tstamp_types(int *tstamp_types); +.ft +.fi +.SH DESCRIPTION +.BR pcap_list_tstamp_types () +is used to get a list of the supported time stamp types of the interface +associated with the pcap descriptor. +.BR pcap_list_tstamp_types () +allocates an array to hold the list and sets +.I *tstamp_typesp +to point to the array. +See +.BR \%pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.PP +The caller is responsible for freeing the array with +.BR pcap_free_tstamp_types (), +which frees the list pointed to by +.IR tstamp_types . +.SH RETURN VALUE +.BR pcap_list_tstamp_types () +returns the number of time stamp types in the array on success and +.B PCAP_ERROR +on failure. +A return value of one means that the only time stamp type supported is +the one in the list, which is the capture device's default time stamp +type. A return value of zero means that the only time stamp type +supported is +.BR PCAP_TSTAMP_HOST , +which is the capture device's default time stamp type (only older +versions of libpcap will return that; newer versions will always return +one or more types). +If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH BACKWARD COMPATIBILITY +.PP +These functions became available in libpcap release 1.2.1. In previous +releases, the time stamp type cannot be set; only the default time stamp +type offered by a capture source is available. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_tstamp_type_val_to_name (3PCAP), +.BR \%pcap-tstamp (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_lookupdev.3pcap b/src/libpcap-1.10.5/pcap_lookupdev.3pcap new file mode 100644 index 0000000000..b4a305da33 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_lookupdev.3pcap @@ -0,0 +1,86 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOKUPDEV 3PCAP "30 November 2023" +.SH NAME +pcap_lookupdev \- find the default device on which to capture +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +[DEPRECATED] char *pcap_lookupdev(char *errbuf); +.ft +.fi +.SH DESCRIPTION +.B This interface is obsoleted by +.BR pcap_findalldevs (3PCAP). +To find a default device on which to capture, call +.BR pcap_findalldevs () +and, if the list it returns is not empty, use the first device in the +list. (If the list is empty, there are no devices on which capture is +possible.) +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.LP +.B If +.BR pcap_init (3PCAP) +.B has been called, this interface always returns +.BR NULL . +.LP +.BR pcap_lookupdev () +returns a pointer to a string giving the name of a network device +suitable for use with +.BR pcap_create (3PCAP) +and +.BR \%pcap_activate (3PCAP), +or with +.BR pcap_open_live (3PCAP), +and with +.BR pcap_lookupnet (3PCAP). +If there is an error, +or if +.BR pcap_init (3PCAP) +has been called, +.B NULL +is returned and +.I errbuf +is filled in with an appropriate error message. +.SH SEE ALSO +.BR pcap (3PCAP) +.SH BUGS +The pointer returned by +.BR pcap_lookupdev () +points to a static buffer; subsequent calls to +.BR pcap_lookupdev () +in the same thread, or calls to +.BR pcap_lookupdev () +in another thread, may overwrite that buffer. +.LP +In WinPcap and Npcap, this function may return a UTF-16 string rather +than an ASCII or UTF-8 string. diff --git a/src/libpcap-1.10.5/pcap_lookupnet.3pcap b/src/libpcap-1.10.5/pcap_lookupnet.3pcap new file mode 100644 index 0000000000..5decea5799 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_lookupnet.3pcap @@ -0,0 +1,73 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOKUPNET 3PCAP "13 March 2024" +.SH NAME +pcap_lookupnet \- find the IPv4 network number and netmask for a device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_lookupnet(const char *device, bpf_u_int32 *netp, + bpf_u_int32 *maskp, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_lookupnet () +is used to determine the IPv4 network number and mask +associated with the network device +.IR device . +Both +.I netp +and +.I maskp +are +.B bpf_u_int32 +pointers. +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.LP +This function is not available on Windows. It supports neither IPv6 nor +multiple IPv4 addresses per interface, which obviously is not practical in +modern networks. See +.BR pcap_findalldevs (3PCAP) +for a more elaborate solution to the problem. +.SH RETURN VALUE +.BR pcap_lookupnet () +returns +.B 0 +on success and +.B PCAP_ERROR +on failure. If +.B PCAP_ERROR +is returned, +.I errbuf +is filled in with an appropriate error message. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_loop.3pcap b/src/libpcap-1.10.5/pcap_loop.3pcap new file mode 100644 index 0000000000..3f2fe312b5 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_loop.3pcap @@ -0,0 +1,222 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_LOOP 3PCAP "5 March 2022" +.SH NAME +pcap_loop, pcap_dispatch \- process packets from a live capture or savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes); +int pcap_loop(pcap_t *p, int cnt, + pcap_handler callback, u_char *user); +int pcap_dispatch(pcap_t *p, int cnt, + pcap_handler callback, u_char *user); +.ft +.fi +.SH DESCRIPTION +.BR pcap_loop () +processes packets from a live capture or ``savefile'' until +.I cnt +packets are processed, the end of the ``savefile'' is +reached when reading from a ``savefile'', +.BR pcap_breakloop (3PCAP) +is called, or an error occurs. +It does +.B not +return when live packet buffer timeouts occur. +A value of +.B \-1 +or +.B 0 +for +.I cnt +is equivalent to infinity, so that packets are processed until another +ending condition occurs. +.PP +.BR pcap_dispatch () +processes packets from a live capture or ``savefile'' until +.I cnt +packets are processed, the end of the current bufferful of packets is +reached when doing a live capture, the end of the ``savefile'' is +reached when reading from a ``savefile'', +.BR pcap_breakloop () +is called, or an error occurs. +Thus, when doing a live capture, +.I cnt +is the maximum number of packets to process before returning, but is not +a minimum number; when reading a live capture, only one +bufferful of packets is read at a time, so fewer than +.I cnt +packets may be processed. A value of +.B \-1 +or +.B 0 +for +.I cnt +causes all the packets received in one buffer to be processed when +reading a live capture, and causes all the packets in the file to be +processed when reading a ``savefile''. +.PP +Note that, when doing a live capture on some platforms, if the read +timeout expires when there are no packets available, +.BR pcap_dispatch () +will return 0, even when not in non-blocking mode, as there are no +packets to process. Applications should be prepared for this to happen, +but must not rely on it happening. +.PP +.I callback +specifies a +.B pcap_handler +routine to be called with three arguments: +a +.B u_char +pointer which is passed in the +.I user +argument to +.BR pcap_loop () +or +.BR pcap_dispatch (), +a +.B const struct pcap_pkthdr +pointer pointing to the packet time stamp and lengths, and a +.B const u_char +pointer to the first +.B caplen +(as given in the +.BR "struct pcap_pkthdr" , +a pointer to which is passed to the callback routine) +bytes of data from the packet. The +.B struct pcap_pkthdr +and the packet data are not to be freed by the callback routine, and are +not guaranteed to be valid after the callback routine returns; if the +code needs them to be valid after the callback, it must make a copy of +them. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.BR pcap_datalink (3PCAP) +routine when handed the +.B pcap_t +value also passed to +.BR pcap_loop () +or +.BR pcap_dispatch (). +.I https://www.tcpdump.org/linktypes.html +lists the values +.BR pcap_datalink () +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.BR pcap_set_datalink (3PCAP) +is called; after a successful call to +.BR pcap_set_datalink (), +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink (). +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +or +.B DLT_LINUX_SLL2 +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.BR pcap_loop () +returns +.B 0 +if +.I cnt +is exhausted or if, when reading from a ``savefile'', no more packets +are available. It returns +.B PCAP_ERROR_BREAK +if the loop terminated due to a call to +.BR pcap_breakloop () +before any packets were processed, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +or +.B PCAP_ERROR +if another error occurs. +It does +.B not +return when live packet buffer timeouts occur; instead, it attempts to +read more packets. +.PP +.BR pcap_dispatch () +returns the number of packets processed on success; this can be 0 if no +packets were read from a live capture (if, for example, they were +discarded because they didn't pass the packet filter, or if, on +platforms that support a packet buffer timeout that starts before any +packets arrive, the timeout expires before any packets arrive, or if the +file descriptor for the capture device is in non-blocking mode and no +packets were available to be read) or if no more packets are available +in a ``savefile.'' It returns +.B PCAP_ERROR_BREAK +if the loop terminated due to a call to +.BR pcap_breakloop () +before any packets were processed, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +or +.B PCAP_ERROR +if another error occurs. +.ft B +If your application uses pcap_breakloop(), +make sure that you explicitly check for PCAP_ERROR and PCAP_ERROR_BREAK, +rather than just checking for a return value < 0. +.ft R +.PP +If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH BACKWARD COMPATIBILITY +.PP +In libpcap versions before 1.5.0, the behavior when +.I cnt +was +.B 0 +was undefined; different platforms and devices behaved differently, +so code that must work with these versions of libpcap should use +.BR \-1 , +not +.BR 0 , +as the value of +.IR cnt . +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_major_version.3pcap b/src/libpcap-1.10.5/pcap_major_version.3pcap new file mode 100644 index 0000000000..393705b4be --- /dev/null +++ b/src/libpcap-1.10.5/pcap_major_version.3pcap @@ -0,0 +1,54 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_MAJOR_VERSION 3PCAP "8 January 2018" +.SH NAME +pcap_major_version, pcap_minor_version \- get the version number of a savefile +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_major_version(pcap_t *p); +int pcap_minor_version(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +If +.I p +refers to a ``savefile'', +.BR pcap_major_version () +returns the major number of the file format of the ``savefile'' and +.BR pcap_minor_version () +returns the minor number of the file format of the ``savefile''. The +version number is stored in the ``savefile''; note that the meaning of +its values depends on the type of ``savefile'' (for example, pcap or +pcapng). +.PP +If +.I p +refers to a live capture, the values returned by +.BR pcap_major_version () +and +.BR pcap_minor_version () +are not meaningful. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_next_ex.3pcap b/src/libpcap-1.10.5/pcap_next_ex.3pcap new file mode 100644 index 0000000000..c6143eed01 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_next_ex.3pcap @@ -0,0 +1,152 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_NEXT_EX 3PCAP "5 March 2022" +.SH NAME +pcap_next_ex, pcap_next \- read the next packet from a pcap_t +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, + const u_char **pkt_data); +const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h); +.ft +.fi +.SH DESCRIPTION +.BR pcap_next_ex () +reads the next packet and returns a success/failure indication. +If the packet was read without problems, the pointer pointed to by the +.I pkt_header +argument is set to point to the +.B pcap_pkthdr +struct for the packet, and the +pointer pointed to by the +.I pkt_data +argument is set to point to the data in the packet. The +.B struct pcap_pkthdr +and the packet data are not to be freed by the caller, and are not +guaranteed to be valid after the next call to +.BR pcap_next_ex (), +.BR pcap_next (), +.BR pcap_loop (3PCAP), +or +.BR pcap_dispatch (3PCAP); +if the code needs them to remain valid, it must make a copy of them. +.PP +.BR pcap_next () +reads the next packet (by calling +.BR pcap_dispatch () +with a +.I cnt +of 1) and returns a +.B u_char +pointer to the data in that packet. The +packet data is not to be freed by the caller, and is not +guaranteed to be valid after the next call to +.BR pcap_next_ex (), +.BR pcap_next (), +.BR pcap_loop (), +or +.BR pcap_dispatch (); +if the code needs it to remain valid, it must make a copy of it. +The +.B pcap_pkthdr +structure pointed to by +.I h +is filled in with the appropriate values for the packet. +.PP +The bytes of data from the packet begin with a link-layer header. The +format of the link-layer header is indicated by the return value of the +.BR pcap_datalink (3PCAP) +routine when handed the +.B pcap_t +value also passed to +.BR pcap_loop () +or +.BR pcap_dispatch (). +.I https://www.tcpdump.org/linktypes.html +lists the values +.BR pcap_datalink () +can return and describes the packet formats that +correspond to those values. The value it returns will be valid for all +packets received unless and until +.BR pcap_set_datalink (3PCAP) +is called; after a successful call to +.BR pcap_set_datalink (), +all subsequent packets will have a link-layer header of the type +specified by the link-layer header type value passed to +.BR pcap_set_datalink (). +.PP +Do +.B NOT +assume that the packets for a given capture or ``savefile`` will have +any given link-layer header type, such as +.B DLT_EN10MB +for Ethernet. For example, the "any" device on Linux will have a +link-layer header type of +.B DLT_LINUX_SLL +or +.B DLT_LINUX_SLL2 +even if all devices on the system at the time the "any" device is opened +have some other data link type, such as +.B DLT_EN10MB +for Ethernet. +.SH RETURN VALUE +.BR pcap_next_ex () +returns +.B 1 +if the packet was read without problems, +.B 0 +if packets are +being read from a live capture and the packet buffer timeout expired, +.B PCAP_ERROR_BREAK +if packets +are being read from a ``savefile'' and there are no more packets to read +from the savefile, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +or +.B PCAP_ERROR +if an error occurred while reading the packet. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.PP +.BR pcap_next () +returns a pointer to the packet data on success, and returns +.B NULL +if an error occurred, or if no packets were read from a live capture +(if, for example, they were discarded because they didn't pass the +packet filter, or if, on platforms that support a packet buffer timeout +that starts before any packets arrive, the timeout expires before any +packets arrive, or if the file descriptor for the capture device is in +non-blocking mode and no packets were available to be read), or if no +more packets are available in a ``savefile.'' Unfortunately, there is no +way to determine whether an error occurred or not. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_offline_filter.3pcap b/src/libpcap-1.10.5/pcap_offline_filter.3pcap new file mode 100644 index 0000000000..94b9a71978 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_offline_filter.3pcap @@ -0,0 +1,54 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OFFLINE_FILTER 3PCAP "7 April 2014" +.SH NAME +pcap_offline_filter \- check whether a filter matches a packet +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_offline_filter(const struct bpf_program *fp, + const struct pcap_pkthdr *h, const u_char *pkt); +.ft +.fi +.SH DESCRIPTION +.BR pcap_offline_filter () +checks whether a filter matches a packet. +.I fp +is a pointer to a +.I bpf_program +struct, usually the result of a call to +.BR pcap_compile (3PCAP). +.I h +points to the +.I pcap_pkthdr +structure for the packet, and +.I pkt +points to the data in the packet. +.SH RETURN VALUE +.BR pcap_offline_filter () +returns the return value of the filter program. This will be zero if +the packet doesn't match the filter and non-zero if the packet matches +the filter. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_open_dead.3pcap.in b/src/libpcap-1.10.5/pcap_open_dead.3pcap.in new file mode 100644 index 0000000000..ced7d6cf1c --- /dev/null +++ b/src/libpcap-1.10.5/pcap_open_dead.3pcap.in @@ -0,0 +1,85 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_DEAD 3PCAP "3 January 2014" +.SH NAME +pcap_open_dead, pcap_open_dead_with_tstamp_precision \- open a fake +pcap_t for compiling filters or opening a capture for output +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +pcap_t *pcap_open_dead(int linktype, int snaplen); +pcap_t *pcap_open_dead_with_tstamp_precision(int linktype, int snaplen, + u_int precision); +.ft +.fi +.SH DESCRIPTION +.PP +.BR pcap_open_dead () +and +.BR pcap_open_dead_with_tstamp_precision () +are used for creating a +.B pcap_t +structure to use when calling the other functions in libpcap. It is +typically used when just using libpcap for compiling BPF code; it can +also be used if using +.BR pcap_dump_open (3PCAP), +.BR pcap_dump (3PCAP), +and +.BR pcap_dump_close (3PCAP) +to write a savefile if there is no +.B pcap_t +that supplies the packets to be written. +.PP +.I linktype +specifies the link-layer type for the +.BR pcap_t . +.PP +.I snaplen +specifies the snapshot length for the +.BR pcap_t . +.PP +When +.BR pcap_open_dead_with_tstamp_precision (), +is used to create a +.B pcap_t +for use with +.BR pcap_dump_open (), +.I precision +specifies the time stamp precision for packets; +.B PCAP_TSTAMP_PRECISION_MICRO +should be specified if the packets to be written have time stamps in +seconds and microseconds, and +.B PCAP_TSTAMP_PRECISION_NANO +should be specified if the packets to be written have time stamps in +seconds and nanoseconds. Its value does not affect +.BR pcap_compile (3PCAP). +.SH BACKWARD COMPATIBILITY +The +.BR pcap_open_dead_with_tstamp_precision () +function became available in libpcap release 1.5.1. In previous +releases, there was no mechanism to open a savefile for writing with +time stamps given in seconds and nanoseconds. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR \%pcap-linktype (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_open_live.3pcap b/src/libpcap-1.10.5/pcap_open_live.3pcap new file mode 100644 index 0000000000..113085180f --- /dev/null +++ b/src/libpcap-1.10.5/pcap_open_live.3pcap @@ -0,0 +1,100 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_LIVE 3PCAP "4 March 2024" +.SH NAME +pcap_open_live \- open a device for capturing +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_open_live(const char *device, int snaplen, + int promisc, int to_ms, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_open_live () +is used to obtain a packet capture handle to look +at packets on the network. +.I device +is a string that specifies the network device to open; on all supported Linux +systems, as well as on recent versions of macOS and Solaris, a +.I device +argument of "any" or +.B NULL +can be used to capture packets from all network interfaces. The latter should +not be confused with all available capture devices as seen by +.BR pcap_findalldevs (3PCAP), +which may also include D-Bus, USB etc. +.PP +.I snaplen +specifies the snapshot length to be set on the handle. If the packet +data should not be truncated at the end, a value of 262144 should be +sufficient for most devices, but D-Bus devices require a value of 128MB +(128*1024*1024). +.PP +.I promisc +specifies whether the interface is to be put into promiscuous mode. +If +.I promisc +is non-zero, promiscuous mode will be set, otherwise it will not be set. +.PP +.I to_ms +specifies the packet buffer timeout, as a non-negative value, in +milliseconds. (See +.BR pcap (3PCAP) +for an explanation of the packet buffer timeout.) +.PP +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH RETURN VALUE +.BR pcap_open_live () +returns a +.B pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.I errbuf +may also be set to warning text when +.BR pcap_open_live () +succeeds; to detect this case the caller should store a zero-length string in +.I errbuf +before calling +.BR pcap_open_live () +and display the warning to the user if +.I errbuf +is no longer a zero-length string. +.SH SEE ALSO +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_open_offline.3pcap.in b/src/libpcap-1.10.5/pcap_open_offline.3pcap.in new file mode 100644 index 0000000000..eca2266029 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_open_offline.3pcap.in @@ -0,0 +1,118 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_OPEN_OFFLINE 3PCAP "30 November 2023" +.SH NAME +pcap_open_offline, pcap_open_offline_with_tstamp_precision, +pcap_fopen_offline, pcap_fopen_offline_with_tstamp_precision \- open a saved capture file for reading +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +pcap_t *pcap_open_offline(const char *fname, char *errbuf); +pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, + u_int precision, char *errbuf); +pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf); +pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, + u_int precision, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_open_offline () +and +.BR pcap_open_offline_with_tstamp_precision () +are called to open a ``savefile'' for reading. +.PP +.I fname +specifies the name of the file to open. The file can have the pcap file +format as described in +.BR \%pcap-savefile (@MAN_FILE_FORMATS@), +which is the file format used by, among other programs, +.BR tcpdump (1) +and +.BR tcpslice (1), +or can have the pcapng file format, although not all pcapng files can +be read. +The name "-" is a synonym for +.BR stdin . +.PP +.BR pcap_open_offline_with_tstamp_precision () +takes an additional +.I precision +argument specifying the time stamp precision desired; +if +.B PCAP_TSTAMP_PRECISION_MICRO +is specified, packet time stamps will be supplied in seconds and +microseconds, +and if +.B PCAP_TSTAMP_PRECISION_NANO +is specified, packet time stamps will be supplied in seconds and +nanoseconds. If the time stamps in the file do not have the same +precision as the requested precision, they will be scaled up or down as +necessary before being supplied. +.PP +Alternatively, you may call +.BR pcap_fopen_offline () +or +.BR pcap_fopen_offline_with_tstamp_precision () +to read dumped data from an existing open stream +.IR fp . +.BR pcap_fopen_offline_with_tstamp_precision () +takes an additional +.I precision +argument as described above. +Note that on Windows, that stream should be opened in binary mode. +.PP +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.SH RETURN VALUE +.BR pcap_open_offline (), +.BR pcap_open_offline_with_tstamp_precision (), +.BR pcap_fopen_offline (), +and +.BR pcap_fopen_offline_with_tstamp_precision () +return a +.B pcap_t * +on success and +.B NULL +on failure. +If +.B NULL +is returned, +.I errbuf +is filled in with an appropriate error message. +.SH BACKWARD COMPATIBILITY +.BR pcap_open_offline_with_tstamp_precision () +and +.BR pcap_fopen_offline_with_tstamp_precision () +became available in libpcap release 1.5.1. In previous releases, time +stamps from a savefile are always given in seconds and microseconds. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR \%pcap-savefile (@MAN_FILE_FORMATS@) diff --git a/src/libpcap-1.10.5/pcap_set_buffer_size.3pcap b/src/libpcap-1.10.5/pcap_set_buffer_size.3pcap new file mode 100644 index 0000000000..49492c068e --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_buffer_size.3pcap @@ -0,0 +1,49 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_BUFFER_SIZE 3PCAP "3 January 2014" +.SH NAME +pcap_set_buffer_size \- set the buffer size for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_buffer_size(pcap_t *p, int buffer_size); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_buffer_size () +sets the buffer size that will be used on a capture handle when +the handle is activated to +.IR buffer_size , +which is in units of bytes. +.SH RETURN VALUE +.BR pcap_set_buffer_size () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_datalink.3pcap b/src/libpcap-1.10.5/pcap_set_datalink.3pcap new file mode 100644 index 0000000000..fd90791316 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_datalink.3pcap @@ -0,0 +1,58 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_DATALINK 3PCAP "5 March 2022" +.SH NAME +pcap_set_datalink \- set the link-layer header type to be used by a +capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_datalink(pcap_t *p, int dlt); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_datalink () +is used to set the current link-layer header type of the pcap descriptor +to the type specified by +.IR dlt . +.SH RETURN VALUE +.BR pcap_set_datalink () +returns +.B 0 +on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, or +.B PCAP_ERROR +on other errors. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_datalink_name_to_val (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_immediate_mode.3pcap.in b/src/libpcap-1.10.5/pcap_set_immediate_mode.3pcap.in new file mode 100644 index 0000000000..95c9cffbde --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_immediate_mode.3pcap.in @@ -0,0 +1,99 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_IMMEDIATE_MODE 3PCAP "23 August 2018" +.SH NAME +pcap_set_immediate_mode \- set immediate mode for a not-yet-activated capture +handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_immediate_mode(pcap_t *p, int immediate_mode); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_immediate_mode () +sets whether immediate mode should be set on a capture handle when +the handle is activated. In immediate mode, packets are always +delivered as soon as they arrive, with no buffering. +If +.I immediate_mode +is non-zero, immediate mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.BR pcap_set_immediate_mode () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.5.0. In previous +releases, if immediate delivery of packets is required: +.IP +on FreeBSD, NetBSD, OpenBSD, DragonFly BSD, macOS, and Solaris 11, +immediate mode must be turned on with a +.B BIOCIMMEDIATE +.BR ioctl (2), +as documented in +.BR bpf (@MAN_DEVICES@), +on the descriptor returned by +.BR pcap_fileno (3PCAP), +after +.BR pcap_activate (3PCAP) +is called; +.IP +on Solaris 10 and earlier versions of Solaris, immediate mode must be +turned on by using a read timeout of 0 when opening the device (this +will not provide immediate delivery of packets on other platforms, so +don't assume it's sufficient); +.IP +on Digital UNIX/Tru64 UNIX, immediate mode must be turned on by doing a +.B BIOCMBIC +.BR ioctl (), +as documented in +.BR packetfilter (7), +to clear the +.B ENBATCH +flag on the descriptor returned by +.BR pcap_fileno (3PCAP), +after +.BR pcap_activate (3PCAP) +is called; +.IP +on Windows, immediate mode must be turned on by calling +.BR pcap_setmintocopy () +with a size of 0. +.PP +On Linux, with previous releases of libpcap, capture devices are always +in immediate mode; however, in 1.5.0 and later, they are, by default, +.B not +in immediate mode, so if +.BR pcap_set_immediate_mode () +is available, it should be used. +.PP +On other platforms, capture devices are always in immediate mode. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_promisc.3pcap b/src/libpcap-1.10.5/pcap_set_promisc.3pcap new file mode 100644 index 0000000000..cfc6cddafe --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_promisc.3pcap @@ -0,0 +1,50 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_PROMISC 3PCAP "3 January 2014" +.SH NAME +pcap_set_promisc \- set promiscuous mode for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_promisc(pcap_t *p, int promisc); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_promisc () +sets whether promiscuous mode should be set on a capture handle when +the handle is activated. +If +.I promisc +is non-zero, promiscuous mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.BR pcap_set_promisc () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_protocol_linux.3pcap b/src/libpcap-1.10.5/pcap_set_protocol_linux.3pcap new file mode 100644 index 0000000000..a891d7492a --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_protocol_linux.3pcap @@ -0,0 +1,72 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_PROTOCOL_LINUX 3PCAP "22 August 2018" +.SH NAME +pcap_set_protocol_linux \- set capture protocol for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_protocol_linux(pcap_t *p, int protocol); +.ft +.fi +.SH DESCRIPTION +On network interface devices on Linux, +.BR pcap_set_protocol_linux () +sets the protocol to be used in the +.BR socket (2) +call to create a capture socket when the handle is activated. The +argument is a link-layer protocol value, such as the values in the +.B +header file, specified in host byte order. +If +.I protocol +is non-zero, packets of that protocol will be captured when the +handle is activated, otherwise, all packets will be captured. This +function is only provided on Linux, and, if it is used on any device +other than a network interface, it will have no effect. +.LP +It should not be used in portable code; instead, a filter should be +specified with +.BR pcap_setfilter (3PCAP). +.LP +If a given network interface provides a standard link-layer header, with +a standard packet type, but provides some packet types with a different +socket-layer protocol type from the one in the link-layer header, that +packet type cannot be filtered with a filter specified with +.BR pcap_setfilter () +but can be filtered by specifying the socket-layer protocol type using +.BR pcap_set_protocol_linux (). +.SH RETURN VALUE +.BR pcap_set_protocol_linux () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.9.0. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_rfmon.3pcap b/src/libpcap-1.10.5/pcap_set_rfmon.3pcap new file mode 100644 index 0000000000..2b104c2557 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_rfmon.3pcap @@ -0,0 +1,51 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_RFMON 3PCAP "3 January 2014" +.SH NAME +pcap_set_rfmon \- set monitor mode for a not-yet-activated capture +handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_rfmon(pcap_t *p, int rfmon); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_rfmon () +sets whether monitor mode should be set on a capture handle when +the handle is activated. +If +.I rfmon +is non-zero, monitor mode will be set, otherwise it will not be set. +.SH RETURN VALUE +.BR pcap_set_rfmon () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP), +.BR pcap_can_set_rfmon (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_snaplen.3pcap b/src/libpcap-1.10.5/pcap_set_snaplen.3pcap new file mode 100644 index 0000000000..e3acff158f --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_snaplen.3pcap @@ -0,0 +1,48 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_SNAPLEN 3PCAP "3 January 2014" +.SH NAME +pcap_set_snaplen \- set the snapshot length for a not-yet-activated +capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_snaplen(pcap_t *p, int snaplen); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_snaplen () +sets the snapshot length to be used on a capture handle when the handle +is activated to +.IR snaplen . +.SH RETURN VALUE +.BR pcap_set_snaplen () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_timeout.3pcap b/src/libpcap-1.10.5/pcap_set_timeout.3pcap new file mode 100644 index 0000000000..d909b2c444 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_timeout.3pcap @@ -0,0 +1,56 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_TIMEOUT 3PCAP "6 December 2017" +.SH NAME +pcap_set_timeout \- set the packet buffer timeout for a +not-yet-activated capture handle +.SH SYNOPSIS +.nf +.ft B +#include +.LP +.ft B +int pcap_set_timeout(pcap_t *p, int to_ms); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_timeout () +sets the packet buffer timeout that will be used on a capture handle +when the handle is activated to +.IR to_ms , +which is in units of milliseconds. (See +.BR pcap (3PCAP) +for an explanation of the packet buffer timeout.) +.LP +The behavior, if the timeout isn't specified, is undefined, as is the +behavior if the timeout is set to zero or to a negative value. We +recommend always setting the timeout to a non-zero value unless +immediate mode is set, in which case the timeout has no effect. +.SH RETURN VALUE +.BR pcap_set_timeout () +returns +.B 0 +on success or +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH SEE ALSO +.BR pcap_create (3PCAP), +.BR pcap_activate (3PCAP), +.BR \%pcap_set_immediate_mode (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_set_tstamp_precision.3pcap.in b/src/libpcap-1.10.5/pcap_set_tstamp_precision.3pcap.in new file mode 100644 index 0000000000..ab27ce595b --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_tstamp_precision.3pcap.in @@ -0,0 +1,69 @@ +.\"Copyright (c) 2013, Michal Sekletar +.\"All rights reserved. +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. The names of the authors may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\"THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\"IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +.TH PCAP_SET_TSTAMP_PRECISION 3PCAP "23 August 2018" +.SH NAME +pcap_set_tstamp_precision \- set the time stamp precision returned in +captures +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_tstamp_precision () +sets the precision of the time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_precision . +It must be called on a pcap descriptor created by +.BR pcap_create (3PCAP) +that has not yet been activated by +.BR pcap_activate (3PCAP). +Two time stamp precisions are supported, microseconds and nanoseconds. One can +use options +.B PCAP_TSTAMP_PRECISION_MICRO +and +.B PCAP_TSTAMP_PRECISION_NANO +to request desired precision. By default, time stamps are in microseconds. +.SH RETURN VALUE +.BR pcap_set_tstamp_precision () +returns +.B 0 +on success if the specified time stamp precision is expected to be +supported by the capture device, +.B PCAP_ERROR_TSTAMP_PRECISION_NOTSUP +if the capture device does not support the requested time stamp +precision, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated. +.SH BACKWARD COMPATIBILITY +This function became available in libpcap release 1.5.1. In previous +releases, time stamps from a capture device or savefile are always given +in seconds and microseconds. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_get_tstamp_precision (3PCAP), +.BR \%pcap-tstamp (@MAN_MISC_INFO@) diff --git a/src/libpcap-1.10.5/pcap_set_tstamp_type.3pcap.in b/src/libpcap-1.10.5/pcap_set_tstamp_type.3pcap.in new file mode 100644 index 0000000000..cd2dc71ced --- /dev/null +++ b/src/libpcap-1.10.5/pcap_set_tstamp_type.3pcap.in @@ -0,0 +1,72 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SET_TSTAMP_TYPE 3PCAP "8 September 2019" +.SH NAME +pcap_set_tstamp_type \- set the time stamp type to be used by a +capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_set_tstamp_type(pcap_t *p, int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.BR pcap_set_tstamp_type () +sets the type of time stamp desired for packets captured on the pcap +descriptor to the type specified by +.IR tstamp_type . +It must be called on a pcap descriptor created by +.BR pcap_create (3PCAP) +that has not yet been activated by +.BR pcap_activate (3PCAP). +.BR pcap_list_tstamp_types (3PCAP) +will give a list of the time stamp types supported by a given capture +device. +See +.BR \%pcap-tstamp (@MAN_MISC_INFO@) +for a list of all the time stamp types. +.SH RETURN VALUE +.BR pcap_set_tstamp_type () +returns +.B 0 +on success if the specified time stamp type is expected to be +supported by the capture device, +.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP +if the specified time stamp type is not supported by the +capture device, +.B PCAP_ERROR_ACTIVATED +if called on a capture handle that has been activated, and +.B PCAP_ERROR_CANTSET_TSTAMP_TYPE +if the capture device doesn't support setting the time stamp type (only +older versions of libpcap will return that; newer versions will always +allow the time stamp type to be set to the default type). +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.2.1. In previous +releases, the time stamp type cannot be set; only the default time stamp +type offered by a capture source is available. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_tstamp_type_name_to_val (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_setdirection.3pcap b/src/libpcap-1.10.5/pcap_setdirection.3pcap new file mode 100644 index 0000000000..04278e8484 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_setdirection.3pcap @@ -0,0 +1,76 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETDIRECTION 3PCAP "5 March 2022" +.SH NAME +pcap_setdirection \- set the direction for which packets will be captured +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_setdirection(pcap_t *p, pcap_direction_t d); +.ft +.fi +.SH DESCRIPTION +.BR pcap_setdirection () +is used to specify a direction that packets will be captured. +.I d +is one of the constants +.BR PCAP_D_IN , +.B PCAP_D_OUT +or +.BR PCAP_D_INOUT . +.B PCAP_D_IN +will only capture packets received by the device, +.B PCAP_D_OUT +will only capture packets sent by the device and +.B PCAP_D_INOUT +will capture packets received by or sent by the device. +.B PCAP_D_INOUT +is the default setting if this function is not called. +.PP +.BR pcap_setdirection () +isn't necessarily fully supported on all platforms; some platforms might +return an error for all values, and some other platforms might not +support +.BR PCAP_D_OUT . +.PP +This operation is not supported if a ``savefile'' is being read. +.SH RETURN VALUE +.BR pcap_setdirection () +returns +.B 0 +on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, or +.B PCAP_ERROR +on other errors. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_setfilter.3pcap b/src/libpcap-1.10.5/pcap_setfilter.3pcap new file mode 100644 index 0000000000..e063ae0ea2 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_setfilter.3pcap @@ -0,0 +1,59 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETFILTER 3PCAP "5 March 2022" +.SH NAME +pcap_setfilter \- set the filter +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_setfilter(pcap_t *p, struct bpf_program *fp); +.ft +.fi +.SH DESCRIPTION +.BR pcap_setfilter () +is used to specify a filter program. +.I fp +is a pointer to a +.I bpf_program +struct, usually the result of a call to +.BR \%pcap_compile (3PCAP). +.SH RETURN VALUE +.BR pcap_setfilter () +returns +.B 0 +on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, or +.B PCAP_ERROR +on other errors. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_setnonblock.3pcap b/src/libpcap-1.10.5/pcap_setnonblock.3pcap new file mode 100644 index 0000000000..672281914f --- /dev/null +++ b/src/libpcap-1.10.5/pcap_setnonblock.3pcap @@ -0,0 +1,108 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SETNONBLOCK 3PCAP "30 November 2023" +.SH NAME +pcap_setnonblock, pcap_getnonblock \- set or get the state of +non-blocking mode on a capture device +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.nf +.ft B +char errbuf[PCAP_ERRBUF_SIZE]; +.ft +.LP +.ft B +int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf); +int pcap_getnonblock(pcap_t *p, char *errbuf); +.ft +.fi +.SH DESCRIPTION +.BR pcap_setnonblock () +puts a capture handle into ``non-blocking'' mode, or takes it out +of ``non-blocking'' mode, depending on whether the +.I nonblock +argument is non-zero or zero. It has no effect on ``savefiles''. +.I errbuf +is a buffer large enough to hold at least +.B PCAP_ERRBUF_SIZE +chars. +.PP +In +``non-blocking'' mode, an attempt to read from the capture descriptor +with +.BR pcap_dispatch (3PCAP) +and +.BR pcap_next_ex (3PCAP) +will, if no packets are currently available to be read, return +.B 0 +immediately rather than blocking waiting for packets to arrive. +.PP +.BR pcap_loop (3PCAP) +will loop forever, consuming CPU time when no packets are currently +available; +.BR pcap_dispatch () +should be used instead. +.BR pcap_next (3PCAP) +will return +.B NULL +if there are no packets currently available to read; +this is indistinguishable from an error, so +.BR pcap_next_ex () +should be used instead. +.PP +When first activated with +.BR pcap_activate (3PCAP) +or opened with +.BR pcap_open_live (3PCAP), +a capture handle is not in ``non-blocking mode''; a call to +.BR pcap_setnonblock () +is required in order to put it into ``non-blocking'' mode. +.SH RETURN VALUE +.BR pcap_setnonblock() +return 0 on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +and +.B PCAP_ERROR +for other errors. +.BR pcap_getnonblock () +returns the current ``non-blocking'' state of the capture descriptor on +success; it always returns +.B 0 +on ``savefiles''. +It returns +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +and +.B PCAP_ERROR +for other errors. +If +.B PCAP_ERROR +is returned, +.I errbuf +is filled in with an appropriate error message. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_next_ex (3PCAP), +.BR pcap_geterr (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_snapshot.3pcap b/src/libpcap-1.10.5/pcap_snapshot.3pcap new file mode 100644 index 0000000000..25f6e03678 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_snapshot.3pcap @@ -0,0 +1,52 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_SNAPSHOT 3PCAP "7 April 2014" +.SH NAME +pcap_snapshot \- get the snapshot length +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_snapshot(pcap_t *p); +.ft +.fi +.SH DESCRIPTION +.BR pcap_snapshot () +returns the snapshot length specified when +.BR pcap_set_snaplen (3PCAP) +or +.BR pcap_open_live (3PCAP) +was called, for a live capture, or the snapshot length from the capture +file, for a ``savefile''. +.PP +It must not be called on a pcap descriptor created by +.BR \%pcap_create (3PCAP) +that has not yet been activated by +.BR \%pcap_activate (3PCAP). +.SH RETURN VALUE +.BR pcap_snapshot () +returns the snapshot length on success and +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_stats.3pcap b/src/libpcap-1.10.5/pcap_stats.3pcap new file mode 100644 index 0000000000..98be9bd7d3 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_stats.3pcap @@ -0,0 +1,105 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STATS 3PCAP "5 March 2022" +.SH NAME +pcap_stats \- get capture statistics +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_stats(pcap_t *p, struct pcap_stat *ps); +.ft +.fi +.SH DESCRIPTION +.BR pcap_stats () +fills in the +.B struct pcap_stat +pointed to by its second argument. The values represent +packet statistics from the start of the run to the time of the call. +.PP +.BR pcap_stats () +is supported only on live captures, not on ``savefiles''; no statistics +are stored in ``savefiles'', so no statistics are available when reading +from a ``savefile''. +.PP +A +.B struct pcap_stat +has the following members: +.RS +.TP +.B ps_recv +number of packets received; +.TP +.B ps_drop +number of packets dropped because there was no room in the operating +system's buffer when they arrived, because packets weren't being read +fast enough; +.TP +.B ps_ifdrop +number of packets dropped by the network interface or its driver. +.RE +.PP +The statistics do not behave the same way on all platforms. +.B ps_recv +might count packets whether they passed any filter set with +.BR pcap_setfilter (3PCAP) +or not, or it might count only packets that pass the filter. +It also might, or might not, count packets dropped because there was no +room in the operating system's buffer when they arrived. +.B ps_drop +is not available on all platforms; it is zero on platforms where it's +not available. If packet filtering is done in libpcap, rather than in +the operating system, it would count packets that don't pass the filter. +Both +.B ps_recv +and +.B ps_drop +might, or might not, count packets not yet read from the operating +system and thus not yet seen by the application. +.B ps_ifdrop +might, or might not, be implemented; if it's zero, that might mean that +no packets were dropped by the interface, or it might mean that the +statistic is unavailable, so it should not be treated as an indication +that the interface did not drop any packets. +.SH RETURN VALUE +.BR pcap_stats () +returns +.B 0 +on success, +.B PCAP_ERROR_NOT_ACTIVATED +if called on a capture handle that has been created but not activated, +or +.B PCAP_ERROR +if there is another error or if +.I p +doesn't support packet statistics. If +.B PCAP_ERROR +is returned, +.BR pcap_geterr (3PCAP) +or +.BR pcap_perror (3PCAP) +may be called with +.I p +as an argument to fetch or display the error text. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_statustostr.3pcap b/src/libpcap-1.10.5/pcap_statustostr.3pcap new file mode 100644 index 0000000000..c679e362e9 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_statustostr.3pcap @@ -0,0 +1,41 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STATUSTOSTR 3PCAP "3 January 2014" +.SH NAME +pcap_statustostr \- convert a PCAP_ERROR_ or PCAP_WARNING_ value to a string +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_statustostr(int error); +.ft +.fi +.SH DESCRIPTION +.BR pcap_statustostr () +converts a +.B PCAP_ERROR_ +or +.B PCAP_WARNING_ +value returned by a libpcap routine to an error string. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_strerror.3pcap b/src/libpcap-1.10.5/pcap_strerror.3pcap new file mode 100644 index 0000000000..2add6cc16f --- /dev/null +++ b/src/libpcap-1.10.5/pcap_strerror.3pcap @@ -0,0 +1,44 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_STRERROR 3PCAP "26 August 2024" +.SH NAME +pcap_strerror \- convert an errno value to a string +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_strerror(int error); +.ft +.fi +.SH DESCRIPTION +This function returns an error message string corresponding to +.IR error . +It uses either +.BR strerror (3) +or its thread-safe variant if one is available, which currently is the case in +every supported OS. +.SH BACKWARD COMPATIBILITY +This function was not thread-safe in libpcap before 1.8.1 on Windows and +in libpcap before 1.10.5 on all other OSes. +.SH SEE ALSO +.BR pcap (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_tstamp_type_name_to_val.3pcap b/src/libpcap-1.10.5/pcap_tstamp_type_name_to_val.3pcap new file mode 100644 index 0000000000..f60516e7e5 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_tstamp_type_name_to_val.3pcap @@ -0,0 +1,49 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_NAME_TO_VAL 3PCAP "22 August 2018" +.SH NAME +pcap_tstamp_type_name_to_val \- get the time stamp type value +corresponding to a time stamp type name +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +int pcap_tstamp_type_name_to_val(const char *name); +.ft +.fi +.SH DESCRIPTION +.BR pcap_tstamp_type_name_to_val () +translates a time stamp type name to the corresponding time stamp type +value. The translation is case-insensitive. +.SH RETURN VALUE +.BR pcap_tstamp_type_name_to_val () +returns time stamp type value on success and +.B PCAP_ERROR +on failure. +.SH BACKWARD COMPATIBILITY +.PP +This function became available in libpcap release 1.2.1. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_tstamp_type_val_to_name (3PCAP) diff --git a/src/libpcap-1.10.5/pcap_tstamp_type_val_to_name.3pcap b/src/libpcap-1.10.5/pcap_tstamp_type_val_to_name.3pcap new file mode 100644 index 0000000000..5958e81025 --- /dev/null +++ b/src/libpcap-1.10.5/pcap_tstamp_type_val_to_name.3pcap @@ -0,0 +1,53 @@ +.\" +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH PCAP_TSTAMP_TYPE_VAL_TO_NAME 3PCAP "22 August 2018" +.SH NAME +pcap_tstamp_type_val_to_name, pcap_tstamp_type_val_to_description \- get +a name or description for a time stamp type value +.SH SYNOPSIS +.nf +.ft B +#include +.ft +.LP +.ft B +const char *pcap_tstamp_type_val_to_name(int tstamp_type); +const char *pcap_tstamp_type_val_to_description(int tstamp_type); +.ft +.fi +.SH DESCRIPTION +.BR pcap_tstamp_type_val_to_name () +translates a time stamp type value to the corresponding time stamp type +name. +.B NULL +is returned on failure. +.PP +.BR pcap_tstamp_type_val_to_description () +translates a time stamp type value to a short description of that time +stamp type. +.B NULL +is returned on failure. +.SH BACKWARD COMPATIBILITY +.PP +These functions became available in libpcap release 1.2.1. +.SH SEE ALSO +.BR pcap (3PCAP), +.BR pcap_tstamp_type_name_to_val (3PCAP) diff --git a/src/libpcap-1.10.5/pflog.h b/src/libpcap-1.10.5/pflog.h new file mode 100644 index 0000000000..b49d04fc8a --- /dev/null +++ b/src/libpcap-1.10.5/pflog.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * pflog headers, at least as they exist now. + */ +#define PFLOG_IFNAMSIZ 16 +#define PFLOG_RULESET_NAME_SIZE 16 + +/* + * Direction values. + */ +#define PF_INOUT 0 +#define PF_IN 1 +#define PF_OUT 2 +#if defined(__OpenBSD__) +#define PF_FWD 3 +#endif + +/* + * Reason values. + */ +#define PFRES_MATCH 0 +#define PFRES_BADOFF 1 +#define PFRES_FRAG 2 +#define PFRES_SHORT 3 +#define PFRES_NORM 4 +#define PFRES_MEMORY 5 +#define PFRES_TS 6 +#define PFRES_CONGEST 7 +#define PFRES_IPOPTIONS 8 +#define PFRES_PROTCKSUM 9 +#define PFRES_BADSTATE 10 +#define PFRES_STATEINS 11 +#define PFRES_MAXSTATES 12 +#define PFRES_SRCLIMIT 13 +#define PFRES_SYNPROXY 14 +#if defined(__FreeBSD__) +#define PFRES_MAPFAILED 15 +#elif defined(__NetBSD__) +#define PFRES_STATELOCKED 15 +#elif defined(__OpenBSD__) +#define PFRES_TRANSLATE 15 +#define PFRES_NOROUTE 16 +#elif defined(__APPLE__) +#define PFRES_DUMMYNET 15 +#endif + +/* + * Action values. + */ +#define PF_PASS 0 +#define PF_DROP 1 +#define PF_SCRUB 2 +#define PF_NOSCRUB 3 +#define PF_NAT 4 +#define PF_NONAT 5 +#define PF_BINAT 6 +#define PF_NOBINAT 7 +#define PF_RDR 8 +#define PF_NORDR 9 +#define PF_SYNPROXY_DROP 10 +#if defined(__FreeBSD__) +#define PF_DEFER 11 +#elif defined(__OpenBSD__) +#define PF_DEFER 11 +#define PF_MATCH 12 +#define PF_DIVERT 13 +#define PF_RT 14 +#define PF_AFRT 15 +#elif defined(__APPLE__) +#define PF_DUMMYNET 11 +#define PF_NODUMMYNET 12 +#define PF_NAT64 13 +#define PF_NONAT64 14 +#endif + +struct pf_addr { + union { + struct in_addr v4; + struct in6_addr v6; + uint8_t addr8[16]; + uint16_t addr16[8]; + uint32_t addr32[4]; + } pfa; /* 128-bit address */ +#define v4 pfa.v4 +#define v6 pfa.v6 +#define addr8 pfa.addr8 +#define addr16 pfa.addr16 +#define addr32 pfa.addr32 +}; + +struct pfloghdr { + uint8_t length; + uint8_t af; + uint8_t action; + uint8_t reason; + char ifname[PFLOG_IFNAMSIZ]; + char ruleset[PFLOG_RULESET_NAME_SIZE]; + uint32_t rulenr; + uint32_t subrulenr; + uint32_t uid; + int32_t pid; + uint32_t rule_uid; + int32_t rule_pid; + uint8_t dir; +#if defined(__OpenBSD__) + uint8_t rewritten; + uint8_t naf; + uint8_t pad[1]; +#else + uint8_t pad[3]; +#endif +#if defined(__FreeBSD__) + uint32_t ridentifier; + uint8_t reserve; + uint8_t pad2[3]; +#elif defined(__OpenBSD__) + struct pf_addr saddr; + struct pf_addr daddr; + uint16_t sport; + uint16_t dport; +#endif +}; + + + diff --git a/src/libpcap-1.10.5/portability.h b/src/libpcap-1.10.5/portability.h new file mode 100644 index 0000000000..5a2496c932 --- /dev/null +++ b/src/libpcap-1.10.5/portability.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef portability_h +#define portability_h + +/* + * Helpers for portability between Windows and UN*X and between different + * flavors of UN*X. + */ +#include /* we declare varargs functions on some platforms */ + +#include "pcap/funcattrs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_STRLCAT + #define pcapint_strlcat strlcat +#else + #if defined(_MSC_VER) || defined(__MINGW32__) + /* + * strncat_s() is supported at least back to Visual + * Studio 2005; we require Visual Studio 2015 or later. + */ + #define pcapint_strlcat(x, y, z) \ + strncat_s((x), (z), (y), _TRUNCATE) + #else + /* + * Define it ourselves. + */ + extern size_t pcapint_strlcat(char * restrict dst, const char * restrict src, size_t dstsize); + #endif +#endif + +#ifdef HAVE_STRLCPY + #define pcapint_strlcpy strlcpy +#else + #if defined(_MSC_VER) || defined(__MINGW32__) + /* + * strncpy_s() is supported at least back to Visual + * Studio 2005; we require Visual Studio 2015 or later. + */ + #define pcapint_strlcpy(x, y, z) \ + strncpy_s((x), (z), (y), _TRUNCATE) + #else + /* + * Define it ourselves. + */ + extern size_t pcapint_strlcpy(char * restrict dst, const char * restrict src, size_t dstsize); + #endif +#endif + +#ifdef _MSC_VER + /* + * If has been included, and _DEBUG is defined, and + * __STDC__ is zero, will define strdup() to call + * _strdup_dbg(). So if it's already defined, don't redefine + * it. + */ + #ifndef strdup + #define strdup _strdup + #endif +#endif + +/* + * We want asprintf(), for some cases where we use it to construct + * dynamically-allocated variable-length strings; it's present on + * some, but not all, platforms. + */ +#ifdef HAVE_ASPRINTF +#define pcapint_asprintf asprintf +#else +extern int pcapint_asprintf(char **, PCAP_FORMAT_STRING(const char *), ...) + PCAP_PRINTFLIKE(2, 3); +#endif + +#ifdef HAVE_VASPRINTF +#define pcapint_vasprintf vasprintf +#else +extern int pcapint_vasprintf(char **, PCAP_FORMAT_STRING(const char *), va_list ap) + PCAP_PRINTFLIKE(2, 0); +#endif + +/* For Solaris before 11. */ +#ifndef timeradd +#define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif /* timeradd */ +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* timersub */ + +#ifdef HAVE_STRTOK_R + #define pcapint_strtok_r strtok_r +#else + #ifdef _WIN32 + /* + * Microsoft gives it a different name. + */ + #define pcapint_strtok_r strtok_s + #else + /* + * Define it ourselves. + */ + extern char *pcapint_strtok_r(char *, const char *, char **); + #endif +#endif /* HAVE_STRTOK_R */ + +#ifdef _WIN32 + #if !defined(__cplusplus) + #define inline __inline + #endif +#endif /* _WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpcap-1.10.5/ppp.h b/src/libpcap-1.10.5/ppp.h new file mode 100644 index 0000000000..d8fcc6febd --- /dev/null +++ b/src/libpcap-1.10.5/ppp.h @@ -0,0 +1,57 @@ +/* + * Point to Point Protocol (PPP) RFC1331 + * + * Copyright 1989 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ +#define PPP_ADDRESS 0xff /* The address byte value */ +#define PPP_CONTROL 0x03 /* The control byte value */ + +#define PPP_PPPD_IN 0x00 /* non-standard for DLT_PPP_PPPD */ +#define PPP_PPPD_OUT 0x01 /* non-standard for DLT_PPP_PPPD */ + +/* Protocol numbers */ +#define PPP_IP 0x0021 /* Raw IP */ +#define PPP_OSI 0x0023 /* OSI Network Layer */ +#define PPP_NS 0x0025 /* Xerox NS IDP */ +#define PPP_DECNET 0x0027 /* DECnet Phase IV */ +#define PPP_APPLE 0x0029 /* Appletalk */ +#define PPP_IPX 0x002b /* Novell IPX */ +#define PPP_VJC 0x002d /* Van Jacobson Compressed TCP/IP */ +#define PPP_VJNC 0x002f /* Van Jacobson Uncompressed TCP/IP */ +#define PPP_BRPDU 0x0031 /* Bridging PDU */ +#define PPP_STII 0x0033 /* Stream Protocol (ST-II) */ +#define PPP_VINES 0x0035 /* Banyan Vines */ +#define PPP_IPV6 0x0057 /* Internet Protocol version 6 */ + +#define PPP_HELLO 0x0201 /* 802.1d Hello Packets */ +#define PPP_LUXCOM 0x0231 /* Luxcom */ +#define PPP_SNS 0x0233 /* Sigma Network Systems */ +#define PPP_MPLS_UCAST 0x0281 /* rfc 3032 */ +#define PPP_MPLS_MCAST 0x0283 /* rfc 3022 */ + +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_OSICP 0x8023 /* OSI Network Layer Control Protocol */ +#define PPP_NSCP 0x8025 /* Xerox NS IDP Control Protocol */ +#define PPP_DECNETCP 0x8027 /* DECnet Control Protocol */ +#define PPP_APPLECP 0x8029 /* Appletalk Control Protocol */ +#define PPP_IPXCP 0x802b /* Novell IPX Control Protocol */ +#define PPP_STIICP 0x8033 /* Stream Protocol Control Protocol */ +#define PPP_VINESCP 0x8035 /* Banyan Vines Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_MPLSCP 0x8281 /* rfc 3022 */ + +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQM 0xc025 /* Link Quality Monitoring */ +#define PPP_CHAP 0xc223 /* Challenge Handshake Authentication Protocol */ diff --git a/src/libpcap-1.10.5/rpcap-protocol.c b/src/libpcap-1.10.5/rpcap-protocol.c new file mode 100644 index 0000000000..d1aac8be79 --- /dev/null +++ b/src/libpcap-1.10.5/rpcap-protocol.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include /* for strlen(), ... */ +#include /* for malloc(), free(), ... */ +#include /* for functions with variable number of arguments */ +#include /* for the errno variable */ +#include "sockutils.h" +#include "portability.h" +#include "rpcap-protocol.h" +#include + +/* + * This file contains functions used both by the rpcap client and the + * rpcap daemon. + */ + +/* + * This function sends a RPCAP error to our peer. + * + * It has to be called when the main program detects an error. + * It will send to our peer the 'buffer' specified by the user. + * This function *does not* request a RPCAP CLOSE connection. A CLOSE + * command must be sent explicitly by the program, since we do not know + * whether the error can be recovered in some way or if it is a + * non-recoverable one. + * + * \param sock: the socket we are currently using. + * + * \param ssl: if compiled with openssl, the optional ssl handler to use with the above socket. + * + * \param ver: the protocol version we want to put in the reply. + * + * \param errcode: a integer which tells the other party the type of error + * we had. + * + * \param error: an user-allocated (and '0' terminated) buffer that contains + * the error description that has to be transmitted to our peer. The + * error message cannot be longer than PCAP_ERRBUF_SIZE. + * + * \param errbuf: a pointer to a user-allocated buffer (of size + * PCAP_ERRBUF_SIZE) that will contain the error message (in case there + * is one). It could be network problem. + * + * \return '0' if everything is fine, '-1' if some errors occurred. The + * error message is returned in the 'errbuf' variable. + */ +int +rpcap_senderror(PCAP_SOCKET sock, SSL *ssl, uint8 ver, unsigned short errcode, const char *error, char *errbuf) +{ + char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */ + int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */ + uint16 length; + + length = (uint16)strlen(error); + + if (length > PCAP_ERRBUF_SIZE) + length = PCAP_ERRBUF_SIZE; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, RPCAP_MSG_ERROR, errcode, length); + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + if (sock_bufferize(error, length, sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE)) + return -1; + + if (sock_send(sock, ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) < 0) + return -1; + + return 0; +} + +/* + * This function fills in a structure of type rpcap_header. + * + * It is provided just because the creation of an rpcap header is a common + * task. It accepts all the values that appears into an rpcap_header, and + * it puts them in place using the proper hton() calls. + * + * \param header: a pointer to a user-allocated buffer which will contain + * the serialized header, ready to be sent on the network. + * + * \param ver: a value (in the host byte order) which will be placed into the + * header.ver field and that represents the protocol version number of the + * current message. + * + * \param type: a value (in the host byte order) which will be placed into the + * header.type field and that represents the type of the current message. + * + * \param value: a value (in the host byte order) which will be placed into + * the header.value field and that has a message-dependent meaning. + * + * \param length: a value (in the host by order) which will be placed into + * the header.length field, representing the payload length of the message. + * + * \return Nothing. The serialized header is returned into the 'header' + * variable. + */ +void +rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length) +{ + memset(header, 0, sizeof(struct rpcap_header)); + + header->ver = ver; + header->type = type; + header->value = htons(value); + header->plen = htonl(length); +} + +/* + * Convert a message type to a string containing the type name. + */ +static const char *requests[] = +{ + NULL, /* not a valid message type */ + "RPCAP_MSG_ERROR", + "RPCAP_MSG_FINDALLIF_REQ", + "RPCAP_MSG_OPEN_REQ", + "RPCAP_MSG_STARTCAP_REQ", + "RPCAP_MSG_UPDATEFILTER_REQ", + "RPCAP_MSG_CLOSE", + "RPCAP_MSG_PACKET", + "RPCAP_MSG_AUTH_REQ", + "RPCAP_MSG_STATS_REQ", + "RPCAP_MSG_ENDCAP_REQ", + "RPCAP_MSG_SETSAMPLING_REQ", +}; +#define NUM_REQ_TYPES (sizeof requests / sizeof requests[0]) + +static const char *replies[] = +{ + NULL, + NULL, /* this would be a reply to RPCAP_MSG_ERROR */ + "RPCAP_MSG_FINDALLIF_REPLY", + "RPCAP_MSG_OPEN_REPLY", + "RPCAP_MSG_STARTCAP_REPLY", + "RPCAP_MSG_UPDATEFILTER_REPLY", + NULL, /* this would be a reply to RPCAP_MSG_CLOSE */ + NULL, /* this would be a reply to RPCAP_MSG_PACKET */ + "RPCAP_MSG_AUTH_REPLY", + "RPCAP_MSG_STATS_REPLY", + "RPCAP_MSG_ENDCAP_REPLY", + "RPCAP_MSG_SETSAMPLING_REPLY", +}; +#define NUM_REPLY_TYPES (sizeof replies / sizeof replies[0]) + +const char * +rpcap_msg_type_string(uint8 type) +{ + if (type & RPCAP_MSG_IS_REPLY) { + type &= ~RPCAP_MSG_IS_REPLY; + if (type >= NUM_REPLY_TYPES) + return NULL; + return replies[type]; + } else { + if (type >= NUM_REQ_TYPES) + return NULL; + return requests[type]; + } +} diff --git a/src/libpcap-1.10.5/rpcap-protocol.h b/src/libpcap-1.10.5/rpcap-protocol.h new file mode 100644 index 0000000000..773a1e4872 --- /dev/null +++ b/src/libpcap-1.10.5/rpcap-protocol.h @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __RPCAP_PROTOCOL_H__ +#define __RPCAP_PROTOCOL_H__ + +#define RPCAP_DEFAULT_NETPORT "2002" /* Default port on which the RPCAP daemon is waiting for connections. */ +/* Default port on which the client workstation is waiting for connections in case of active mode. */ +#define RPCAP_DEFAULT_NETPORT_ACTIVE "2003" +#define RPCAP_DEFAULT_NETADDR "" /* Default network address on which the RPCAP daemon binds to. */ + +/* + * Minimum and maximum supported versions of the protocol. + * + * If new message types are added, the protocol version MUST be changed, + * so that a client knows, from the negotiated protocol version, what + * messages can be sent to the server. + * + * If the format of an existing message type is changed, the protocol + * version MUST be changed, so that each side knows, from the negotiated + * protocol version, what format should be used. + * + * The RPCAP_MSG_ERROR format MUST not change, as it's used to, among + * other things, report "incorrect version number" errors, where, if + * the format changed, the sender of the message might not know what + * versions the recipient would understand, or might know a version + * they support (the version number they sent) but might not know + * the format of the message in that version. + * + * Other message versions SHOULD not change, as that would complicate + * the process of interpreting the message, making it version-dependent. + * Introducing a new message with a new format is preferable. + * + * Version negotiation is done as part of the authentication process: + * + * The client sends an authentication request, with a version number + * of 0. All servers must accept authentication requests with a version + * number of 0, even if they don't support version 0 for any other + * requests. + * + * The server attempts to authenticate the client. If that succeeds, + * older servers - which only support version 0 - will send an + * authentication reply with no payload. Newer servers - which might + * support other versions - will send an authentication reply with + * a payload giving the minimum and maximum versions it supports. + * + * The client attempts to find the largest version number that is + * in both its range of supported versions and the server's supported + * versions. If it fails, it gives up; otherwise, it uses that version. + */ +#define RPCAP_MIN_VERSION 0 +#define RPCAP_MAX_VERSION 0 + +/* + * Version numbers are unsigned, so if RPCAP_MIN_VERSION is 0, they + * are >= the minimum version, by definition; don't check against + * RPCAP_MIN_VERSION, as you may get compiler warnings that the + * comparison will always succeed. + */ +#if RPCAP_MIN_VERSION == 0 +#define RPCAP_VERSION_IS_SUPPORTED(v) \ + ((v) <= RPCAP_MAX_VERSION) +#else +#define RPCAP_VERSION_IS_SUPPORTED(v) \ + ((v) >= RPCAP_MIN_VERSION && (v) <= RPCAP_MAX_VERSION) +#endif + +/* + * Separators used for the host list. + * + * It is used: + * - by the rpcapd daemon, when you types a list of allowed connecting hosts + * - by the rpcap client in active mode, when the client waits for incoming + * connections from other hosts + */ +#define RPCAP_HOSTLIST_SEP " ,;\n\r" + +/********************************************************* + * * + * Protocol messages formats * + * * + *********************************************************/ +/* + * WARNING: This file defines some structures that are used to transfer + * data on the network. + * Note that your compiler MUST not insert padding into these structures + * for better alignment. + * These structures have been created in order to be correctly aligned to + * a 32-bit boundary, but be careful in any case. + * + * The layout of these structures MUST not be changed. If a packet + * format is different in different versions of the protocol, versions + * of the structure should be provided for all the different versions or + * version ranges (if more than one version of the protocol has the same + * layout) that we support. + */ + +/* + * WARNING: These typedefs MUST be of a specific size. + * You might have to change them on your platform. + * + * XXX - use the C99 types? Microsoft's newer versions of Visual Studio + * support them. + */ +#ifndef __HAIKU__ +typedef unsigned char uint8; /* 8-bit unsigned integer */ +typedef unsigned short uint16; /* 16-bit unsigned integer */ +typedef unsigned int uint32; /* 32-bit unsigned integer */ +typedef int int32; /* 32-bit signed integer */ +#else +#include +#endif + +/* Common header for all the RPCAP messages */ +struct rpcap_header +{ + uint8 ver; /* RPCAP version number */ + uint8 type; /* RPCAP message type (error, findalldevs, ...) */ + uint16 value; /* Message-dependent value (not always used) */ + uint32 plen; /* Length of the payload of this RPCAP message */ +}; + +/* + * Format of data that may appear at the end of an authentication reply, + * giving the minimum and maximum versions of the protocol that the + * server supports. + * + * Older servers don't provide this; they support only version 0. + */ +struct rpcap_authreply +{ + uint8 minvers; /* Minimum version supported */ + uint8 maxvers; /* Maximum version supported */ + uint8 pad[2]; /* Pad to 4-byte boundary **/ + uint32 byte_order_magic; /* RPCAP_BYTE_ORDER_MAGIC, in server byte order */ +}; + +/* + * Any resemblance between this and the pcap file magic number + * is purely coincidental, trust me. + */ +#define RPCAP_BYTE_ORDER_MAGIC 0xa1b2c3d4U +#define RPCAP_BYTE_ORDER_MAGIC_SWAPPED 0xd4c3b2a1U + +/* + * Older version of authentication reply, without byte order indication + * and padding. + */ +struct rpcap_authreply_old +{ + uint8 minvers; /* Minimum version supported */ + uint8 maxvers; /* Maximum version supported */ +}; + +/* Format of the message for the interface description (findalldevs command) */ +struct rpcap_findalldevs_if +{ + uint16 namelen; /* Length of the interface name */ + uint16 desclen; /* Length of the interface description */ + uint32 flags; /* Interface flags */ + uint16 naddr; /* Number of addresses */ + uint16 dummy; /* Must be zero */ +}; + +/* + * Format of an address as sent over the wire. + * + * Do *NOT* use struct sockaddr_storage, as the layout for that is + * machine-dependent. + * + * RFC 2553 gives two sample layouts, both of which are 128 bytes long, + * both of which are aligned on an 8-byte boundary, and both of which + * have 2 bytes before the address data. + * + * However, one has a 2-byte address family value at the beginning + * and the other has a 1-byte address length value and a 1-byte + * address family value; this reflects the fact that the original + * BSD sockaddr structure had a 2-byte address family value, which + * was later changed to a 1-byte address length value and a 1-byte + * address family value, when support for variable-length OSI + * network-layer addresses was added. + * + * Furthermore, Solaris's struct sockaddr_storage is 256 bytes + * long. + * + * This structure is supposed to be aligned on an 8-byte boundary; + * the message header is 8 bytes long, so we don't have to do + * anything to ensure it's aligned on that boundary within a packet, + * so we just define it as 128 bytes long, with a 2-byte address + * family. (We only support IPv4 and IPv6 addresses, which are fixed- + * length.) That way, it's the same size as sockaddr_storage on + * Windows, and it'll look like what an older Windows client will + * expect. + * + * In addition, do *NOT* use the host's AF_ value for an address, + * as the value for AF_INET6 is machine-dependent. We use the + * Windows value, so it'll look like what an older Windows client + * will expect. + * + * (The Windows client is the only one that has been distributed + * as a standard part of *pcap; UN*X clients are probably built + * from source by the user or administrator, so they're in a + * better position to upgrade an old client. Therefore, we + * try to make what goes over the wire look like what comes + * from a Windows server.) + */ +struct rpcap_sockaddr +{ + uint16 family; /* Address family */ + char data[128-2]; /* Data */ +}; + +/* + * Format of an IPv4 address as sent over the wire. + */ +#define RPCAP_AF_INET 2 /* Value on all OSes except for Haiku */ +struct rpcap_sockaddr_in +{ + uint16 family; /* Address family */ + uint16 port; /* Port number */ + uint32 addr; /* IPv4 address */ + uint8 zero[8]; /* Padding */ +}; + +/* + * Format of an IPv6 address as sent over the wire. + */ +#define RPCAP_AF_INET6 23 /* Value on Windows */ +struct rpcap_sockaddr_in6 +{ + uint16 family; /* Address family */ + uint16 port; /* Port number */ + uint32 flowinfo; /* IPv6 flow information */ + uint8 addr[16]; /* IPv6 address */ + uint32 scope_id; /* Scope zone index */ +}; + +/* Format of the message for the address listing (findalldevs command) */ +struct rpcap_findalldevs_ifaddr +{ + struct rpcap_sockaddr addr; /* Network address */ + struct rpcap_sockaddr netmask; /* Netmask for that address */ + struct rpcap_sockaddr broadaddr; /* Broadcast address for that address */ + struct rpcap_sockaddr dstaddr; /* P2P destination address for that address */ +}; + +/* + * \brief Format of the message of the connection opening reply (open command). + * + * This structure transfers over the network some of the values useful on the client side. + */ +struct rpcap_openreply +{ + int32 linktype; /* Link type */ + int32 tzoff; /* Timezone offset - not used by newer clients */ +}; + +/* Format of the message that starts a remote capture (startcap command) */ +struct rpcap_startcapreq +{ + uint32 snaplen; /* Length of the snapshot (number of bytes to capture for each packet) */ + uint32 read_timeout; /* Read timeout in milliseconds */ + uint16 flags; /* Flags (see RPCAP_STARTCAPREQ_FLAG_xxx) */ + uint16 portdata; /* Network port on which the client is waiting at (if 'serveropen') */ +}; + +/* Format of the reply message that devoted to start a remote capture (startcap reply command) */ +struct rpcap_startcapreply +{ + int32 bufsize; /* Size of the user buffer allocated by WinPcap; it can be different from the one we chose */ + uint16 portdata; /* Network port on which the server is waiting at (passive mode only) */ + uint16 dummy; /* Must be zero */ +}; + +/* + * \brief Format of the header which encapsulates captured packets when transmitted on the network. + * + * This message requires the general header as well, since we want to be able to exchange + * more information across the network in the future (for example statistics, and kind like that). + */ +struct rpcap_pkthdr +{ + /* + * This protocol needs to be updated with a new version before + * 2038-01-19 03:14:07 UTC. + */ + uint32 timestamp_sec; /* 'struct timeval' compatible, it represents the 'tv_sec' field */ + uint32 timestamp_usec; /* 'struct timeval' compatible, it represents the 'tv_usec' field */ + uint32 caplen; /* Length of portion present in the capture */ + uint32 len; /* Real length of this packet (off wire) */ + uint32 npkt; /* Ordinal number of the packet (i.e. the first one captured has '1', the second one '2', etc) */ +}; + +/* General header used for the pcap_setfilter() command; keeps just the number of BPF instructions */ +struct rpcap_filter +{ + uint16 filtertype; /* type of the filter transferred (BPF instructions, ...) */ + uint16 dummy; /* Must be zero */ + uint32 nitems; /* Number of items contained into the filter (e.g. BPF instructions for BPF filters) */ +}; + +/* Structure that keeps a single BPF instruction; it is repeated 'ninsn' times according to the 'rpcap_filterbpf' header */ +struct rpcap_filterbpf_insn +{ + uint16 code; /* opcode of the instruction */ + uint8 jt; /* relative offset to jump to in case of 'true' */ + uint8 jf; /* relative offset to jump to in case of 'false' */ + int32 k; /* instruction-dependent value */ +}; + +/* Structure that keeps the data required for the authentication on the remote host */ +struct rpcap_auth +{ + uint16 type; /* Authentication type */ + uint16 dummy; /* Must be zero */ + uint16 slen1; /* Length of the first authentication item (e.g. username) */ + uint16 slen2; /* Length of the second authentication item (e.g. password) */ +}; + +/* Structure that keeps the statistics about the number of packets captured, dropped, etc. */ +struct rpcap_stats +{ + uint32 ifrecv; /* Packets received by the kernel filter (i.e. pcap_stats.ps_recv) */ + uint32 ifdrop; /* Packets dropped by the network interface (e.g. not enough buffers) (i.e. pcap_stats.ps_ifdrop) */ + uint32 krnldrop; /* Packets dropped by the kernel filter (i.e. pcap_stats.ps_drop) */ + uint32 svrcapt; /* Packets captured by the RPCAP daemon and sent on the network */ +}; + +/* Structure that is needed to set sampling parameters */ +struct rpcap_sampling +{ + uint8 method; /* Sampling method */ + uint8 dummy1; /* Must be zero */ + uint16 dummy2; /* Must be zero */ + uint32 value; /* Parameter related to the sampling method */ +}; + +/* + * Messages field coding. + * + * These values are used in messages sent over the network, and MUST + * not be changed. + */ +#define RPCAP_MSG_IS_REPLY 0x080 /* Flag indicating a reply */ + +#define RPCAP_MSG_ERROR 0x01 /* Message that keeps an error notification */ +#define RPCAP_MSG_FINDALLIF_REQ 0x02 /* Request to list all the remote interfaces */ +#define RPCAP_MSG_OPEN_REQ 0x03 /* Request to open a remote device */ +#define RPCAP_MSG_STARTCAP_REQ 0x04 /* Request to start a capture on a remote device */ +#define RPCAP_MSG_UPDATEFILTER_REQ 0x05 /* Send a compiled filter into the remote device */ +#define RPCAP_MSG_CLOSE 0x06 /* Close the connection with the remote peer */ +#define RPCAP_MSG_PACKET 0x07 /* This is a 'data' message, which carries a network packet */ +#define RPCAP_MSG_AUTH_REQ 0x08 /* Message that keeps the authentication parameters */ +#define RPCAP_MSG_STATS_REQ 0x09 /* It requires to have network statistics */ +#define RPCAP_MSG_ENDCAP_REQ 0x0A /* Stops the current capture, keeping the device open */ +#define RPCAP_MSG_SETSAMPLING_REQ 0x0B /* Set sampling parameters */ + +#define RPCAP_MSG_FINDALLIF_REPLY (RPCAP_MSG_FINDALLIF_REQ | RPCAP_MSG_IS_REPLY) /* Keeps the list of all the remote interfaces */ +#define RPCAP_MSG_OPEN_REPLY (RPCAP_MSG_OPEN_REQ | RPCAP_MSG_IS_REPLY) /* The remote device has been opened correctly */ +#define RPCAP_MSG_STARTCAP_REPLY (RPCAP_MSG_STARTCAP_REQ | RPCAP_MSG_IS_REPLY) /* The capture is starting correctly */ +#define RPCAP_MSG_UPDATEFILTER_REPLY (RPCAP_MSG_UPDATEFILTER_REQ | RPCAP_MSG_IS_REPLY) /* The filter has been applied correctly on the remote device */ +#define RPCAP_MSG_AUTH_REPLY (RPCAP_MSG_AUTH_REQ | RPCAP_MSG_IS_REPLY) /* Sends a message that says 'ok, authorization successful' */ +#define RPCAP_MSG_STATS_REPLY (RPCAP_MSG_STATS_REQ | RPCAP_MSG_IS_REPLY) /* Message that keeps the network statistics */ +#define RPCAP_MSG_ENDCAP_REPLY (RPCAP_MSG_ENDCAP_REQ | RPCAP_MSG_IS_REPLY) /* Confirms that the capture stopped successfully */ +#define RPCAP_MSG_SETSAMPLING_REPLY (RPCAP_MSG_SETSAMPLING_REQ | RPCAP_MSG_IS_REPLY) /* Confirms that the capture stopped successfully */ + +#define RPCAP_STARTCAPREQ_FLAG_PROMISC 0x00000001 /* Enables promiscuous mode (default: disabled) */ +#define RPCAP_STARTCAPREQ_FLAG_DGRAM 0x00000002 /* Use a datagram (i.e. UDP) connection for the data stream (default: use TCP)*/ +#define RPCAP_STARTCAPREQ_FLAG_SERVEROPEN 0x00000004 /* The server has to open the data connection toward the client */ +#define RPCAP_STARTCAPREQ_FLAG_INBOUND 0x00000008 /* Capture only inbound packets (take care: the flag has no effect with promiscuous enabled) */ +#define RPCAP_STARTCAPREQ_FLAG_OUTBOUND 0x00000010 /* Capture only outbound packets (take care: the flag has no effect with promiscuous enabled) */ + +#define RPCAP_UPDATEFILTER_BPF 1 /* This code tells us that the filter is encoded with the BPF/NPF syntax */ + +/* + * Network error codes. + * + * These values are used in messages sent over the network, and MUST + * not be changed. + */ +#define PCAP_ERR_NETW 1 /* Network error */ +#define PCAP_ERR_INITTIMEOUT 2 /* The RPCAP initial timeout has expired */ +#define PCAP_ERR_AUTH 3 /* Generic authentication error */ +#define PCAP_ERR_FINDALLIF 4 /* Generic findalldevs error */ +#define PCAP_ERR_NOREMOTEIF 5 /* The findalldevs was ok, but the remote end had no interfaces to list */ +#define PCAP_ERR_OPEN 6 /* Generic pcap_open error */ +#define PCAP_ERR_UPDATEFILTER 7 /* Generic updatefilter error */ +#define PCAP_ERR_GETSTATS 8 /* Generic pcap_stats error */ +#define PCAP_ERR_READEX 9 /* Generic pcap_next_ex error */ +#define PCAP_ERR_HOSTNOAUTH 10 /* The host is not authorized to connect to this server */ +#define PCAP_ERR_REMOTEACCEPT 11 /* Generic pcap_remoteaccept error */ +#define PCAP_ERR_STARTCAPTURE 12 /* Generic pcap_startcapture error */ +#define PCAP_ERR_ENDCAPTURE 13 /* Generic pcap_endcapture error */ +#define PCAP_ERR_RUNTIMETIMEOUT 14 /* The RPCAP run-time timeout has expired */ +#define PCAP_ERR_SETSAMPLING 15 /* Error during the settings of sampling parameters */ +#define PCAP_ERR_WRONGMSG 16 /* The other end endpoint sent a message which has not been recognized */ +#define PCAP_ERR_WRONGVER 17 /* The other end endpoint has a version number that is not compatible with our */ +#define PCAP_ERR_AUTH_FAILED 18 /* The user couldn't be authenticated */ +#define PCAP_ERR_TLS_REQUIRED 19 /* The server requires TLS to connect */ +#define PCAP_ERR_AUTH_TYPE_NOTSUP 20 /* The authentication type isn't supported */ + +/* + * \brief Buffer used by socket functions to send-receive packets. + * In case you plan to have messages larger than this value, you have to increase it. + */ +#define RPCAP_NETBUF_SIZE 64000 + +/********************************************************* + * * + * Routines used by the rpcap client and rpcap daemon * + * * + *********************************************************/ + +#include "sockutils.h" +#include "sslutils.h" + +extern void rpcap_createhdr(struct rpcap_header *header, uint8 ver, uint8 type, uint16 value, uint32 length); +extern const char *rpcap_msg_type_string(uint8 type); +extern int rpcap_senderror(PCAP_SOCKET sock, SSL *ssl, uint8 ver, uint16 errcode, const char *error, char *errbuf); + +#endif diff --git a/src/libpcap-1.10.5/rpcapd/CMakeLists.txt b/src/libpcap-1.10.5/rpcapd/CMakeLists.txt new file mode 100644 index 0000000000..28fd3c241f --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/CMakeLists.txt @@ -0,0 +1,165 @@ +message(STATUS "Running rpcapd/CMakeLists.txt") +if(UNIX) + check_function_exists(crypt HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + if(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + set(HAVE_CRYPT TRUE) + else(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + check_library_exists(crypt crypt "" HAVE_CRYPT_IN_LIBCRYPT) + if(HAVE_CRYPT_IN_LIBCRYPT) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} crypt) + set(HAVE_CRYPT TRUE) + else(HAVE_CRYPT_IN_LIBCRYPT) + message(WARNING "crypt() not found. Won't be able to build rpcapd.") + endif(HAVE_CRYPT_IN_LIBCRYPT) + endif(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) +endif(UNIX) + +# +# On UN*X, we need pthreads and crypt(). +# +if(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT)) + if(UNIX) + # + # Do we have getspnam()? + # + check_function_exists(getspnam HAVE_GETSPNAM) + + # + # Find library needed for getaddrinfo. + # NOTE: if you hand check_library_exists as its last argument a variable + # that's been set, it skips the test, so we need different variables. + # + include(CheckLibraryExists) + check_function_exists(getaddrinfo STDLIBS_HAVE_GETADDRINFO) + if(NOT STDLIBS_HAVE_GETADDRINFO) + check_library_exists(xnet getaddrinfo "" LIBXNET_HAS_GETADDRINFO) + if(LIBXNET_HAS_GETADDRINFO) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} xnet) + else(LIBXNET_HAS_GETADDRINFO) + include(CMakePushCheckState) + cmake_push_check_state() + set(CMAKE_REQUIRED_LIBRARIES nsl) + check_library_exists(socket getaddrinfo "" LIBSOCKET_HAS_GETADDRINFO) + cmake_pop_check_state() + if(LIBSOCKET_HAS_GETADDRINFO) + set(RPCAPD_LINK_LIBRARIES ${RPCAPD_LINK_LIBRARIES} socket nsl) + endif(LIBSOCKET_HAS_GETADDRINFO) + endif(LIBXNET_HAS_GETADDRINFO) + endif(NOT STDLIBS_HAVE_GETADDRINFO) + endif(UNIX) + + if(WIN32) + set(RPCAPD_EXTRA_SOURCES + win32-svc.c + ${pcap_SOURCE_DIR}/charconv.c + ${pcap_SOURCE_DIR}/missing/getopt.c + rpcapd.rc) + include_directories(${pcap_SOURCE_DIR}/rpcapd ${pcap_SOURCE_DIR}/missing) + endif(WIN32) + + add_executable(rpcapd + daemon.c + fileconf.c + log.c + rpcapd.c + ${pcap_SOURCE_DIR}/rpcap-protocol.c + ${pcap_SOURCE_DIR}/sockutils.c + ${pcap_SOURCE_DIR}/sslutils.c + ${pcap_SOURCE_DIR}/fmtutils.c + ${RPCAPD_EXTRA_SOURCES} + ) + + if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(rpcapd PROPERTIES COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) + endif() + + if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(rpcapd PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") + endif() + + # + # By default, build rpcapd universal with the appropriate set of + # architectures for the OS on which we're doing the build. + # + if(APPLE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") + set_target_properties(rpcapd PROPERTIES + OSX_ARCHITECTURES "${OSX_EXECUTABLE_ARCHITECTURES}") + endif() + + if(WIN32) + target_link_libraries(rpcapd ${LIBRARY_NAME} + ${RPCAPD_LINK_LIBRARIES} ${PCAP_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + else(WIN32) + target_link_libraries(rpcapd ${LIBRARY_NAME}_static + ${RPCAPD_LINK_LIBRARIES} ${PCAP_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + endif(WIN32) + + ###################################### + # Install rpcap daemon and man pages + ###################################### + + # + # "Define GNU standard installation directories", which actually + # are also defined, to some degree, by autotools, and at least + # some of which are general UN*X conventions. + # + include(GNUInstallDirs) + + set(MANADMIN_EXPAND rpcapd.manadmin.in) + + set(MANFILE_EXPAND rpcapd-config.manfile.in) + + if(WIN32) + # + # XXX - where should the install target put rpcapd on Windows? + # + # Note that if an installer package is being produced + # from the results of the build, the installer package + # will determine where it goes. + # + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + install(TARGETS rpcapd DESTINATION bin/amd64) + else(CMAKE_SIZEOF_VOID_P EQUAL 8) + install(TARGETS rpcapd DESTINATION bin) + endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + else(WIN32) + # + # On UN*X, we put it in the sbin directory. + # + # XXX - the Linux Filesystem Hierarchy Standard says /usr/sbin + # is for daemons, but some other systems use /usr/libexec instead. + # However, since some users might, instead of having rpcapd be + # launched by inetd/xinetd/launchd/systemd, just run it on a + # machine when remote capture is to be done, a case can be made + # for the sbin directory even on systems with /usr/libexec. + # + install(TARGETS rpcapd DESTINATION ${CMAKE_INSTALL_SBINDIR}) + endif(WIN32) + + # On UN*X, and on Windows when not using MSVC, generate process man + # pages and arrange that they be installed. + if(NOT MSVC) + # + # Man pages. + # + # For each section of the manual for which we have man pages + # that require macro expansion, do the expansion. + # + set(MANADMIN "") + foreach(TEMPLATE_MANPAGE ${MANADMIN_EXPAND}) + string(REPLACE ".manadmin.in" ".${MAN_ADMIN_COMMANDS}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANADMIN ${MANADMIN} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANADMIN} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_ADMIN_COMMANDS}) + + set(MANFILE "") + foreach(TEMPLATE_MANPAGE ${MANFILE_EXPAND}) + string(REPLACE ".manfile.in" ".${MAN_FILE_FORMATS}" MANPAGE ${TEMPLATE_MANPAGE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_MANPAGE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE} @ONLY) + set(MANFILE ${MANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${MANPAGE}) + endforeach(TEMPLATE_MANPAGE) + install(FILES ${MANFILE} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_FILE_FORMATS}) + endif(NOT MSVC) +endif(WIN32 OR ((CMAKE_USE_PTHREADS_INIT OR PTHREADS_FOUND) AND HAVE_CRYPT)) diff --git a/src/libpcap-1.10.5/rpcapd/Makefile.in b/src/libpcap-1.10.5/rpcapd/Makefile.in new file mode 100644 index 0000000000..fd00886df2 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/Makefile.in @@ -0,0 +1,142 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ +PROG=libpcap +RPCAPD_LIBS = @RPCAPD_LIBS@ + +# Standard CFLAGS +FULL_CFLAGS = $(CCOPT) @V_PROG_CCOPT_FAT@ $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +SRC = daemon.c \ + fileconf.c \ + log.c \ + rpcapd.c + +OBJ = $(SRC:.c=.o) +PUBHDR = + +HDR = $(PUBHDR) log.h + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) rpcapd + +MANADMIN = \ + rpcapd.manadmin.in + +MANFILE = \ + rpcapd-config.manfile.in + +rpcapd: $(OBJ) ../libpcap.a + $(CC) $(CCOPT) $(CFLAGS) $(LDFLAGS) @V_PROG_LDFLAGS_FAT@ \ + -o $@ $(OBJ) ../libpcap.a $(LIBS) $(RPCAPD_LIBS) $(PTHREAD_LIBS) +clean: + rm -f $(CLEANFILES) + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h stamp-h stamp-h.in + rm -f $(MANADMIN:.in=) $(MANFILE:.in=) + rm -rf autom4te.cache + +install: rpcapd + [ -d $(DESTDIR)$(sbindir) ] || \ + (mkdir -p $(DESTDIR)$(sbindir); chmod 755 $(DESTDIR)$(sbindir)) + $(INSTALL_PROGRAM) rpcapd $(DESTDIR)$(sbindir)/rpcapd + [ -d $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@) + [ -d $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@ ] || \ + (mkdir -p $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@; chmod 755 $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@) + for i in $(MANADMIN); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manadmin.in/.manadmin/'` \ + $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done + for i in $(MANFILE); do \ + $(INSTALL_DATA) `echo $$i | sed 's/.manfile.in/.manfile/'` \ + $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + +uninstall: + rm -f $(DESTDIR)$(sbindir)/rpcapd + for i in $(MANADMIN); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_ADMIN_COMMANDS@/`echo $$i | sed 's/.manadmin.in/.@MAN_ADMIN_COMMANDS@/'`; done + for i in $(MANFILE); do \ + rm -f $(DESTDIR)$(mandir)/man@MAN_FILE_FORMATS@/`echo $$i | sed 's/.manfile.in/.@MAN_FILE_FORMATS@/'`; done + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +depend: + $(MKDEP) -c $(CC) -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/src/libpcap-1.10.5/rpcapd/config_params.h b/src/libpcap-1.10.5/rpcapd/config_params.h new file mode 100644 index 0000000000..a46897d59f --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/config_params.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __CONFIG_PARAMS_H__ +#define __CONFIG_PARAMS_H__ + +// +// Parameters set from the configuration file. +// + +#define MAX_LINE 2048 /* Maximum chars allowed for the host list (in passive mode) */ +#define MAX_HOST_LIST 64000 +#define MAX_ACTIVE_LIST 10 + +struct active_pars +{ + char address[MAX_LINE + 1]; // keeps the network address (either numeric or literal) to of the active client + char port[MAX_LINE + 1]; // keeps the network port to bind to + int ai_family; // address family to use +}; + +extern char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server +extern struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) +extern int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +extern char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration + +#endif diff --git a/src/libpcap-1.10.5/rpcapd/daemon.c b/src/libpcap-1.10.5/rpcapd/daemon.c new file mode 100644 index 0000000000..8727466580 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/daemon.c @@ -0,0 +1,3148 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "ftmacros.h" +#include "varattrs.h" + +#include // for the errno variable +#include // for malloc(), free(), ... +#include // for strlen(), ... +#include // for INT_MAX + +#ifdef _WIN32 + #include // for threads +#else + #include + #include + #include + #include + #include // for select() and such + #include // for password management +#endif + +#ifdef HAVE_GETSPNAM +#include // for password management +#endif + +#include // for libpcap/WinPcap calls + +#include "fmtutils.h" +#include "sockutils.h" // for socket calls +#include "portability.h" +#include "rpcap-protocol.h" +#include "daemon.h" +#include "log.h" + +#ifdef HAVE_OPENSSL +#include +#include "sslutils.h" +#endif + +// +// Timeout, in seconds, when we're waiting for a client to send us an +// authentication request; if they don't send us a request within that +// interval, we drop the connection, so we don't stay stuck forever. +// +#define RPCAP_TIMEOUT_INIT 90 + +// +// Timeout, in seconds, when we're waiting for an authenticated client +// to send us a request, if a capture isn't in progress; if they don't +// send us a request within that interval, we drop the connection, so +// we don't stay stuck forever. +// +#define RPCAP_TIMEOUT_RUNTIME 180 + +// +// Time, in seconds, that we wait after a failed authentication attempt +// before processing the next request; this prevents a client from +// rapidly trying different accounts or passwords. +// +#define RPCAP_SUSPEND_WRONGAUTH 1 + +// Parameters for the service loop. +struct daemon_slpars +{ + PCAP_SOCKET sockctrl; //!< PCAP_SOCKET ID of the control connection + SSL *ssl; //!< Optional SSL handler for the controlling sockets + int isactive; //!< Not null if the daemon has to run in active mode + int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +}; + +// +// Data for a session managed by a thread. +// It includes both a Boolean indicating whether we *have* a thread, +// and a platform-dependent (UN*X vs. Windows) identifier for the +// thread; on Windows, we could use an invalid handle to indicate +// that we don't have a thread, but there *is* no portable "no thread" +// value for a pthread_t on UN*X. +// +struct session { + PCAP_SOCKET sockctrl; + PCAP_SOCKET sockdata; + SSL *ctrl_ssl, *data_ssl; // optional SSL handlers for sockctrl and sockdata. + uint8 protocol_version; + pcap_t *fp; + unsigned int TotCapt; + int have_thread; +#ifdef _WIN32 + HANDLE thread; +#else + pthread_t thread; +#endif +}; + +// Locally defined functions +static int daemon_msg_err(PCAP_SOCKET sockctrl, SSL *, uint32 plen); +static int daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen); +static int daemon_AuthUserPwd(char *username, char *password, char *errbuf); + +static int daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen); + +static int daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, char *source, size_t sourcelen); +static int daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, char *source, struct session **sessionp, + struct rpcap_sampling *samp_param, int uses_ssl); +static int daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, + struct session *session); + +static int daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen); +static int daemon_unpackapplyfilter(PCAP_SOCKET sockctrl, SSL *, struct session *session, uint32 *plenp, char *errbuf); + +static int daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen, struct pcap_stat *stats, + unsigned int svrcapt); + +static int daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, + uint32 plen, struct rpcap_sampling *samp_param); + +static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout); +#ifdef _WIN32 +static unsigned __stdcall daemon_thrdatamain(void *ptr); +#else +static void *daemon_thrdatamain(void *ptr); +static void noop_handler(int sign); +#endif + +static int rpcapd_recv_msg_header(PCAP_SOCKET sock, SSL *, struct rpcap_header *headerp); +static int rpcapd_recv(PCAP_SOCKET sock, SSL *, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf); +static int rpcapd_discard(PCAP_SOCKET sock, SSL *, uint32 len); +static void session_close(struct session *); + +// +// TLS record layer header; used when processing the first message from +// the client, in case we aren't doing TLS but they are. +// +struct tls_record_header { + uint8 type; // ContentType - will be 22, for Handshake + uint8 version_major; // TLS protocol major version + uint8 version_injor; // TLS protocol minor version + // This is *not* aligned on a 2-byte boundary; we just + // declare it as two bytes. Don't assume any particular + // compiler's mechanism for saying "packed"! + uint8 length_hi; // Upper 8 bits of payload length + uint8 length_lo; // Low 8 bits of payload length +}; + +#define TLS_RECORD_HEADER_LEN 5 // Don't use sizeof in case it's padded + +#define TLS_RECORD_TYPE_ALERT 21 +#define TLS_RECORD_TYPE_HANDSHAKE 22 + +// +// TLS alert message. +// +struct tls_alert { + uint8 alert_level; + uint8 alert_description; +}; + +#define TLS_ALERT_LEN 2 + +#define TLS_ALERT_LEVEL_FATAL 2 +#define TLS_ALERT_HANDSHAKE_FAILURE 40 + +static int is_url(const char *source); + +/* + * Maximum sizes for fixed-bit-width values. + */ +#ifndef UINT16_MAX +#define UINT16_MAX 65535U +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295U +#endif + +int +daemon_serviceloop(PCAP_SOCKET sockctrl, int isactive, char *passiveClients, + int nullAuthAllowed, int uses_ssl) +{ + uint8 first_octet; + struct tls_record_header tls_header; + struct tls_alert tls_alert; + struct daemon_slpars pars; // service loop parameters + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + char errmsgbuf[PCAP_ERRBUF_SIZE + 1]; // buffer for errors to send to the client + int host_port_check_status; + SSL *ssl = NULL; + int nrecv; + struct rpcap_header header; // RPCAP message general header + uint32 plen; // payload length from header + int authenticated = 0; // 1 if the client has successfully authenticated + char source[PCAP_BUF_SIZE+1]; // keeps the string that contains the interface to open + int got_source = 0; // 1 if we've gotten the source from an open request +#ifndef _WIN32 + struct sigaction action; +#endif + struct session *session = NULL; // struct session main variable + const char *msg_type_string; // string for message type + int client_told_us_to_close = 0; // 1 if the client told us to close the capture + + // needed to save the values of the statistics + struct pcap_stat stats; + unsigned int svrcapt; + + struct rpcap_sampling samp_param; // in case sampling has been requested + + // Structures needed for the select() call + fd_set rfds; // set of socket descriptors we have to check + struct timeval tv; // maximum time the select() can block waiting for data + int retval; // select() return value + + *errbuf = 0; // Initialize errbuf + + // + // Peek into the socket to determine whether the client sent us + // a TLS handshake message or a non-TLS rpcapd message. + // + // The first byte of an rpcapd request is the version number; + // the first byte of a TLS handshake message is 22. The + // first request to an rpcapd server must be an authentication + // request or a close request, and must have a version number + // of 0, so it will be possible to distinguish between an + // initial plaintext request to a server and an initial TLS + // handshake message. + // + nrecv = sock_recv(sockctrl, NULL, (char *)&first_octet, 1, + SOCK_EOF_ISNT_ERROR|SOCK_MSG_PEEK, errbuf, PCAP_ERRBUF_SIZE); + if (nrecv == -1) + { + // Fatal error. + rpcapd_log(LOGPRIO_ERROR, "Peek from client failed: %s", errbuf); + goto end; + } + if (nrecv == 0) + { + // Client closed the connection. + goto end; + } + +#ifdef HAVE_OPENSSL + // + // We have to upgrade to TLS as soon as possible, so that the + // whole protocol goes through the encrypted tunnel, including + // early error messages. + // + // Even in active mode, the other end has to initiate the TLS + // handshake as we still are the server as far as TLS is concerned, + // so we don't check isactive. + // + if (uses_ssl) + { + // + // We're expecting a TLS handshake message. If this + // isn't one, assume it's a non-TLS rpcapd message. + // + // The first octet of a TLS handshake is + // TLS_RECORD_TYPE_HANDSHAKE. + // + if (first_octet != TLS_RECORD_TYPE_HANDSHAKE) + { + // + // We assume this is a non-TLS rpcapd message. + // + // Read the message header from the client. + // + nrecv = rpcapd_recv_msg_header(sockctrl, NULL, &header); + if (nrecv == -1) + { + // Fatal error. + goto end; + } + if (nrecv == -2) + { + // Client closed the connection. + goto end; + } + plen = header.plen; + + // Discard the rest of the message. + if (rpcapd_discard(sockctrl, NULL, plen) == -1) + { + // Network error. + goto end; + } + + // + // Send an authentication error, indicating + // that we require TLS. + // + if (rpcap_senderror(sockctrl, NULL, header.ver, + PCAP_ERR_TLS_REQUIRED, + "TLS is required by this server", errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // Shut the session down. + goto end; + } + ssl = ssl_promotion(1, sockctrl, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake on control connection failed: %s", + errbuf); + goto end; + } + } + else +#endif + { + // + // We're expecting a non-TLS rpcapd message. If this + // looks, instead, like a TLS handshake message, send + // a TLS handshake_failed alert. + // + // The first octet of a TLS handshake is + // TLS_RECORD_TYPE_HANDSHAKE. + // + if (first_octet == TLS_RECORD_TYPE_HANDSHAKE) + { + // + // TLS handshake. + // Read the record header. + // + nrecv = sock_recv(sockctrl, ssl, (char *) &tls_header, + sizeof tls_header, SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, + errbuf, PCAP_ERRBUF_SIZE); + if (nrecv == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + goto end; + } + if (nrecv == 0) + { + // Immediate EOF + goto end; + } + plen = (tls_header.length_hi << 8U) | tls_header.length_lo; + + // Discard the rest of the message. + if (rpcapd_discard(sockctrl, NULL, plen) == -1) + { + // Network error. + goto end; + } + + // + // Send a TLS handshake failure alert. + // Use the same version the client sent us. + // + tls_header.type = TLS_RECORD_TYPE_ALERT; + tls_header.length_hi = 0; + tls_header.length_lo = TLS_ALERT_LEN; + + if (sock_send(sockctrl, NULL, (char *) &tls_header, + TLS_RECORD_HEADER_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + tls_alert.alert_level = TLS_ALERT_LEVEL_FATAL; + tls_alert.alert_description = TLS_ALERT_HANDSHAKE_FAILURE; + if (sock_send(sockctrl, NULL, (char *) &tls_alert, + TLS_ALERT_LEN, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // + // Give up anyway. + // + goto end; + } + } + + // Set parameters structure + pars.sockctrl = sockctrl; + pars.ssl = ssl; + pars.isactive = isactive; // active mode + pars.nullAuthAllowed = nullAuthAllowed; + + // + // We have a connection. + // + // If it's a passive mode connection, check whether the connecting + // host is among the ones allowed. + // + // In either case, we were handed a copy of the host list; free it + // as soon as we're done with it. + // + if (pars.isactive) + { + // Nothing to do. + free(passiveClients); + passiveClients = NULL; + } + else + { + struct sockaddr_storage from; + socklen_t fromlen; + + // + // Get the address of the other end of the connection. + // + fromlen = sizeof(struct sockaddr_storage); + if (getpeername(pars.sockctrl, (struct sockaddr *)&from, + &fromlen) == -1) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); + if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // + // Are they in the list of host/port combinations we allow? + // + host_port_check_status = sock_check_hostlist(passiveClients, RPCAP_HOSTLIST_SEP, &from, errmsgbuf, PCAP_ERRBUF_SIZE); + free(passiveClients); + passiveClients = NULL; + if (host_port_check_status < 0) + { + if (host_port_check_status == -2) { + // + // We got an error; log it. + // + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + } + + // + // Sorry, we can't let you in. + // + if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_HOSTNOAUTH, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + +#ifndef _WIN32 + // + // Catch SIGUSR1, but do nothing. We use it to interrupt the + // capture thread to break it out of a loop in which it's + // blocked waiting for packets to arrive. + // + // We don't want interrupted system calls to restart, so that + // the read routine for the pcap_t gets EINTR rather than + // restarting if it's blocked in a system call. + // + memset(&action, 0, sizeof (action)); + action.sa_handler = noop_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGUSR1, &action, NULL); +#endif + + // + // The client must first authenticate; loop until they send us a + // message with a version we support and credentials we accept, + // they send us a close message indicating that they're giving up, + // or we get a network error or other fatal error. + // + while (!authenticated) + { + // + // If we're not in active mode, we use select(), with a + // timeout, to wait for an authentication request; if + // the timeout expires, we drop the connection, so that + // a client can't just connect to us and leave us + // waiting forever. + // + if (!pars.isactive) + { + FD_ZERO(&rfds); + // We do not have to block here + tv.tv_sec = RPCAP_TIMEOUT_INIT; + tv.tv_usec = 0; + + FD_SET(pars.sockctrl, &rfds); + + retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv); + if (retval == -1) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "select() failed"); + if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_NETW, errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // The timeout has expired + // So, this was a fake connection. Drop it down + if (retval == 0) + { + if (rpcap_senderror(pars.sockctrl, pars.ssl, 0, PCAP_ERR_INITTIMEOUT, "The RPCAP initial timeout has expired", errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + + // + // Read the message header from the client. + // + nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header); + if (nrecv == -1) + { + // Fatal error. + goto end; + } + if (nrecv == -2) + { + // Client closed the connection. + goto end; + } + + plen = header.plen; + + // + // While we're in the authentication phase, all requests + // must use version 0. + // + if (header.ver != 0) + { + // + // Send it back to them with their version. + // + if (rpcap_senderror(pars.sockctrl, pars.ssl, header.ver, + PCAP_ERR_WRONGVER, + "RPCAP version in requests in the authentication phase must be 0", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // Discard the rest of the message and drop the + // connection. + (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen); + goto end; + } + + switch (header.type) + { + case RPCAP_MSG_AUTH_REQ: + retval = daemon_msg_auth_req(&pars, plen); + if (retval == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + if (retval == -2) + { + // Non-fatal error; we sent back + // an error message, so let them + // try again. + continue; + } + + // OK, we're authenticated; we sent back + // a reply, so start serving requests. + authenticated = 1; + break; + + case RPCAP_MSG_CLOSE: + // + // The client is giving up. + // Discard the rest of the message, if + // there is anything more. + // + (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen); + // We're done with this client. + goto end; + + case RPCAP_MSG_ERROR: + // Log this and close the connection? + // XXX - is this what happens in active + // mode, where *we* initiate the + // connection, and the client gives us + // an error message rather than a "let + // me log in" message, indicating that + // we're not allowed to connect to them? + (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen); + goto end; + + case RPCAP_MSG_FINDALLIF_REQ: + case RPCAP_MSG_OPEN_REQ: + case RPCAP_MSG_STARTCAP_REQ: + case RPCAP_MSG_UPDATEFILTER_REQ: + case RPCAP_MSG_STATS_REQ: + case RPCAP_MSG_ENDCAP_REQ: + case RPCAP_MSG_SETSAMPLING_REQ: + // + // These requests can't be sent until + // the client is authenticated. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s request sent before authentication was completed", msg_type_string); + } + else + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message of type %u sent before authentication was completed", header.type); + } + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGMSG, + errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Network error. + goto end; + } + break; + + case RPCAP_MSG_PACKET: + case RPCAP_MSG_FINDALLIF_REPLY: + case RPCAP_MSG_OPEN_REPLY: + case RPCAP_MSG_STARTCAP_REPLY: + case RPCAP_MSG_UPDATEFILTER_REPLY: + case RPCAP_MSG_AUTH_REPLY: + case RPCAP_MSG_STATS_REPLY: + case RPCAP_MSG_ENDCAP_REPLY: + case RPCAP_MSG_SETSAMPLING_REPLY: + // + // These are server-to-client messages. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string); + } + else + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); + } + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGMSG, + errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Fatal error. + goto end; + } + break; + + default: + // + // Unknown message type. + // + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type); + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGMSG, + errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Fatal error. + goto end; + } + break; + } + } + + // + // OK, the client has authenticated itself, and we can start + // processing regular requests from it. + // + + // + // We don't have any statistics yet. + // + stats.ps_ifdrop = 0; + stats.ps_recv = 0; + stats.ps_drop = 0; + svrcapt = 0; + + // + // Service requests. + // + for (;;) + { + errbuf[0] = 0; // clear errbuf + + // Avoid zombies connections; check if the connection is opens but no commands are performed + // from more than RPCAP_TIMEOUT_RUNTIME + // Conditions: + // - I have to be in normal mode (no active mode) + // - if the device is open, I don't have to be in the middle of a capture (session->sockdata) + // - if the device is closed, I have always to check if a new command arrives + // + // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but + // sockdata is 0 + if ((!pars.isactive) && (session == NULL || session->sockdata == 0)) + { + // Check for the initial timeout + FD_ZERO(&rfds); + // We do not have to block here + tv.tv_sec = RPCAP_TIMEOUT_RUNTIME; + tv.tv_usec = 0; + + FD_SET(pars.sockctrl, &rfds); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + retval = 1; +#else + retval = select((int)pars.sockctrl + 1, &rfds, NULL, NULL, &tv); +#endif + if (retval == -1) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "select() failed"); + if (rpcap_senderror(pars.sockctrl, pars.ssl, + 0, PCAP_ERR_NETW, + errmsgbuf, errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // The timeout has expired + // So, this was a fake connection. Drop it down + if (retval == 0) + { + if (rpcap_senderror(pars.sockctrl, pars.ssl, + 0, PCAP_ERR_INITTIMEOUT, + "The RPCAP initial timeout has expired", + errbuf) == -1) + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + + // + // Read the message header from the client. + // + nrecv = rpcapd_recv_msg_header(pars.sockctrl, pars.ssl, &header); + if (nrecv == -1) + { + // Fatal error. + goto end; + } + if (nrecv == -2) + { + // Client closed the connection. + goto end; + } + + plen = header.plen; + + // + // Did the client specify a protocol version that we + // support? + // + if (!RPCAP_VERSION_IS_SUPPORTED(header.ver)) + { + // + // Tell them it's not a supported version. + // Send the error message with their version, + // so they don't reject it as having the wrong + // version. + // + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGVER, + "RPCAP version in message isn't supported by the server", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + + // Discard the rest of the message. + (void)rpcapd_discard(pars.sockctrl, pars.ssl, plen); + // Give up on them. + goto end; + } + + switch (header.type) + { + case RPCAP_MSG_ERROR: // The other endpoint reported an error + { + (void)daemon_msg_err(pars.sockctrl, pars.ssl, plen); + // Do nothing; just exit; the error code is already into the errbuf + // XXX - actually exit.... + break; + } + + case RPCAP_MSG_FINDALLIF_REQ: + { + if (daemon_msg_findallif_req(header.ver, &pars, plen) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_OPEN_REQ: + { + // + // Process the open request, and keep + // the source from it, for use later + // when the capture is started. + // + // XXX - we don't care if the client sends + // us multiple open requests, the last + // one wins. + // + retval = daemon_msg_open_req(header.ver, &pars, + plen, source, sizeof(source)); + if (retval == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + got_source = 1; + break; + } + + case RPCAP_MSG_STARTCAP_REQ: + { + if (!got_source) + { + // They never told us what device + // to capture on! + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, + PCAP_ERR_STARTCAPTURE, + "No capture device was specified", + errbuf) == -1) + { + // Fatal error; log an + // error and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + goto end; + } + break; + } + + if (daemon_msg_startcap_req(header.ver, &pars, + plen, source, &session, &samp_param, + uses_ssl) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_UPDATEFILTER_REQ: + { + if (session) + { + if (daemon_msg_updatefilter_req(header.ver, + &pars, session, plen) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + } + else + { + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, + PCAP_ERR_UPDATEFILTER, + "Device not opened. Cannot update filter", + errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + } + break; + } + + case RPCAP_MSG_CLOSE: // The other endpoint close the pcap session + { + // + // Indicate to our caller that the client + // closed the control connection. + // This is used only in case of active mode. + // + client_told_us_to_close = 1; + rpcapd_log(LOGPRIO_DEBUG, "The other end system asked to close the connection."); + goto end; + } + + case RPCAP_MSG_STATS_REQ: + { + if (daemon_msg_stats_req(header.ver, &pars, + session, plen, &stats, svrcapt) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_ENDCAP_REQ: // The other endpoint close the current capture session + { + if (session) + { + // Save statistics (we can need them in the future) + if (pcap_stats(session->fp, &stats)) + { + svrcapt = session->TotCapt; + } + else + { + stats.ps_ifdrop = 0; + stats.ps_recv = 0; + stats.ps_drop = 0; + svrcapt = 0; + } + + if (daemon_msg_endcap_req(header.ver, + &pars, session) == -1) + { + free(session); + session = NULL; + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + free(session); + session = NULL; + } + else + { + rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, + PCAP_ERR_ENDCAPTURE, + "Device not opened. Cannot close the capture", + errbuf); + } + break; + } + + case RPCAP_MSG_SETSAMPLING_REQ: + { + if (daemon_msg_setsampling_req(header.ver, + &pars, plen, &samp_param) == -1) + { + // Fatal error; a message has + // been logged, so just give up. + goto end; + } + break; + } + + case RPCAP_MSG_AUTH_REQ: + { + // + // We're already authenticated; you don't + // get to reauthenticate. + // + rpcapd_log(LOGPRIO_INFO, "The client sent an RPCAP_MSG_AUTH_REQ message after authentication was completed"); + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, + PCAP_ERR_WRONGMSG, + "RPCAP_MSG_AUTH_REQ request sent after authentication was completed", + errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + + case RPCAP_MSG_PACKET: + case RPCAP_MSG_FINDALLIF_REPLY: + case RPCAP_MSG_OPEN_REPLY: + case RPCAP_MSG_STARTCAP_REPLY: + case RPCAP_MSG_UPDATEFILTER_REPLY: + case RPCAP_MSG_AUTH_REPLY: + case RPCAP_MSG_STATS_REPLY: + case RPCAP_MSG_ENDCAP_REPLY: + case RPCAP_MSG_SETSAMPLING_REPLY: + // + // These are server-to-client messages. + // + msg_type_string = rpcap_msg_type_string(header.type); + if (msg_type_string != NULL) + { + rpcapd_log(LOGPRIO_INFO, "The client sent a %s server-to-client message", msg_type_string); + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message %s received from client", msg_type_string); + } + else + { + rpcapd_log(LOGPRIO_INFO, "The client sent a server-to-client message of type %u", header.type); + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Server-to-client message of type %u received from client", header.type); + } + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGMSG, + errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + + default: + // + // Unknown message type. + // + rpcapd_log(LOGPRIO_INFO, "The client sent a message of type %u", header.type); + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Unknown message type %u", header.type); + if (rpcap_senderror(pars.sockctrl, pars.ssl, + header.ver, PCAP_ERR_WRONGMSG, + errbuf, errmsgbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto end; + } + // Discard the rest of the message. + if (rpcapd_discard(pars.sockctrl, pars.ssl, plen) == -1) + { + // Fatal error. + goto end; + } + goto end; + } + } + } + +end: + // The service loop is finishing up. + // If we have a capture session running, close it. + if (session) + { + session_close(session); + free(session); + session = NULL; + } + + if (passiveClients) { + free(passiveClients); + } + // + // Finish using the SSL handle for the control socket, if we + // have an SSL connection, and close the control socket. + // +#ifdef HAVE_OPENSSL + if (ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(ssl); + } +#endif + sock_close(sockctrl, NULL, 0); + + // Print message and return + rpcapd_log(LOGPRIO_DEBUG, "I'm exiting from the child loop"); + + return client_told_us_to_close; +} + +/* + * This handles the RPCAP_MSG_ERR message. + */ +static int +daemon_msg_err(PCAP_SOCKET sockctrl, SSL *ssl, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char remote_errbuf[PCAP_ERRBUF_SIZE]; + + if (plen >= PCAP_ERRBUF_SIZE) + { + /* + * Message is too long; just read as much of it as we + * can into the buffer provided, and discard the rest. + */ + if (sock_recv(sockctrl, ssl, remote_errbuf, PCAP_ERRBUF_SIZE - 1, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + if (rpcapd_discard(sockctrl, ssl, plen - (PCAP_ERRBUF_SIZE - 1)) == -1) + { + // Network error. + return -1; + } + + /* + * Null-terminate it. + */ + remote_errbuf[PCAP_ERRBUF_SIZE - 1] = '\0'; + } + else if (plen == 0) + { + /* Empty error string. */ + remote_errbuf[0] = '\0'; + } + else + { + if (sock_recv(sockctrl, ssl, remote_errbuf, plen, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + + /* + * Null-terminate it. + */ + remote_errbuf[plen] = '\0'; + } + // Log the message + rpcapd_log(LOGPRIO_ERROR, "Error from client: %s", remote_errbuf); + return 0; +} + +/* + * This handles the RPCAP_MSG_AUTH_REQ message. + * It checks if the authentication credentials supplied by the user are valid. + * + * This function is called if the daemon receives a RPCAP_MSG_AUTH_REQ + * message in its authentication loop. It reads the body of the + * authentication message from the network and checks whether the + * credentials are valid. + * + * \param sockctrl: the socket for the control connection. + * + * \param nullAuthAllowed: '1' if the NULL authentication is allowed. + * + * \param errbuf: a user-allocated buffer in which the error message + * (if one) has to be written. It must be at least PCAP_ERRBUF_SIZE + * bytes long. + * + * \return '0' if everything is fine, '-1' if an unrecoverable error occurred, + * or '-2' if the authentication failed. For errors, an error message is + * returned in the 'errbuf' variable; this gives a message for the + * unrecoverable error or for the authentication failure. + */ +static int +daemon_msg_auth_req(struct daemon_slpars *pars, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + int status; + struct rpcap_auth auth; // RPCAP authentication header + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_authreply *authreply; // authentication reply message + + status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &auth, sizeof(struct rpcap_auth), &plen, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + goto error; + } + + switch (ntohs(auth.type)) + { + case RPCAP_RMTAUTH_NULL: + { + if (!pars->nullAuthAllowed) + { + // Send the client an error reply. + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Authentication failed; NULL authentication not permitted."); + if (rpcap_senderror(pars->sockctrl, pars->ssl, + 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + goto error_noreply; + } + break; + } + + case RPCAP_RMTAUTH_PWD: + { + char *username, *passwd; + uint32 usernamelen, passwdlen; + + usernamelen = ntohs(auth.slen1); + username = (char *) malloc (usernamelen + 1); + if (username == NULL) + { + pcapint_fmt_errmsg_for_errno(errmsgbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + goto error; + } + status = rpcapd_recv(pars->sockctrl, pars->ssl, username, usernamelen, &plen, errmsgbuf); + if (status == -1) + { + free(username); + return -1; + } + if (status == -2) + { + free(username); + goto error; + } + username[usernamelen] = '\0'; + + passwdlen = ntohs(auth.slen2); + passwd = (char *) malloc (passwdlen + 1); + if (passwd == NULL) + { + pcapint_fmt_errmsg_for_errno(errmsgbuf, + PCAP_ERRBUF_SIZE, errno, "malloc() failed"); + free(username); + goto error; + } + status = rpcapd_recv(pars->sockctrl, pars->ssl, passwd, passwdlen, &plen, errmsgbuf); + if (status == -1) + { + free(username); + free(passwd); + return -1; + } + if (status == -2) + { + free(username); + free(passwd); + goto error; + } + passwd[passwdlen] = '\0'; + + if (daemon_AuthUserPwd(username, passwd, errmsgbuf)) + { + // + // Authentication failed. Let the client + // know. + // + free(username); + free(passwd); + if (rpcap_senderror(pars->sockctrl, pars->ssl, + 0, PCAP_ERR_AUTH_FAILED, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // + // Suspend for 1 second, so that they can't + // hammer us with repeated tries with an + // attack such as a dictionary attack. + // + // WARNING: this delay is inserted only + // at this point; if the client closes the + // connection and reconnects, the suspension + // time does not have any effect. + // + sleep_secs(RPCAP_SUSPEND_WRONGAUTH); + goto error_noreply; + } + + free(username); + free(passwd); + break; + } + + default: + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Authentication type not recognized."); + if (rpcap_senderror(pars->sockctrl, pars->ssl, + 0, PCAP_ERR_AUTH_TYPE_NOTSUP, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + goto error_noreply; + } + + // The authentication succeeded; let the client know. + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, 0, + RPCAP_MSG_AUTH_REPLY, 0, sizeof(struct rpcap_authreply)); + + authreply = (struct rpcap_authreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_authreply), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + // + // Indicate to our peer what versions we support and what our + // version of the byte-order magic is (which will tell the + // client whether our byte order differs from theirs, in which + // case they will need to byte-swap some fields in some + // link-layer types' headers). + // + memset(authreply, 0, sizeof(struct rpcap_authreply)); + authreply->minvers = RPCAP_MIN_VERSION; + authreply->maxvers = RPCAP_MAX_VERSION; + authreply->byte_order_magic = RPCAP_BYTE_ORDER_MAGIC; + + // Send the reply. + if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, pars->ssl, 0, PCAP_ERR_AUTH, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + +error_noreply: + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + + return -2; +} + +static int +daemon_AuthUserPwd(char *username, char *password, char *errbuf) +{ +#ifdef _WIN32 + /* + * Warning: the user which launches the process must have the + * SE_TCB_NAME right. + * This corresponds to have the "Act as part of the Operating System" + * turned on (administrative tools, local security settings, local + * policies, user right assignment) + * However, it seems to me that if you run it as a service, this + * right should be provided by default. + * + * XXX - hopefully, this returns errors such as ERROR_LOGON_FAILURE, + * which merely indicates that the user name or password is + * incorrect, not whether it's the user name or the password + * that's incorrect, so a client that's trying to brute-force + * accounts doesn't know whether it's the user name or the + * password that's incorrect, so it doesn't know whether to + * stop trying to log in with a given user name and move on + * to another user name. + */ + DWORD error; + HANDLE Token; + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to log + + if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + error = GetLastError(); + if (error != ERROR_LOGON_FAILURE) + { + // Some error other than an authentication error; + // log it. + pcapint_fmt_errmsg_for_win32_err(errmsgbuf, + PCAP_ERRBUF_SIZE, error, "LogonUser() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + } + return -1; + } + + // This call should change the current thread to the selected user. + // I didn't test it. + if (ImpersonateLoggedOnUser(Token) == 0) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + pcapint_fmt_errmsg_for_win32_err(errmsgbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "ImpersonateLoggedOnUser() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errmsgbuf); + CloseHandle(Token); + return -1; + } + + CloseHandle(Token); + return 0; + +#else + /* + * See + * + * https://www.unixpapa.com/incnote/passwd.html + * + * We use the Solaris/Linux shadow password authentication if + * we have getspnam(), otherwise we just do traditional + * authentication, which, on some platforms, might work, even + * with shadow passwords, if we're running as root. Traditional + * authentication won't work if we're not running as root, as + * I think these days all UN*Xes either won't return the password + * at all with getpwnam() or will only do so if you're root. + * + * XXX - perhaps what we *should* be using is PAM, if we have + * it. That might hide all the details of username/password + * authentication, whether it's done with a visible-to-root- + * only password database or some other authentication mechanism, + * behind its API. + */ + int error; + struct passwd *user; + char *user_password; +#ifdef HAVE_GETSPNAM + struct spwd *usersp; +#endif + char *crypt_password; + + // This call is needed to get the uid + if ((user = getpwnam(username)) == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + +#ifdef HAVE_GETSPNAM + // This call is needed to get the password; otherwise 'x' is returned + if ((usersp = getspnam(username)) == NULL) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + user_password = usersp->sp_pwdp; +#else + /* + * XXX - what about other platforms? + * The unixpapa.com page claims this Just Works on *BSD if you're + * running as root - it's from 2000, so it doesn't indicate whether + * macOS (which didn't come out until 2001, under the name Mac OS + * X) behaves like the *BSDs or not, and might also work on AIX. + * HP-UX does something else. + * + * Again, hopefully PAM hides all that. + */ + user_password = user->pw_passwd; +#endif + + // + // The Single UNIX Specification says that if crypt() fails it + // sets errno, but some implementations that haven't been run + // through the SUS test suite might not do so. + // + errno = 0; + crypt_password = crypt(password, user_password); + if (crypt_password == NULL) + { + error = errno; + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + if (error == 0) + { + // It didn't set errno. + rpcapd_log(LOGPRIO_ERROR, "crypt() failed"); + } + else + { + rpcapd_log(LOGPRIO_ERROR, "crypt() failed: %s", + strerror(error)); + } + return -1; + } + if (strcmp(user_password, crypt_password) != 0) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed"); + return -1; + } + + if (setuid(user->pw_uid)) + { + error = errno; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + error, "setuid"); + rpcapd_log(LOGPRIO_ERROR, "setuid() failed: %s", + strerror(error)); + return -1; + } + +/* if (setgid(user->pw_gid)) + { + error = errno; + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "setgid"); + rpcapd_log(LOGPRIO_ERROR, "setgid() failed: %s", + strerror(error)); + return -1; + } +*/ + return 0; + +#endif + +} + +/* + * Make sure that the reply length won't overflow 32 bits if we add the + * specified amount to it. If it won't, add that amount to it. + * + * We check whether replylen + itemlen > UINT32_MAX, but subtract itemlen + * from both sides, to prevent overflow. + */ +#define CHECK_AND_INCREASE_REPLY_LEN(itemlen) \ + if (replylen > UINT32_MAX - (itemlen)) { \ + pcapint_strlcpy(errmsgbuf, "Reply length doesn't fit in 32 bits", \ + sizeof (errmsgbuf)); \ + goto error; \ + } \ + replylen += (uint32)(itemlen) + +static int +daemon_msg_findallif_req(uint8 ver, struct daemon_slpars *pars, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + pcap_if_t *alldevs = NULL; // pointer to the header of the interface chain + pcap_if_t *d; // temp pointer needed to scan the interface chain + struct pcap_addr *address; // pcap structure that keeps a network address of an interface + uint32 replylen; // length of reply payload + uint16 nif = 0; // counts the number of interface listed + + // Discard the rest of the message; there shouldn't be any payload. + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + // Network error. + return -1; + } + + // Retrieve the device list + if (pcap_findalldevs(&alldevs, errmsgbuf) == -1) + goto error; + + if (alldevs == NULL) + { + if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, + PCAP_ERR_NOREMOTEIF, + "No interfaces found! Make sure libpcap/WinPcap is properly installed" + " and you have the right to access to the remote device.", + errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; + } + + // This checks the number of interfaces and computes the total + // length of the payload. + replylen = 0; + for (d = alldevs; d != NULL; d = d->next) + { + nif++; + + if (d->description) { + size_t stringlen = strlen(d->description); + if (stringlen > UINT16_MAX) { + pcapint_strlcpy(errmsgbuf, + "Description length doesn't fit in 16 bits", + sizeof (errmsgbuf)); + goto error; + } + CHECK_AND_INCREASE_REPLY_LEN(stringlen); + } + if (d->name) { + size_t stringlen = strlen(d->name); + if (stringlen > UINT16_MAX) { + pcapint_strlcpy(errmsgbuf, + "Name length doesn't fit in 16 bits", + sizeof (errmsgbuf)); + goto error; + } + CHECK_AND_INCREASE_REPLY_LEN(stringlen); + } + + CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_findalldevs_if)); + + uint16_t naddrs = 0; + for (address = d->addresses; address != NULL; address = address->next) + { + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + CHECK_AND_INCREASE_REPLY_LEN(sizeof(struct rpcap_sockaddr) * 4); + if (naddrs == UINT16_MAX) { + pcapint_strlcpy(errmsgbuf, + "Number of interfaces doesn't fit in 16 bits", + sizeof (errmsgbuf)); + goto error; + } + naddrs++; + break; + + default: + break; + } + } + } + + // RPCAP findalldevs reply + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_FINDALLIF_REPLY, nif, replylen); + + // send the interface list + for (d = alldevs; d != NULL; d = d->next) + { + uint16 lname, ldescr; + + // Note: the findalldevs_if entries are *not* neatly + // aligned on 4-byte boundaries, because they're + // preceded by strings that aren't padded to 4-byte + // boundaries, so we cannot just cast output buffer + // boundaries to struct rpcap_findalldevs_if pointers + // and store into them - we must fill in a structure and + // then copy the structure to the buffer, as not all + // systems support unaligned access (some, such as + // SPARC, crash; others, such as Arm, may just ignore + // the lower-order bits). + struct rpcap_findalldevs_if findalldevs_if; + + /* + * We've already established that the string lengths + * fit in 16 bits. + */ + if (d->description) + ldescr = (uint16) strlen(d->description); + else + ldescr = 0; + if (d->name) + lname = (uint16) strlen(d->name); + else + lname = 0; + + findalldevs_if.desclen = htons(ldescr); + findalldevs_if.namelen = htons(lname); + findalldevs_if.flags = htonl(d->flags); + + uint16_t naddrs = 0; + for (address = d->addresses; address != NULL; address = address->next) + { + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + naddrs++; + break; + + default: + break; + } + } + findalldevs_if.naddr = htons(naddrs); + findalldevs_if.dummy = 0; + + if (sock_bufferize(&findalldevs_if, sizeof(struct rpcap_findalldevs_if), sendbuf, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errmsgbuf, + PCAP_ERRBUF_SIZE) == -1) + goto error; + + // send all addresses + for (address = d->addresses; address != NULL; address = address->next) + { + struct rpcap_sockaddr *sockaddr; + + /* + * Send only IPv4 and IPv6 addresses over the wire. + */ + switch (address->addr->sa_family) + { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->addr, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->netmask, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->broadaddr, sockaddr); + + sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx]; + if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + daemon_seraddr((struct sockaddr_storage *) address->dstaddr, sockaddr); + break; + + default: + break; + } + } + } + + // We no longer need the device list. Free it. + pcap_freealldevs(alldevs); + + // Send a final command that says "now send it!" + if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + if (alldevs) + pcap_freealldevs(alldevs); + + if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, + PCAP_ERR_FINDALLIF, errmsgbuf, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; +} + +/* + \param plen: the length of the current message (needed in order to be able + to discard excess data in the message, if present) +*/ +static int +daemon_msg_open_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + char *source, size_t sourcelen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + pcap_t *fp; // pcap_t main variable + int nread; + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_openreply *openreply; // open reply message + + if (plen > sourcelen - 1) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string too long"); + goto error; + } + + nread = sock_recv(pars->sockctrl, pars->ssl, source, plen, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + source[nread] = '\0'; + plen -= nread; + + // Is this a URL rather than a device? + // If so, reject it. + if (is_url(source)) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Source string refers to a remote device"); + goto error; + } + + // Open the selected device + // This is a fake open, since we do that only to get the needed parameters, then we close the device again + if ((fp = pcap_open_live(source, + 1500 /* fake snaplen */, + 0 /* no promisc */, + 1000 /* fake timeout */, + errmsgbuf)) == NULL) + goto error; + + // Now, I can send a RPCAP open reply message + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply)); + + openreply = (struct rpcap_openreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + memset(openreply, 0, sizeof(struct rpcap_openreply)); + openreply->linktype = htonl(pcap_datalink(fp)); + /* + * This is always 0 for live captures; we no longer support it + * as something we read from capture files and supply to + * clients, but we have to send it over the wire, as open + * replies are expected to have 8 bytes of payload by + * existing clients. + */ + openreply->tzoff = 0; + + // We're done with the pcap_t. + pcap_close(fp); + + // Send the reply. + if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_OPEN, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + return 0; +} + +/* + \param plen: the length of the current message (needed in order to be able + to discard excess data in the message, if present) +*/ +static int +daemon_msg_startcap_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + char *source, struct session **sessionp, + struct rpcap_sampling *samp_param _U_, int uses_ssl) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char portdata[PCAP_BUF_SIZE]; // temp variable needed to derive the data port + char peerhost[PCAP_BUF_SIZE]; // temp variable needed to derive the host name of our peer + struct session *session = NULL; // saves state of session + int status; + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + + // socket-related variables + struct addrinfo hints; // temp, needed to open a socket connection + struct addrinfo *addrinfo; // temp, needed to open a socket connection + struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine + socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine + int ret; // return value from functions + + // RPCAP-related variables + struct rpcap_startcapreq startcapreq; // start capture request message + struct rpcap_startcapreply *startcapreply; // start capture reply message + int serveropen_dp; // keeps who is going to open the data connection + + addrinfo = NULL; + + status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &startcapreq, + sizeof(struct rpcap_startcapreq), &plen, errmsgbuf); + if (status == -1) + { + goto fatal_error; + } + if (status == -2) + { + goto error; + } + + startcapreq.flags = ntohs(startcapreq.flags); + + // Check that the client does not ask for UDP is the server has been asked + // to enforce encryption, as SSL is not supported yet with UDP: + if (uses_ssl && (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM)) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SSL not supported with UDP forward of remote packets"); + goto error; + } + + // Create a session structure + session = malloc(sizeof(struct session)); + if (session == NULL) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Can't allocate session structure"); + goto error; + } + + session->sockdata = INVALID_SOCKET; + session->ctrl_ssl = session->data_ssl = NULL; + // We don't have a thread yet. + session->have_thread = 0; + // + // We *shouldn't* have to initialize the thread indicator + // itself, because the compiler *should* realize that we + // only use this if have_thread isn't 0, but we *do* have + // to do it, because not all compilers *do* realize that. + // + // There is no "invalid thread handle" value for a UN*X + // pthread_t, so we just zero it out. + // +#ifdef _WIN32 + session->thread = INVALID_HANDLE_VALUE; +#else + memset(&session->thread, 0, sizeof(session->thread)); +#endif + + // Open the selected device + if ((session->fp = pcap_open_live(source, + ntohl(startcapreq.snaplen), + (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? 1 : 0 /* local device, other flags not needed */, + ntohl(startcapreq.read_timeout), + errmsgbuf)) == NULL) + goto error; + +#if 0 + // Apply sampling parameters + fp->rmt_samp.method = samp_param->method; + fp->rmt_samp.value = samp_param->value; +#endif + + /* + We're in active mode if: + - we're using TCP, and the user wants us to be in active mode + - we're using UDP + */ + serveropen_dp = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || pars->isactive; + + /* + Gets the sockaddr structure referred to the other peer in the ctrl connection + + We need that because: + - if we're in passive mode, we need to know the address family we want to use + (the same used for the ctrl socket) + - if we're in active mode, we need to know the network address of the other host + we want to connect to + */ + saddrlen = sizeof(struct sockaddr_storage); + if (getpeername(pars->sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getpeername() failed"); + goto error; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_family = saddr.ss_family; + + // Now we have to create a new socket to send packets + if (serveropen_dp) // Data connection is opened by the server toward the client + { + snprintf(portdata, sizeof portdata, "%d", ntohs(startcapreq.portdata)); + + // Get the name of the other peer (needed to connect to that specific network address) + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost, + sizeof(peerhost), NULL, 0, NI_NUMERICHOST)) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + goto error; + } + + addrinfo = sock_initaddress(peerhost, portdata, &hints, + errmsgbuf, PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + goto error; + + if ((session->sockdata = sock_open(peerhost, addrinfo, SOCKOPEN_CLIENT, 0, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error; + } + else // Data connection is opened by the client toward the server + { + hints.ai_flags = AI_PASSIVE; + + // Make the server socket pick up a free network port for us + addrinfo = sock_initaddress(NULL, NULL, &hints, errmsgbuf, + PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + goto error; + + if ((session->sockdata = sock_open(NULL, addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errmsgbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + goto error; + + // get the complete sockaddr structure used in the data connection + saddrlen = sizeof(struct sockaddr_storage); + if (getsockname(session->sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getsockname() failed"); + goto error; + } + + // Get the local port the system picked up + if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL, + 0, portdata, sizeof(portdata), NI_NUMERICSERV)) + { + sock_geterrmsg(errmsgbuf, PCAP_ERRBUF_SIZE, + "getnameinfo() failed"); + goto error; + } + } + + // addrinfo is no longer used + freeaddrinfo(addrinfo); + addrinfo = NULL; + + // Needed to send an error on the ctrl connection + session->sockctrl = pars->sockctrl; + session->ctrl_ssl = pars->ssl; + session->protocol_version = ver; + + // Now I can set the filter + ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf); + if (ret == -1) + { + // Fatal error. A message has been logged; just give up. + goto fatal_error; + } + if (ret == -2) + { + // Non-fatal error. Send an error message to the client. + goto error; + } + + // Now, I can send a RPCAP start capture reply message + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, + RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply)); + + startcapreply = (struct rpcap_startcapreply *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + memset(startcapreply, 0, sizeof(struct rpcap_startcapreply)); + startcapreply->bufsize = htonl(pcap_bufsize(session->fp)); + + if (!serveropen_dp) + { + unsigned short port = (unsigned short)strtoul(portdata,NULL,10); + startcapreply->portdata = htons(port); + } + + if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + goto fatal_error; + } + + if (!serveropen_dp) + { + PCAP_SOCKET socktemp; // We need another socket, since we're going to accept() a connection + + // Connection creation + saddrlen = sizeof(struct sockaddr_storage); + + socktemp = accept(session->sockdata, (struct sockaddr *) &saddr, &saddrlen); + + if (socktemp == INVALID_SOCKET) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "accept() failed"); + rpcapd_log(LOGPRIO_ERROR, "Accept of data connection failed: %s", + errbuf); + goto error; + } + + // Now that I accepted the connection, the server socket is no longer needed + sock_close(session->sockdata, NULL, 0); + session->sockdata = socktemp; + } + + SSL *ssl = NULL; + if (uses_ssl) + { +#ifdef HAVE_OPENSSL + /* In both active or passive cases, wait for the client to initiate the + * TLS handshake. Yes during that time the control socket will not be + * served, but the same was true from the above call to accept(). */ + ssl = ssl_promotion(1, session->sockdata, errbuf, PCAP_ERRBUF_SIZE); + if (! ssl) + { + rpcapd_log(LOGPRIO_ERROR, "TLS handshake failed: %s", errbuf); + goto error; + } +#endif + } + session->data_ssl = ssl; + + // Now we have to create a new thread to receive packets +#ifdef _WIN32 + session->thread = (HANDLE)_beginthreadex(NULL, 0, daemon_thrdatamain, + (void *) session, 0, NULL); + if (session->thread == 0) + { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread"); + goto error; + } +#else + ret = pthread_create(&session->thread, NULL, daemon_thrdatamain, + (void *) session); + if (ret != 0) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + ret, "Error creating the data thread"); + goto error; + } +#endif + session->have_thread = 1; + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + goto fatal_error; + + *sessionp = session; + return 0; + +error: + // + // Not a fatal error, so send the client an error message and + // keep serving client requests. + // + *sessionp = NULL; + + if (addrinfo) + freeaddrinfo(addrinfo); + + if (session) + { + session_close(session); + free(session); + } + + if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, + PCAP_ERR_STARTCAPTURE, errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + // Network error. + return -1; + } + + return 0; + +fatal_error: + // + // Fatal network error, so don't try to communicate with + // the client, just give up. + // + *sessionp = NULL; + + if (session) + { + session_close(session); + free(session); + } + + return -1; +} + +static int +daemon_msg_endcap_req(uint8 ver, struct daemon_slpars *pars, + struct session *session) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + struct rpcap_header header; + + session_close(session); + + rpcap_createhdr(&header, ver, RPCAP_MSG_ENDCAP_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; +} + +// +// We impose a limit on the filter program size, so that, on Windows, +// where there's only one server process with multiple threads, it's +// harder to eat all the server address space by sending larger filter +// programs. (This isn't an issue on UN*X, where there are multiple +// server processes, one per client connection.) +// +// We pick a value that limits each filter to 64K; that value is twice +// the in-kernel limit for Linux and 16 times the in-kernel limit for +// *BSD and macOS. +// +// It also prevents an overflow on 32-bit platforms when calculating +// the total size of the filter program. (It's not an issue on 64-bit +// platforms with a 64-bit size_t, as the filter size is 32 bits.) +// +#define RPCAP_BPF_MAXINSNS 8192 + +static int +daemon_unpackapplyfilter(PCAP_SOCKET sockctrl, SSL *ctrl_ssl, struct session *session, uint32 *plenp, char *errmsgbuf) +{ + int status; + struct rpcap_filter filter; + struct rpcap_filterbpf_insn insn; + struct bpf_insn *bf_insn; + struct bpf_program bf_prog; + unsigned int i; + + status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &filter, + sizeof(struct rpcap_filter), plenp, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + return -2; + } + + bf_prog.bf_len = ntohl(filter.nitems); + + if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported"); + return -2; + } + + if (bf_prog.bf_len > RPCAP_BPF_MAXINSNS) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, + "Filter program is larger than the maximum size of %d instructions", + RPCAP_BPF_MAXINSNS); + return -2; + } + bf_insn = (struct bpf_insn *) malloc (sizeof(struct bpf_insn) * bf_prog.bf_len); + if (bf_insn == NULL) + { + pcapint_fmt_errmsg_for_errno(errmsgbuf, PCAP_ERRBUF_SIZE, + errno, "malloc() failed"); + return -2; + } + + bf_prog.bf_insns = bf_insn; + + for (i = 0; i < bf_prog.bf_len; i++) + { + status = rpcapd_recv(sockctrl, ctrl_ssl, (char *) &insn, + sizeof(struct rpcap_filterbpf_insn), plenp, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + return -2; + } + + bf_insn->code = ntohs(insn.code); + bf_insn->jf = insn.jf; + bf_insn->jt = insn.jt; + bf_insn->k = ntohl(insn.k); + + bf_insn++; + } + + // + // XXX - pcap_setfilter() should do the validation for us. + // + if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions"); + return -2; + } + + if (pcap_setfilter(session->fp, &bf_prog)) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp)); + return -2; + } + + return 0; +} + +static int +daemon_msg_updatefilter_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + int ret; // status of daemon_unpackapplyfilter() + struct rpcap_header header; // keeps the answer to the updatefilter command + + ret = daemon_unpackapplyfilter(pars->sockctrl, pars->ssl, session, &plen, errmsgbuf); + if (ret == -1) + { + // Fatal error. A message has been logged; just give up. + return -1; + } + if (ret == -2) + { + // Non-fatal error. Send an error reply to the client. + goto error; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + // Network error. + return -1; + } + + // A response is needed, otherwise the other host does not know that everything went well + rpcap_createhdr(&header, ver, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE)) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_UPDATEFILTER, + errmsgbuf, NULL); + + return 0; +} + +/*! + \brief Received the sampling parameters from remote host and it stores in the pcap_t structure. +*/ +static int +daemon_msg_setsampling_req(uint8 ver, struct daemon_slpars *pars, uint32 plen, + struct rpcap_sampling *samp_param) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; + struct rpcap_header header; + struct rpcap_sampling rpcap_samp; + int status; + + status = rpcapd_recv(pars->sockctrl, pars->ssl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), &plen, errmsgbuf); + if (status == -1) + { + return -1; + } + if (status == -2) + { + goto error; + } + + // Save these settings in the pcap_t + samp_param->method = rpcap_samp.method; + samp_param->value = ntohl(rpcap_samp.value); + + // A response is needed, otherwise the other host does not know that everything went well + rpcap_createhdr(&header, ver, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0); + + if (sock_send(pars->sockctrl, pars->ssl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + + return 0; + +error: + if (rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_SETSAMPLING, + errmsgbuf, errbuf) == -1) + { + // That failed; log a message and give up. + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + // Check if all the data has been read; if not, discard the data in excess + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + return -1; + } + + return 0; +} + +static int +daemon_msg_stats_req(uint8 ver, struct daemon_slpars *pars, + struct session *session, uint32 plen, struct pcap_stat *stats, + unsigned int svrcapt) +{ + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + char errmsgbuf[PCAP_ERRBUF_SIZE]; // buffer for errors to send to the client + char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered + int sendbufidx = 0; // index which keeps the number of bytes currently buffered + struct rpcap_stats *netstats; // statistics sent on the network + + // Checks that the header does not contain other data; if so, discard it + if (rpcapd_discard(pars->sockctrl, pars->ssl, plen) == -1) + { + // Network error. + return -1; + } + + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + rpcap_createhdr((struct rpcap_header *) sendbuf, ver, + RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats)); + + netstats = (struct rpcap_stats *) &sendbuf[sendbufidx]; + + if (sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, + &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errmsgbuf, PCAP_ERRBUF_SIZE) == -1) + goto error; + + if (session && session->fp) + { + if (pcap_stats(session->fp, stats) == -1) + { + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "%s", pcap_geterr(session->fp)); + goto error; + } + + netstats->ifdrop = htonl(stats->ps_ifdrop); + netstats->ifrecv = htonl(stats->ps_recv); + netstats->krnldrop = htonl(stats->ps_drop); + netstats->svrcapt = htonl(session->TotCapt); + } + else + { + // We have to keep compatibility with old applications, + // which ask for statistics also when the capture has + // already stopped. + netstats->ifdrop = htonl(stats->ps_ifdrop); + netstats->ifrecv = htonl(stats->ps_recv); + netstats->krnldrop = htonl(stats->ps_drop); + netstats->svrcapt = htonl(svrcapt); + } + + // Send the packet + if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Send to client failed: %s", errbuf); + return -1; + } + + return 0; + +error: + rpcap_senderror(pars->sockctrl, pars->ssl, ver, PCAP_ERR_GETSTATS, + errmsgbuf, NULL); + return 0; +} + +#ifdef _WIN32 +static unsigned __stdcall +#else +static void * +#endif +daemon_thrdatamain(void *ptr) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer + struct session *session; // pointer to the struct session for this session + int retval; // general variable used to keep the return value of other functions + struct rpcap_pkthdr *net_pkt_header;// header of the packet + struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet + u_char *pkt_data; // pointer to the buffer that contains the current packet + size_t sendbufsize; // size for the send buffer + char *sendbuf; // temporary buffer in which data to be sent is buffered + int sendbufidx; // index which keeps the number of bytes currently buffered + int status; +#ifndef _WIN32 + sigset_t sigusr1; // signal set with just SIGUSR1 +#endif + + session = (struct session *) ptr; + + session->TotCapt = 0; // counter which is incremented each time a packet is received + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + // + // We need a buffer large enough to hold a buffer large enough + // for a maximum-size packet for this pcap_t. + // + if (pcap_snapshot(session->fp) < 0) + { + // + // The snapshot length is negative. + // This "should not happen". + // + rpcapd_log(LOGPRIO_ERROR, + "Unable to allocate the buffer for this child thread: snapshot length of %d is negative", + pcap_snapshot(session->fp)); + sendbuf = NULL; // we can't allocate a buffer, so nothing to free + goto error; + } + // + // size_t is unsigned, and the result of pcap_snapshot() is signed; + // on no platform that we support is int larger than size_t. + // This means that, unless the extra information we prepend to + // a maximum-sized packet is impossibly large, the sum of the + // snapshot length and the size of that extra information will + // fit in a size_t. + // + // So we don't need to make sure that sendbufsize will overflow. + // + // However, we *do* need to make sure its value fits in an int, + // because sock_send() can't send more than INT_MAX bytes (it could + // do so on 64-bit UN*Xes, but can't do so on Windows, not even + // 64-bit Windows, as the send() buffer size argument is an int + // in Winsock). + // + sendbufsize = sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr) + pcap_snapshot(session->fp); + if (sendbufsize > INT_MAX) + { + rpcapd_log(LOGPRIO_ERROR, + "Buffer size for this child thread would be larger than %d", + INT_MAX); + sendbuf = NULL; // we haven't allocated a buffer, so nothing to free + goto error; + } + sendbuf = (char *) malloc (sendbufsize); + if (sendbuf == NULL) + { + rpcapd_log(LOGPRIO_ERROR, + "Unable to allocate the buffer for this child thread"); + goto error; + } + +#ifndef _WIN32 + // + // Set the signal set to include just SIGUSR1, and block that + // signal; we only want it unblocked when we're reading + // packets - we dn't want any other system calls, such as + // ones being used to send to the client or to log messages, + // to be interrupted. + // + sigemptyset(&sigusr1); + sigaddset(&sigusr1, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &sigusr1, NULL); +#endif + + // Retrieve the packets + for (;;) + { +#ifndef _WIN32 + // + // Unblock SIGUSR1 while we might be waiting for packets. + // + pthread_sigmask(SIG_UNBLOCK, &sigusr1, NULL); +#endif + retval = pcap_next_ex(session->fp, &pkt_header, (const u_char **) &pkt_data); // cast to avoid a compiler warning +#ifndef _WIN32 + // + // Now block it again. + // + pthread_sigmask(SIG_BLOCK, &sigusr1, NULL); +#endif + if (retval < 0) + break; // error + if (retval == 0) // Read timeout elapsed + continue; + + sendbufidx = 0; + + // Bufferize the general header + if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, + &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + rpcap_createhdr((struct rpcap_header *) sendbuf, + session->protocol_version, RPCAP_MSG_PACKET, 0, + (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen)); + + net_pkt_header = (struct rpcap_pkthdr *) &sendbuf[sendbufidx]; + + // Bufferize the pkt header + if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, + &sendbufidx, (int)sendbufsize, SOCKBUF_CHECKONLY, errbuf, + PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + net_pkt_header->caplen = htonl(pkt_header->caplen); + net_pkt_header->len = htonl(pkt_header->len); + net_pkt_header->npkt = htonl(++(session->TotCapt)); + // + // This protocol needs to be updated with a new version + // before 2038-01-19 03:14:07 UTC. + // + net_pkt_header->timestamp_sec = htonl((uint32)pkt_header->ts.tv_sec); + net_pkt_header->timestamp_usec = htonl((uint32)pkt_header->ts.tv_usec); + + // Bufferize the pkt data + if (sock_bufferize((char *) pkt_data, pkt_header->caplen, + sendbuf, &sendbufidx, (int)sendbufsize, SOCKBUF_BUFFERIZE, + errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, + "sock_bufferize() error sending packet message: %s", + errbuf); + goto error; + } + + // Send the packet + // If the client dropped the connection, don't report an + // error, just quit. + status = sock_send(session->sockdata, session->data_ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE); + if (status < 0) + { + if (status == -1) + { + // + // Error other than "client closed the + // connection out from under us"; report + // it. + // + rpcapd_log(LOGPRIO_ERROR, + "Send of packet to client failed: %s", + errbuf); + } + + // + // Give up in either case. + // + goto error; + } + } + + if (retval < 0 && retval != PCAP_ERROR_BREAK) + { + // + // Failed with an error other than "we were told to break + // out of the loop". + // + // The latter just means that the client told us to stop + // capturing, so there's no error to report. + // + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp)); + rpcap_senderror(session->sockctrl, session->ctrl_ssl, session->protocol_version, + PCAP_ERR_READEX, errbuf, NULL); + } + +error: + // + // The main thread will clean up the session structure. + // + free(sendbuf); + + return 0; +} + +#ifndef _WIN32 +// +// Do-nothing handler for SIGUSR1; the sole purpose of SIGUSR1 is to +// interrupt the data thread if it's blocked in a system call waiting +// for packets to arrive. +// +static void noop_handler(int sign _U_) +{ +} +#endif + +/*! + \brief It serializes a network address. + + It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format + that can be used to be sent on the network. Basically, it applies all the hton() + conversion required to the input variable. + + \param sockaddrin a 'sockaddr_storage' pointer to the variable that has to be + serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'. + + \param sockaddrout an 'rpcap_sockaddr' pointer to the variable that will contain + the serialized data. This variable has to be allocated by the user. + + \warning This function supports only AF_INET and AF_INET6 address families. +*/ +static void +daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout) +{ + memset(sockaddrout, 0, sizeof(struct sockaddr_storage)); + + // There can be the case in which the sockaddrin is not available + if (sockaddrin == NULL) return; + + // Warning: we support only AF_INET and AF_INET6 + // + // Note: as noted above, the output structures are not + // neatly aligned on 4-byte boundaries, so we must fill + // in an aligned structure and then copy it to the output + // buffer with memcpy(). + switch (sockaddrin->ss_family) + { + case AF_INET: + { + struct sockaddr_in *sockaddrin_ipv4; + struct rpcap_sockaddr_in sockaddrout_ipv4; + + sockaddrin_ipv4 = (struct sockaddr_in *) sockaddrin; + + sockaddrout_ipv4.family = htons(RPCAP_AF_INET); + sockaddrout_ipv4.port = htons(sockaddrin_ipv4->sin_port); + memcpy(&sockaddrout_ipv4.addr, &sockaddrin_ipv4->sin_addr, sizeof(sockaddrout_ipv4.addr)); + memset(sockaddrout_ipv4.zero, 0, sizeof(sockaddrout_ipv4.zero)); + memcpy(sockaddrout, &sockaddrout_ipv4, sizeof(struct rpcap_sockaddr_in)); + break; + } + +#ifdef AF_INET6 + case AF_INET6: + { + struct sockaddr_in6 *sockaddrin_ipv6; + struct rpcap_sockaddr_in6 sockaddrout_ipv6; + + sockaddrin_ipv6 = (struct sockaddr_in6 *) sockaddrin; + + sockaddrout_ipv6.family = htons(RPCAP_AF_INET6); + sockaddrout_ipv6.port = htons(sockaddrin_ipv6->sin6_port); + sockaddrout_ipv6.flowinfo = htonl(sockaddrin_ipv6->sin6_flowinfo); + memcpy(&sockaddrout_ipv6.addr, &sockaddrin_ipv6->sin6_addr, sizeof(sockaddrout_ipv6.addr)); + sockaddrout_ipv6.scope_id = htonl(sockaddrin_ipv6->sin6_scope_id); + memcpy(sockaddrout, &sockaddrout_ipv6, sizeof(struct rpcap_sockaddr_in6)); + break; + } +#endif + } +} + + +/*! + \brief Suspends a thread for secs seconds. +*/ +void sleep_secs(int secs) +{ +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +#ifdef _WIN32 + Sleep(secs*1000); +#else + unsigned secs_remaining; + + if (secs <= 0) + return; + secs_remaining = secs; + while (secs_remaining != 0) + secs_remaining = sleep(secs_remaining); +#endif +#endif +} + +/* + * Read the header of a message. + */ +static int +rpcapd_recv_msg_header(PCAP_SOCKET sock, SSL *ssl, struct rpcap_header *headerp) +{ + int nread; + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + + nread = sock_recv(sock, ssl, (char *) headerp, sizeof(struct rpcap_header), + SOCK_RECEIVEALL_YES|SOCK_EOF_ISNT_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + if (nread == 0) + { + // Immediate EOF; that's treated like a close message. + return -2; + } + headerp->plen = ntohl(headerp->plen); + return 0; +} + +/* + * Read data from a message. + * If we're trying to read more data that remains, puts an error + * message into errmsgbuf and returns -2. Otherwise, tries to read + * the data and, if that succeeds, subtracts the amount read from + * the number of bytes of data that remains. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int +rpcapd_recv(PCAP_SOCKET sock, SSL *ssl, char *buffer, size_t toread, uint32 *plen, char *errmsgbuf) +{ + int nread; + char errbuf[PCAP_ERRBUF_SIZE]; // buffer for network errors + + if (toread > *plen) + { + // Tell the client and continue. + snprintf(errmsgbuf, PCAP_ERRBUF_SIZE, "Message payload is too short"); + return -2; + } + nread = sock_recv(sock, ssl, buffer, toread, + SOCK_RECEIVEALL_YES|SOCK_EOF_IS_ERROR, errbuf, PCAP_ERRBUF_SIZE); + if (nread == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + *plen -= nread; + return 0; +} + +/* + * Discard data from a connection. + * Mostly used to discard wrong-sized messages. + * Returns 0 on success, logs a message and returns -1 on a network + * error. + */ +static int +rpcapd_discard(PCAP_SOCKET sock, SSL *ssl, uint32 len) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + if (len != 0) + { + if (sock_discard(sock, ssl, len, errbuf, PCAP_ERRBUF_SIZE) == -1) + { + // Network error. + rpcapd_log(LOGPRIO_ERROR, "Read from client failed: %s", errbuf); + return -1; + } + } + return 0; +} + +// +// Shut down any packet-capture thread associated with the session, +// close the SSL handle for the data socket if we have one, close +// the data socket if we have one, and close the underlying packet +// capture handle if we have one. +// +// We do not, of course, touch the controlling socket that's also +// copied into the session, as the service loop might still use it. +// +static void session_close(struct session *session) +{ + if (session->have_thread) + { + // + // Tell the data connection thread main capture loop to + // break out of that loop. + // + // This may be sufficient to wake up a blocked thread, + // but it's not guaranteed to be sufficient. + // + pcap_breakloop(session->fp); + +#ifdef _WIN32 + // + // Set the event on which a read would block, so that, + // if it's currently blocked waiting for packets to + // arrive, it'll wake up, so it can see the "break + // out of the loop" indication. (pcap_breakloop() + // might do this, but older versions don't. Setting + // it twice should, at worst, cause an extra wakeup, + // which shouldn't be a problem.) + // + // XXX - what about modules other than NPF? + // + SetEvent(pcap_getevent(session->fp)); + + // + // Wait for the thread to exit, so we don't close + // sockets out from under it. + // + // XXX - have a timeout, so we don't wait forever? + // + WaitForSingleObject(session->thread, INFINITE); + + // + // Release the thread handle, as we're done with + // it. + // + CloseHandle(session->thread); + session->have_thread = 0; + session->thread = INVALID_HANDLE_VALUE; +#else + // + // Send a SIGUSR1 signal to the thread, so that, if + // it's currently blocked waiting for packets to arrive, + // it'll wake up (we've turned off SA_RESTART for + // SIGUSR1, so that the system call in which it's blocked + // should return EINTR rather than restarting). + // + pthread_kill(session->thread, SIGUSR1); + + // + // Wait for the thread to exit, so we don't close + // sockets out from under it. + // + // XXX - have a timeout, so we don't wait forever? + // + pthread_join(session->thread, NULL); + session->have_thread = 0; + memset(&session->thread, 0, sizeof(session->thread)); +#endif + } + +#ifdef HAVE_OPENSSL + if (session->data_ssl) + { + // Finish using the SSL handle for the socket. + // This must be done *before* the socket is closed. + ssl_finish(session->data_ssl); + session->data_ssl = NULL; + } +#endif + + if (session->sockdata != INVALID_SOCKET) + { + sock_close(session->sockdata, NULL, 0); + session->sockdata = INVALID_SOCKET; + } + + if (session->fp) + { + pcap_close(session->fp); + session->fp = NULL; + } +} + +// +// Check whether a capture source string is a URL or not. +// This includes URLs that refer to a local device; a scheme, followed +// by ://, followed by *another* scheme and ://, is just silly, and +// anybody who supplies that will get an error. +// +static int +is_url(const char *source) +{ + char *colonp; + + /* + * RFC 3986 says: + * + * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * Step 1: look for the ":" at the end of the scheme. + * A colon in the source is *NOT* sufficient to indicate that + * this is a URL, as interface names on some platforms might + * include colons (e.g., I think some Solaris interfaces + * might). + */ + colonp = strchr(source, ':'); + if (colonp == NULL) + { + /* + * The source is the device to open. It's not a URL. + */ + return (0); + } + + /* + * All schemes must have "//" after them, i.e. we only support + * hier-part = "//" authority path-abempty, not + * hier-part = path-absolute + * hier-part = path-rootless + * hier-part = path-empty + * + * We need that in order to distinguish between a local device + * name that happens to contain a colon and a URI. + */ + if (strncmp(colonp + 1, "//", 2) != 0) + { + /* + * The source is the device to open. It's not a URL. + */ + return (0); + } + + /* + * It's a URL. + */ + return (1); +} diff --git a/src/libpcap-1.10.5/rpcapd/daemon.h b/src/libpcap-1.10.5/rpcapd/daemon.h new file mode 100644 index 0000000000..79cd384846 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/daemon.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __DAEMON_H__ +#define __DAEMON_H__ + +#include + +#include "sslutils.h" + +// +// Returns 1 if the client closed the control connection explicitly, 0 +// otherwise; the return value is used only by callers that call us +// for active mode. +// +int daemon_serviceloop(PCAP_SOCKET sockctrl, int isactive, char *passiveClients, + int nullAuthAllowed, int uses_ssl); + +void sleep_secs(int secs); + +#endif diff --git a/src/libpcap-1.10.5/rpcapd/fileconf.c b/src/libpcap-1.10.5/rpcapd/fileconf.c new file mode 100644 index 0000000000..853b40996b --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/fileconf.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "ftmacros.h" + +#include +#include +#include +#include // for PCAP_ERRBUF_SIZE + +#include "portability.h" +#include "rpcapd.h" +#include "config_params.h" // configuration file parameters +#include "fileconf.h" +#include "rpcap-protocol.h" +#include "log.h" + +// +// Parameter names. +// +#define PARAM_ACTIVECLIENT "ActiveClient" +#define PARAM_PASSIVECLIENT "PassiveClient" +#define PARAM_NULLAUTHPERMIT "NullAuthPermit" + +static char *skipws(char *ptr); + +/* + * Locale-independent version checks for alphabetical and alphanumerical + * characters that also can handle being handed a char value that might + * be negative. + */ +#define FILECONF_ISALPHA(c) \ + (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) +#define FILECONF_ISALNUM(c) \ + (FILECONF_ISALPHA(c) || ((c) >= '0' && (c) <= '9')) + +void fileconf_read(void) +{ + FILE *fp; + unsigned int num_active_clients; + + if ((fp = fopen(loadfile, "r")) != NULL) + { + char line[MAX_LINE + 1]; + unsigned int lineno; + + hostlist[0] = 0; + num_active_clients = 0; + lineno = 0; + + while (fgets(line, MAX_LINE, fp) != NULL) + { + size_t linelen; + char *ptr; + char *param; + size_t result; + size_t toklen; + + lineno++; + + linelen = strlen(line); + if (line[linelen - 1] != '\n') + { + int c; + + // + // Either the line doesn't fit in + // the buffer, or we got an EOF + // before the EOL. Assume it's the + // former. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u is longer than %u characters", + loadfile, lineno, MAX_LINE); + + // + // Eat characters until we get an NL. + // + while ((c = getc(fp)) != '\n') + { + if (c == EOF) + goto done; + } + + // + // Try the next line. + // + continue; + } + ptr = line; + + // + // Skip leading white space, if any. + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // Blank line. + continue; + } + + // + // Is the next character a "#"? If so, this + // line is a comment; skip to the next line. + // + if (*ptr == '#') + continue; + + // + // Is the next character alphabetic? If not, + // this isn't a valid parameter name. + // + if (FILECONF_ISALPHA(*ptr)) + { + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u doesn't have a valid parameter name", + loadfile, lineno); + continue; + } + + // + // Grab the first token, which is made of + // alphanumerics, underscores, and hyphens. + // That's the name of the parameter being set. + // + param = ptr; + while (FILECONF_ISALNUM(*ptr) || *ptr == '-' || *ptr == '_') + ptr++; + + // + // Skip over white space, if any. + // + ptr = skipws(ptr); + if (ptr == NULL || *ptr != '=') + { + // + // We hit the end of the line before + // finding a non-white space character, + // or we found one but it's not an "=". + // That means there's no "=", so this + // line is invalid. Complain and skip + // this line. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no =", + loadfile, lineno); + continue; + } + + // + // We found the '='; set it to '\0', and skip + // past it. + // + *ptr++ = '\0'; + + // + // Skip past any white space after the "=". + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // + // The value is empty. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + + // + // OK, what parameter is this? + // + if (strcmp(param, PARAM_ACTIVECLIENT) == 0) { + // + // Add this to the list of active clients. + // + char *address, *port; + + // + // We can't have more than MAX_ACTIVE_LIST + // active clients. + // + if (num_active_clients >= MAX_ACTIVE_LIST) + { + // + // Too many entries for the active + // client list. Complain and + // ignore it. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter, but we already have %u active clients", + loadfile, lineno, PARAM_ACTIVECLIENT, + MAX_ACTIVE_LIST); + continue; + } + + // + // Get the address. + // It's terminated by a host list separator + // *or* a #; there *shouldn't* be a #, as + // that starts a comment, and that would + // mean that we have no port. + // + address = ptr; + toklen = strcspn(ptr, RPCAP_HOSTLIST_SEP "#"); + ptr += toklen; // skip to the terminator + if (toklen == 0) + { + if (*ptr == ' ' || *ptr == '\t' || + *ptr == '\r' || *ptr == '\n' || + *ptr == '#' || *ptr == '\0') + { + // + // The first character it saw + // was a whitespace character + // or a comment character, + // or we ran out of characters. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + } + else + { + // + // This means that the first + // character it saw was a + // separator. This means that + // there's no address in the + // value, just a port. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no address", + loadfile, lineno, PARAM_ACTIVECLIENT); + } + continue; + } + + // + // Null-terminate the address, and skip past + // it. + // + *ptr++ = '\0'; + + // + // Skip any white space following the + // separating character. + // + ptr = skipws(ptr); + if (ptr == NULL) + { + // + // The value is empty, so there's + // no port in the value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no port", + loadfile, lineno, PARAM_ACTIVECLIENT); + continue; + } + + // + // Get the port. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + port = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + ptr += toklen; + if (toklen == 0) + { + // + // The value is empty, so there's + // no port in the value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with a value containing no port", + loadfile, lineno, PARAM_ACTIVECLIENT); + continue; + } + + // + // Null-terminate the port, and skip past + // it. + // + *ptr++ = '\0'; + result = pcapint_strlcpy(activelist[num_active_clients].address, address, sizeof(activelist[num_active_clients].address)); + if (result >= sizeof(activelist[num_active_clients].address)) + { + // + // It didn't fit. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with an address with more than %u characters", + loadfile, lineno, PARAM_ACTIVECLIENT, + (unsigned int)(sizeof(activelist[num_active_clients].address) - 1)); + continue; + } + if (strcmp(port, "DEFAULT") == 0) // the user choose a custom port + result = pcapint_strlcpy(activelist[num_active_clients].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof(activelist[num_active_clients].port)); + else + result = pcapint_strlcpy(activelist[num_active_clients].port, port, sizeof(activelist[num_active_clients].port)); + if (result >= sizeof(activelist[num_active_clients].address)) + { + // + // It didn't fit. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an %s parameter with an port with more than %u characters", + loadfile, lineno, PARAM_ACTIVECLIENT, + (unsigned int)(sizeof(activelist[num_active_clients].port) - 1)); + continue; + } + + num_active_clients++; + } + else if (strcmp(param, PARAM_PASSIVECLIENT) == 0) + { + char *eos; + char *host; + + // + // Get the host. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + host = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + if (toklen == 0) + { + // + // The first character it saw + // was a whitespace character + // or a comment character. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + ptr += toklen; + *ptr++ = '\0'; + + // + // Append this to the host list. + // Save the current end-of-string for the + // host list, in case the new host doesn't + // fit, so that we can discard the partially- + // copied host name. + // + eos = hostlist + strlen(hostlist); + if (eos != hostlist) + { + // + // The list is not empty, so prepend + // a comma before adding this host. + // + result = pcapint_strlcat(hostlist, ",", sizeof(hostlist)); + if (result >= sizeof(hostlist)) + { + // + // It didn't fit. Discard + // the comma (which wasn't + // added, but...), complain, + // and ignore this line. + // + *eos = '\0'; + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a %s parameter with a host name that doesn't fit", + loadfile, lineno, PARAM_PASSIVECLIENT); + continue; + } + } + result = pcapint_strlcat(hostlist, host, sizeof(hostlist)); + if (result >= sizeof(hostlist)) + { + // + // It didn't fit. Discard the comma, + // complain, and ignore this line. + // + *eos = '\0'; + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a %s parameter with a host name that doesn't fit", + loadfile, lineno, PARAM_PASSIVECLIENT); + continue; + } + } + else if (strcmp(param, PARAM_NULLAUTHPERMIT) == 0) + { + char *setting; + + // + // Get the setting. + // We look for a white space character + // or a # as a terminator; the # introduces + // a comment that runs to the end of the + // line. + // + setting = ptr; + toklen = strcspn(ptr, " \t#\r\n"); + ptr += toklen; + if (toklen == 0) + { + // + // The first character it saw + // was a whitespace character + // or a comment character. + // This means that there's + // no value. + // + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has a parameter but no value", + loadfile, lineno); + continue; + } + *ptr++ = '\0'; + + // + // XXX - should we complain if it's + // neither "yes" nor "no"? + // + if (strcmp(setting, "YES") == 0) + nullAuthAllowed = 1; + else + nullAuthAllowed = 0; + } + else + { + rpcapd_log(LOGPRIO_ERROR, + "%s, line %u has an unknown parameter %s", + loadfile, lineno, param); + continue; + } + } + +done: + // clear the remaining fields of the active list + for (int i = num_active_clients; i < MAX_ACTIVE_LIST; i++) + { + activelist[i].address[0] = 0; + activelist[i].port[0] = 0; + num_active_clients++; + } + + rpcapd_log(LOGPRIO_DEBUG, "New passive host list: %s", hostlist); + fclose(fp); + } +} + +int fileconf_save(const char *savefile) +{ + FILE *fp; + + if ((fp = fopen(savefile, "w")) != NULL) + { + char *token; /*, *port;*/ // temp, needed to separate items into the hostlist + char temphostlist[MAX_HOST_LIST + 1]; + int i = 0; + char *lasts; + + fprintf(fp, "# Configuration file help.\n\n"); + + // Save list of clients which are allowed to connect to us in passive mode + fprintf(fp, "# Hosts which are allowed to connect to this server (passive mode)\n"); + fprintf(fp, "# Format: PassiveClient = \n\n"); + + pcapint_strlcpy(temphostlist, hostlist, sizeof (temphostlist)); + + token = pcapint_strtok_r(temphostlist, RPCAP_HOSTLIST_SEP, &lasts); + while(token != NULL) + { + fprintf(fp, "%s = %s\n", PARAM_PASSIVECLIENT, token); + token = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + } + + + // Save list of clients which are allowed to connect to us in active mode + fprintf(fp, "\n\n"); + fprintf(fp, "# Hosts to which this server is trying to connect to (active mode)\n"); + fprintf(fp, "# Format: ActiveClient = , \n\n"); + + + while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0)) + { + fprintf(fp, "%s = %s, %s\n", PARAM_ACTIVECLIENT, + activelist[i].address, activelist[i].port); + i++; + } + + // Save if we want to permit NULL authentication + fprintf(fp, "\n\n"); + fprintf(fp, "# Permit NULL authentication: YES or NO\n\n"); + + fprintf(fp, "%s = %s\n", PARAM_NULLAUTHPERMIT, + nullAuthAllowed ? "YES" : "NO"); + + fclose(fp); + return 0; + } + else + { + return -1; + } + +} + +// +// Skip over white space. +// If we hit a CR or LF, return NULL, otherwise return a pointer to +// the first non-white space character. Replace white space characters +// other than CR or LF with '\0', so that, if we're skipping white space +// after a token, the token is null-terminated. +// +static char *skipws(char *ptr) +{ + while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') { + if (*ptr == '\r' || *ptr == '\n') + return NULL; + *ptr++ = '\0'; + } + return ptr; +} diff --git a/src/libpcap-1.10.5/rpcapd/fileconf.h b/src/libpcap-1.10.5/rpcapd/fileconf.h new file mode 100644 index 0000000000..912dd3264c --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/fileconf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __FILECONF_H__ +#define __FILECONF_H__ + +void fileconf_read(void); +int fileconf_save(const char *savefile); + +#endif diff --git a/src/libpcap-1.10.5/rpcapd/log.c b/src/libpcap-1.10.5/rpcapd/log.c new file mode 100644 index 0000000000..71668a195b --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/log.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "portability.h" + +#include "log.h" + +static int log_to_systemlog; +static int log_debug_messages; + +static void rpcapd_vlog_stderr(log_priority, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0); + +static void rpcapd_vlog_stderr(log_priority priority, const char *message, va_list ap) +{ + const char *tag; + + /* + * Squelch warnings from compilers that *don't* assume that + * priority always has a valid enum value and therefore don't + * assume that we'll always go through one of the case arms. + * + * If we have a default case, compilers that *do* assume that + * will then complain about the default case code being + * unreachable. + * + * Damned if you do, damned if you don't. + */ + tag = ""; + + switch (priority) { + + case LOGPRIO_DEBUG: + tag = "DEBUG: "; + break; + + case LOGPRIO_INFO: + tag = ""; + break; + + case LOGPRIO_WARNING: + tag = "warning: "; + break; + + case LOGPRIO_ERROR: + tag = "error: "; + break; + } + + fprintf(stderr, "rpcapd: %s", tag); + vfprintf(stderr, message, ap); + putc('\n', stderr); +} + +static void rpcapd_vlog_systemlog(log_priority, + PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0); + +#ifdef _WIN32 +#define MESSAGE_SUBKEY \ + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\rpcapd" + +static void rpcapd_vlog_systemlog(log_priority priority, const char *message, + va_list ap) +{ +#if 0 + static int initialized = 0; + HKEY hey_handle; + static HANDLE log_handle; + WORD eventlog_type; + DWORD event_id; + char msgbuf[1024]; + char *strings[1]; + + if (!initialized) { + /* + * Register our message stuff in the Registry. + * + * First, create the registry key for us. If the key + * already exists, this succeeds and returns a handle + * for it. + */ + if (RegCreateKey(HKEY_LOCAL_MACHINE, MESSAGE_SUBKEY, + &key_handle) != ERROR_SUCCESS) { + /* + * Failed - give up and just log this message, + * and all subsequent messages, to the + * standard error. + */ + log_to_systemlog = 0; + initialized = 1; + rpcapd_vlog_stderr(priority, message, ap); + return; + } + log_handle = RegisterEventSource(NULL, "rpcapd"); + initialized = 1; + } + + switch (priority) { + + case LOGPRIO_DEBUG: + // + // XXX - what *should* we do about debug messages? + // + eventlog_type = EVENTLOG_INFORMATION_TYPE; + event_id = RPCAPD_INFO_ID; + break; + + case LOGPRIO_INFO: + eventlog_type = EVENTLOG_INFORMATION_TYPE; + event_id = RPCAPD_INFO_ID; + break; + + case LOGPRIO_WARNING: + eventlog_type = EVENTLOG_WARNING_TYPE; + event_id = RPCAPD_WARNING_ID; + break; + + case LOGPRIO_ERROR: + eventlog_type = EVENTLOG_ERROR_TYPE; + event_id = RPCAPD_ERROR_ID; + break; + + default: + /* Don't do this. */ + return; + } + + vsprintf(msgbuf, message, ap); + + strings[0] = msgbuf; + /* + * If this fails, how are we going to report it? + */ + (void) ReportEvent(log_handle, eventlog_type, 0, event_id, NULL, 1, 0, + strings, NULL); +#else + rpcapd_vlog_stderr(priority, message, ap); +#endif +} +#else +static void rpcapd_vlog_systemlog(log_priority priority, const char *message, + va_list ap) +{ + static int initialized = 0; + int syslog_priority; + + if (!initialized) { + // + // Open the log. + // + openlog("rpcapd", LOG_PID, LOG_DAEMON); + initialized = 1; + } + + switch (priority) { + + case LOGPRIO_DEBUG: + syslog_priority = LOG_DEBUG; + break; + + case LOGPRIO_INFO: + syslog_priority = LOG_INFO; + break; + + case LOGPRIO_WARNING: + syslog_priority = LOG_WARNING; + break; + + case LOGPRIO_ERROR: + syslog_priority = LOG_ERR; + break; + + default: + /* Don't do this. */ + return; + } + +#ifdef HAVE_VSYSLOG + vsyslog(syslog_priority, message, ap); +#else + /* + * Thanks, IBM, for not providing vsyslog() in AIX! + * + * They also warn that the syslog functions shouldn't + * be used in multithreaded programs, but the only thing + * obvious that seems to make the syslog_r functions + * better is that they have an additional argument + * that points to the information that's static to + * the syslog code in non-thread-safe versions. Most + * of that data is set by openlog(); since we already + * do an openlog before doing logging, and don't + * change that data afterwards, I suspect that, in + * practice, the regular syslog routines are OK for + * us (especially given that we'd end up having one + * static struct syslog_data anyway, which means we'd + * just be like the non-thread-safe version). + */ + char logbuf[1024+1]; + + vsnprintf(logbuf, sizeof logbuf, message, ap); + syslog(syslog_priority, "%s", logbuf); +#endif +} +#endif + +void rpcapd_log_set(int log_to_systemlog_arg, int log_debug_messages_arg) +{ + log_debug_messages = log_debug_messages_arg; + log_to_systemlog = log_to_systemlog_arg; +} + +void rpcapd_log(log_priority priority, const char *message, ...) +{ + va_list ap; + + if (priority != LOGPRIO_DEBUG || log_debug_messages) { + va_start(ap, message); + if (log_to_systemlog) + { + rpcapd_vlog_systemlog(priority, message, ap); + } + else + { + rpcapd_vlog_stderr(priority, message, ap); + } + va_end(ap); + } +} diff --git a/src/libpcap-1.10.5/rpcapd/log.h b/src/libpcap-1.10.5/rpcapd/log.h new file mode 100644 index 0000000000..28a6cee0ae --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/log.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "pcap/funcattrs.h" + +extern void rpcapd_log_set(int, int); + +typedef enum { + LOGPRIO_DEBUG, + LOGPRIO_INFO, + LOGPRIO_WARNING, + LOGPRIO_ERROR +} log_priority; + +extern void rpcapd_log(log_priority priority, + PCAP_FORMAT_STRING(const char *message), ...) PCAP_PRINTFLIKE(2, 3); diff --git a/src/libpcap-1.10.5/rpcapd/org.tcpdump.rpcapd.plist b/src/libpcap-1.10.5/rpcapd/org.tcpdump.rpcapd.plist new file mode 100644 index 0000000000..c485787552 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/org.tcpdump.rpcapd.plist @@ -0,0 +1,30 @@ + + + + + Disabled + + Label + org.tcpdump.rpcapd + Program + /usr/local/libexec/rpcapd + ProgramArguments + + /usr/local/libexec/rpcapd + -i + + Sockets + + Listeners + + SockServiceName + 2002 + + + inetdCompatibility + + Wait + + + + diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd-config.manfile.in b/src/libpcap-1.10.5/rpcapd/rpcapd-config.manfile.in new file mode 100644 index 0000000000..dd0c91e165 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd-config.manfile.in @@ -0,0 +1,82 @@ +.\" Copyright (c) 1994, 1996, 1997 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that: (1) source code distributions +.\" retain the above copyright notice and this paragraph in its entirety, (2) +.\" distributions including binary code include the above copyright notice and +.\" this paragraph in its entirety in the documentation or other materials +.\" provided with the distribution, and (3) all advertising materials mentioning +.\" features or use of this software display the following acknowledgement: +.\" ``This product includes software developed by the University of California, +.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +.\" the University nor the names of its contributors may be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.TH RPCAPD-CONFIG @MAN_FILE_FORMATS@ "6 January 2019" +.SH NAME +rpcapd-config \- rpcapd configuration file format +.SH DESCRIPTION +An +.I rpcapd +configuration file allows parameters to be set for +.BR rpcapd (@MAN_ADMIN_COMMANDS@). +.LP +A +.B # +introduces a comment that runs to the end of the line. Blank lines, +and lines with only a comment, are ignored. Leading and trailing white +space on a line are also ignored. +.LP +Lines that set a parameter are of the form +.IP +\fIparameter\fB=\fIvalue\fR +.LP +Whitespace preceding or following the +.B = +is ignored. +.LP +The +.IR parameter s +are: +.TP +.B ActiveClient +.I value +is a host name or IP address, followed by a comma, +semicolon, or space, followed by a port name and address or +.BR DEFAULT . +.B DEFAULT +specifies the default active mode port for rpcapd, port 2003. +Each +.B ActiveClient +line adds the host and port to the list of clients to which the server +should connect in active mode. +.TP +.B PassiveClient +.I value +is a host name or IP address, followed by a comma, +semicolon, or space, followed by a port name and address or +.BR DEFAULT . +.B DEFAULT +specifies the default passive mode port for rpcapd, port 2002. +Each +.B PassiveClient +line adds the host and port to the list of clients addresses and ports +that are allowed to connect to the server in passive mode. +.TP +.B NullAuthPermit +.I value +is either +.B YES +or +.BR NO . +.B YES +means that null authentication is permitted; +.B NO +means that it is not permitted. +.SH SEE ALSO +.BR rpcapd (@MAN_ADMIN_COMMANDS@) diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.c b/src/libpcap-1.10.5/rpcapd/rpcapd.c new file mode 100644 index 0000000000..4ab11d8ac3 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.c @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "ftmacros.h" +#include "diag-control.h" + +#include // for the errno variable +#include // for strtok, etc +#include // for malloc(), free(), ... +#include // for fprintf(), stderr, FILE etc +#include // for PCAP_ERRBUF_SIZE +#include // for signal() + +#include "fmtutils.h" +#include "sockutils.h" // for socket calls +#include "varattrs.h" // for _U_ +#include "portability.h" +#include "rpcapd.h" +#include "config_params.h" // configuration file parameters +#include "fileconf.h" // for the configuration file management +#include "rpcap-protocol.h" +#include "daemon.h" // the true main() method of this daemon +#include "log.h" + +#ifdef HAVE_OPENSSL +#include "sslutils.h" +#endif + +#ifdef _WIN32 + #include // for thread stuff + #include "win32-svc.h" // for Win32 service stuff + #include "getopt.h" // for getopt()-for-Windows +#else + #include // for open() + #include // for exit() + #include // waitpid() +#endif + +// +// Element in list of sockets on which we're listening for connections. +// +struct listen_sock { + struct listen_sock *next; + PCAP_SOCKET sock; +}; + +// Global variables +char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server +struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode) +int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise +static struct listen_sock *listen_socks; //!< sockets on which we listen +char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration +static int passivemode = 1; //!< '1' if we want to run in passive mode as well +static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket +static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to +static char port[MAX_LINE + 1]; //!< keeps the network port to bind to +#ifdef _WIN32 +static HANDLE state_change_event; //!< event to signal that a state change should take place +#endif +static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down +static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration +static int uses_ssl; //!< '1' to use TLS over TCP + +extern char *optarg; // for getopt() + +// Function definition +#ifdef _WIN32 +static unsigned __stdcall main_active(void *ptr); +static BOOL WINAPI main_ctrl_event(DWORD); +#else +static void *main_active(void *ptr); +static void main_terminate(int sign); +static void main_reread_config(int sign); +#endif +static void accept_connections(void); +static void accept_connection(PCAP_SOCKET listen_sock); +#ifndef _WIN32 +static void main_reap_children(int sign); +#endif +#ifdef _WIN32 +static unsigned __stdcall main_passive_serviceloop_thread(void *ptr); +#endif + +#define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */ + +/*! + \brief Prints the usage screen if it is launched in console mode. +*/ +static void printusage(FILE * f) +{ + const char *usagetext = + "USAGE:" + " " PROGRAM_NAME " [-b
] [-p ] [-4] [-l ] [-a ]\n" + " [-n] [-v] [-d] " +#ifndef _WIN32 + "[-i] " +#endif + "[-D] [-s ] [-f ]\n\n" + " -b
the address to bind to (either numeric or literal).\n" + " Default: binds to all local IPv4 and IPv6 addresses\n\n" + " -p the port to bind to.\n" + " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n" + " -4 use only IPv4.\n" + " Default: use both IPv4 and IPv6 waiting sockets\n\n" + " -l a file that contains a list of hosts that are allowed\n" + " to connect to this server (if more than one, list them one\n" + " per line).\n" + " We suggest to use literal names (instead of numeric ones)\n" + " in order to avoid problems with different address families.\n\n" + " -n permit NULL authentication (usually used with '-l')\n\n" + " -a run in active mode when connecting to 'host' on port 'port'\n" + " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n" + " -v run in active mode only (default: if '-a' is specified, it\n" + " accepts passive connections as well)\n\n" + " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n" + " Warning (Win32): this switch is provided automatically when\n" + " the service is started from the control panel\n\n" +#ifndef _WIN32 + " -i run in inetd mode (UNIX only)\n\n" +#endif + " -D log debugging messages\n\n" +#ifdef HAVE_OPENSSL + " -S encrypt all communication with SSL (implements rpcaps://)\n" + " -C enable compression\n" + " -K uses the SSL private key in this file (default: key.pem)\n" + " -X uses the certificate from this file (default: cert.pem)\n" +#endif + " -s save the current configuration to file\n\n" + " -f load the current configuration from file; all switches\n" + " specified from the command line are ignored\n\n" + " -h print this help screen\n\n"; + + (void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n" + "Compiled with %s\n", pcap_lib_version()); +#if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION) + (void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION)); +#endif + (void)fprintf(f, "\n%s", usagetext); +} + + + +//! Program main +int main(int argc, char *argv[]) +{ + char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration + int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error + int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon +#ifndef _WIN32 + int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like +#endif + int log_debug_messages = 0; // Non-zero if the user wants debug messages logged + int retval; // keeps the returning value from several functions + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed +#ifndef _WIN32 + struct sigaction action; +#endif +#ifdef HAVE_OPENSSL + int enable_compression = 0; +#endif + + savefile[0] = 0; + loadfile[0] = 0; + hostlist[0] = 0; + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + pcapint_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address)); + pcapint_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port)); + + // Prepare to open a new server socket + memset(&mainhints, 0, sizeof(struct addrinfo)); + + mainhints.ai_family = PF_UNSPEC; + mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket + mainhints.ai_socktype = SOCK_STREAM; + + // Getting the proper command line options +# ifdef HAVE_OPENSSL +# define SSL_CLOPTS "SK:X:C" +# else +# define SSL_CLOPTS "" +# endif + +# define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS + + while ((retval = getopt(argc, argv, CLOPTS)) != -1) + { + switch (retval) + { + case 'D': + log_debug_messages = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); + break; + case 'b': + pcapint_strlcpy(address, optarg, sizeof (address)); + break; + case 'p': + pcapint_strlcpy(port, optarg, sizeof (port)); + break; + case '4': + mainhints.ai_family = PF_INET; // IPv4 server only + break; + case 'd': + isdaemon = 1; + log_to_systemlog = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); + break; + case 'i': +#ifdef _WIN32 + printusage(stderr); + exit(1); +#else + isrunbyinetd = 1; + log_to_systemlog = 1; + rpcapd_log_set(log_to_systemlog, log_debug_messages); +#endif + break; + case 'n': + nullAuthAllowed = 1; + break; + case 'v': + passivemode = 0; + break; + case 'l': + { + pcapint_strlcpy(hostlist, optarg, sizeof(hostlist)); + break; + } + case 'a': + { + char *tmpaddress, *tmpport; + char *lasts; + int i = 0; + + tmpaddress = pcapint_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts); + + while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST)) + { + tmpport = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + + pcapint_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address)); + + if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port + pcapint_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port)); + else + pcapint_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port)); + + tmpaddress = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts); + + i++; + } + + if (i > MAX_ACTIVE_LIST) + rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported."); + + // I don't initialize the remaining part of the structure, since + // it is already zeroed (it is a global var) + break; + } + case 'f': + pcapint_strlcpy(loadfile, optarg, sizeof (loadfile)); + break; + case 's': + pcapint_strlcpy(savefile, optarg, sizeof (savefile)); + break; +#ifdef HAVE_OPENSSL + case 'S': + uses_ssl = 1; + break; + case 'C': + enable_compression = 1; + break; + case 'K': + ssl_set_keyfile(optarg); + break; + case 'X': + ssl_set_certfile(optarg); + break; +#endif + case 'h': + printusage(stdout); + exit(0); + /*NOTREACHED*/ + default: + exit(1); + /*NOTREACHED*/ + } + } + +#ifndef _WIN32 + if (isdaemon && isrunbyinetd) + { + rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together"); + exit(1); + } +#endif + + // + // We want UTF-8 error messages. + // + if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(-1); + } + pcapint_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8); + + if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) + { + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(-1); + } + + if (savefile[0] && fileconf_save(savefile)) + rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file"); + + // If the file does not exist, it keeps the settings provided by the command line + if (loadfile[0]) + fileconf_read(); + +#ifdef _WIN32 + // + // Create a handle to signal the main loop to tell it to do + // something. + // + state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (state_change_event == NULL) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't create state change event"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + // + // Catch control signals. + // + if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE)) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't set control handler"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } +#else + memset(&action, 0, sizeof (action)); + action.sa_handler = main_terminate; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGTERM, &action, NULL); + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reap_children; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGCHLD, &action, NULL); + // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed + // connection, we don't want to get killed by a signal in that case +#ifdef __illumos__ + DIAG_OFF_STRICT_PROTOTYPES +#endif /* __illumos__ */ + signal(SIGPIPE, SIG_IGN); +#ifdef __illumos__ + DIAG_ON_STRICT_PROTOTYPES +#endif /* __illumos__ */ +#endif + +# ifdef HAVE_OPENSSL + if (uses_ssl) { + if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0) + { + rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s", + errbuf); + exit(2); + } + } +# endif + +#ifndef _WIN32 + if (isrunbyinetd) + { + // + // -i was specified, indicating that this is being run + // by inetd or something that can run network daemons + // as if it were inetd (xinetd, launchd, systemd, etc.). + // + // We assume that the program that launched us just + // duplicated a single socket for the connection + // to our standard input, output, and error, so we + // can just use the standard input as our control + // socket. + // + int sockctrl; + int devnull_fd; + + // + // Duplicate the standard input as the control socket. + // + sockctrl = dup(0); + if (sockctrl == -1) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't dup standard input"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + // + // Try to set the standard input, output, and error + // to /dev/null. + // + devnull_fd = open("/dev/null", O_RDWR); + if (devnull_fd != -1) + { + // + // If this fails, just drive on. + // + (void)dup2(devnull_fd, 0); + (void)dup2(devnull_fd, 1); + (void)dup2(devnull_fd, 2); + close(devnull_fd); + } + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + exit(0); + } + (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, + nullAuthAllowed, uses_ssl); + + // + // Nothing more to do. + // + exit(0); + } +#endif + + if (isdaemon) + { + // + // This is being run as a daemon. + // On UN*X, it might be manually run, or run from an + // rc file. + // +#ifndef _WIN32 + int pid; + + // + // Daemonize ourselves. + // + // Unix Network Programming, pg 336 + // + if ((pid = fork()) != 0) + exit(0); // Parent terminates + + // First child continues + // Set daemon mode + setsid(); + + // generated under unix with 'kill -HUP', needed to reload the configuration + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reread_config; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGHUP, &action, NULL); + + if ((pid = fork()) != 0) + exit(0); // First child terminates + + // LINUX WARNING: the current linux implementation of pthreads requires a management thread + // to handle some hidden stuff. So, as soon as you create the first thread, two threads are + // created. From this point on, the number of threads active are always one more compared + // to the number you're expecting + + // Second child continues +// umask(0); +// chdir("/"); +#else + // + // This is being run as a service on Windows. + // + // If this call succeeds, it is blocking on Win32 + // + if (!svc_start()) + rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service"); + + // When the previous call returns, the entire application has to be stopped. + exit(0); +#endif + } + else // Console mode + { +#ifndef _WIN32 + // Enable the catching of Ctrl+C + memset(&action, 0, sizeof (action)); + action.sa_handler = main_terminate; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGINT, &action, NULL); + + // generated under unix with 'kill -HUP', needed to reload the configuration + // We do not have this kind of signal in Win32 + memset(&action, 0, sizeof (action)); + action.sa_handler = main_reread_config; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaction(SIGHUP, &action, NULL); +#endif + + printf("Press CTRL + C to stop the server...\n"); + } + + // If we're a Win32 service, we have already called this function in the service_main + main_startup(); + + // The code should never arrive here (since the main_startup is blocking) + // however this avoids a compiler warning + exit(0); +} + +void main_startup(void) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket + int i; +#ifdef _WIN32 + HANDLE threadId; // handle for the subthread +#else + pid_t pid; +#endif + + i = 0; + addrinfo = NULL; + memset(errbuf, 0, sizeof(errbuf)); + + // Starts all the active threads + while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0)) + { + activelist[i].ai_family = mainhints.ai_family; + +#ifdef _WIN32 + threadId = (HANDLE)_beginthreadex(NULL, 0, main_active, + (void *)&activelist[i], 0, NULL); + if (threadId == 0) + { + rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads"); + continue; + } + CloseHandle(threadId); +#else + if ((pid = fork()) == 0) // I am the child + { + main_active((void *) &activelist[i]); + exit(0); + } +#endif + i++; + } + + /* + * The code that manages the active connections is not blocking; + * the code that manages the passive connection is blocking. + * So, if the user does not want to run in passive mode, we have + * to block the main thread here, otherwise the program ends and + * all threads are stopped. + * + * WARNING: this means that in case we have only active mode, + * the program does not terminate even if all the child thread + * terminates. The user has always to press Ctrl+C (or send a + * SIGTERM) to terminate the program. + */ + if (passivemode) + { + struct addrinfo *tempaddrinfo; + + // + // Get a list of sockets on which to listen. + // + addrinfo = sock_initaddress((address[0]) ? address : NULL, + port, &mainhints, errbuf, PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + return; + } + + for (tempaddrinfo = addrinfo; tempaddrinfo; + tempaddrinfo = tempaddrinfo->ai_next) + { + PCAP_SOCKET sock; + struct listen_sock *sock_info; + + if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + switch (tempaddrinfo->ai_family) + { + case AF_INET: + { + struct sockaddr_in *in; + char addrbuf[INET_ADDRSTRLEN]; + + in = (struct sockaddr_in *)tempaddrinfo->ai_addr; + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", + inet_ntop(AF_INET, &in->sin_addr, + addrbuf, sizeof (addrbuf)), + ntohs(in->sin_port), + errbuf); + break; + } + + case AF_INET6: + { + struct sockaddr_in6 *in6; + char addrbuf[INET6_ADDRSTRLEN]; + + in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr; + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s", + inet_ntop(AF_INET6, &in6->sin6_addr, + addrbuf, sizeof (addrbuf)), + ntohs(in6->sin6_port), + errbuf); + break; + } + + default: + rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s", + tempaddrinfo->ai_family, + errbuf); + break; + } + continue; + } + + sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock)); + if (sock_info == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket"); + exit(2); + } + sock_info->sock = sock; + sock_info->next = listen_socks; + listen_socks = sock_info; + } + + freeaddrinfo(addrinfo); + + if (listen_socks == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address"); + exit(2); + } + + // + // Now listen on all of them, waiting for connections. + // + accept_connections(); + } + + // + // We're done; exit. + // + rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n"); + +#ifndef _WIN32 + // + // Sends a KILL signal to all the processes in this process's + // process group; i.e., it kills all the child processes + // we've created. + // + // XXX - that also includes us, so we will be killed as well; + // that may cause a message to be printed or logged. + // + kill(0, SIGKILL); +#endif + + // + // Just leave. We shouldn't need to clean up sockets or + // anything else, and if we try to do so, we'll could end + // up closing sockets, or shutting Winsock down, out from + // under service loops, causing all sorts of noisy error + // messages. + // + // We shouldn't need to worry about cleaning up any resources + // such as handles, sockets, threads, etc. - exit() should + // terminate the process, causing all those resources to be + // cleaned up (including the threads; Microsoft claims in the + // ExitProcess() documentation that, if ExitProcess() is called, + // "If a thread is waiting on a kernel object, it will not be + // terminated until the wait has completed.", but claims in the + // _beginthread()/_beginthreadex() documentation that "All threads + // are terminated if any thread calls abort, exit, _exit, or + // ExitProcess." - the latter appears to be the case, even for + // threads waiting on the event for a pcap_t). + // + exit(0); +} + +#ifdef _WIN32 +static void +send_state_change_event(void) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + if (!SetEvent(state_change_event)) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "SetEvent on shutdown event failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + } +} + +void +send_shutdown_notification(void) +{ + // + // Indicate that the server should shut down. + // + shutdown_server = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + +void +send_reread_configuration_notification(void) +{ + // + // Indicate that the server should re-read its configuration file. + // + reread_config = 1; + + // + // Send a state change event, to wake up WSAWaitForMultipleEvents(). + // + send_state_change_event(); +} + +static BOOL WINAPI main_ctrl_event(DWORD ctrltype) +{ + // + // ctrltype is one of: + // + // CTRL_C_EVENT - we got a ^C; this is like SIGINT + // CTRL_BREAK_EVENT - we got Ctrl+Break + // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP + // CTRL_LOGOFF_EVENT - a user is logging off; this is received + // only by services + // CTRL_SHUTDOWN_EVENT - the system is shutting down; this is + // received only by services + // + // For now, we treat all but CTRL_LOGOFF_EVENT as indications + // that we should shut down. + // + switch (ctrltype) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_SHUTDOWN_EVENT: + // + // Set a shutdown notification. + // + send_shutdown_notification(); + break; + + default: + break; + } + + // + // We handled this. + // + return TRUE; +} +#else +static void main_terminate(int sign _U_) +{ + // + // Note that the server should shut down. + // select() should get an EINTR error when we return, + // so it will wake up and know it needs to check the flag. + // + shutdown_server = 1; +} + +static void main_reread_config(int sign _U_) +{ + // + // Note that the server should re-read its configuration file. + // select() should get an EINTR error when we return, + // so it will wake up and know it needs to check the flag. + // + reread_config = 1; +} + +static void main_reap_children(int sign _U_) +{ + pid_t pid; + int exitstat; + + // Reap all child processes that have exited. + // For reference, Stevens, pg 128 + + while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0) + rpcapd_log(LOGPRIO_DEBUG, "Child terminated"); + + return; +} +#endif + +// +// Loop waiting for incoming connections and accepting them. +// +static void +accept_connections(void) +{ +#ifdef _WIN32 + struct listen_sock *sock_info; + DWORD num_events; + WSAEVENT *events; + int i; + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + + // + // How big does the set of events need to be? + // One for the shutdown event, plus one for every socket on which + // we'll be listening. + // + num_events = 1; // shutdown event + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + if (num_events == WSA_MAXIMUM_WAIT_EVENTS) + { + // + // WSAWaitForMultipleEvents() doesn't support + // more than WSA_MAXIMUM_WAIT_EVENTS events + // on which to wait. + // + rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen"); + exit(2); + } + num_events++; + } + + // + // Allocate the array of events. + // + events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT)); + if (events == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen"); + exit(2); + } + + // + // Fill it in. + // + events[0] = state_change_event; // state change event first + for (sock_info = listen_socks, i = 1; sock_info; + sock_info = sock_info->next, i++) + { + WSAEVENT event; + + // + // Create an event that is signaled if there's a connection + // to accept on the socket in question. + // + event = WSACreateEvent(); + if (event == WSA_INVALID_EVENT) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't create socket event"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "Can't setup socket event"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + events[i] = event; + } + + for (;;) + { + // + // Wait for incoming connections. + // + DWORD ret; + + ret = WSAWaitForMultipleEvents(num_events, events, FALSE, + WSA_INFINITE, FALSE); + if (ret == WSA_WAIT_FAILED) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAWaitForMultipleEvents failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + + if (ret == WSA_WAIT_EVENT_0) + { + // + // The state change event was set. + // + if (shutdown_server) + { + // + // Time to quit. Exit the loop. + // + break; + } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); + } + } + + // + // Check each socket. + // + for (sock_info = listen_socks, i = 1; sock_info; + sock_info = sock_info->next, i++) + { + WSANETWORKEVENTS network_events; + + if (WSAEnumNetworkEvents(sock_info->sock, + events[i], &network_events) == SOCKET_ERROR) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAEnumNetworkEvents failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + exit(2); + } + if (network_events.lNetworkEvents & FD_ACCEPT) + { + // + // Did an error occur? + // + if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0) + { + // + // Yes - report it and keep going. + // + sock_fmterrmsg(errbuf, + PCAP_ERRBUF_SIZE, + network_events.iErrorCode[FD_ACCEPT_BIT], + "Socket error"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + continue; + } + + // + // Accept the connection. + // + accept_connection(sock_info->sock); + } + } + } +#else + struct listen_sock *sock_info; + int num_sock_fds; + + // + // How big does the bitset of sockets on which to select() have + // to be? + // + num_sock_fds = 0; + for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) + { + if (sock_info->sock + 1 > num_sock_fds) + { + if ((unsigned int)(sock_info->sock + 1) > + (unsigned int)FD_SETSIZE) + { + rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set"); + exit(2); + } + num_sock_fds = sock_info->sock + 1; + } + } + + for (;;) + { + fd_set sock_fds; + int ret; + + // + // Set up an fd_set for all the sockets on which we're + // listening. + // + // This set is modified by select(), so we have to + // construct it anew each time. + // + FD_ZERO(&sock_fds); + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + FD_SET(sock_info->sock, &sock_fds); + } + + // + // Wait for incoming connections. + // + ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL); + if (ret == -1) + { + if (errno == EINTR) + { + // + // If this is a "terminate the + // server" signal, exit the loop, + // otherwise just keep trying. + // + if (shutdown_server) + { + // + // Time to quit. Exit the loop. + // + break; + } + if (reread_config) + { + // + // We should re-read the configuration + // file. + // + reread_config = 0; // clear the indicator + fileconf_read(); + } + + // + // Go back and wait again. + // + continue; + } + else + { + rpcapd_log(LOGPRIO_ERROR, "select failed: %s", + strerror(errno)); + exit(2); + } + } + + // + // Check each socket. + // + for (sock_info = listen_socks; sock_info; + sock_info = sock_info->next) + { + if (FD_ISSET(sock_info->sock, &sock_fds)) + { + // + // Accept the connection. + // + accept_connection(sock_info->sock); + } + } + } +#endif + + // + // Close all the listen sockets. + // + for (sock_info = listen_socks; sock_info; sock_info = sock_info->next) + { + closesocket(sock_info->sock); + } + sock_cleanup(); +} + +#ifdef _WIN32 +// +// A structure to hold the parameters to the daemon service loop +// thread on Windows. +// +// (On UN*X, there is no need for this explicit copy since the +// fork "inherits" the parent stack.) +// +struct params_copy { + PCAP_SOCKET sockctrl; + char *hostlist; +}; +#endif + +// +// Accept a connection and start a worker thread, on Windows, or a +// worker process, on UN*X, to handle the connection. +// +static void +accept_connection(PCAP_SOCKET listen_sock) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection + struct sockaddr_storage from; // generic sockaddr_storage variable + socklen_t fromlen; // keeps the length of the sockaddr_storage variable + +#ifdef _WIN32 + HANDLE threadId; // handle for the subthread + u_long off = 0; + struct params_copy *params_copy = NULL; +#else + pid_t pid; +#endif + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + for (;;) + { + // Accept the connection + fromlen = sizeof(struct sockaddr_storage); + + sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen); + + if (sockctrl != INVALID_SOCKET) + { + // Success. + break; + } + + // The accept() call can return this error when a signal is caught + // In this case, we have simply to ignore this error code + // Stevens, pg 124 +#ifdef _WIN32 + if (WSAGetLastError() == WSAEINTR) +#else + if (errno == EINTR) +#endif + continue; + + // Don't check for errors here, since the error can be due to the fact that the thread + // has been killed + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed"); + rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s", + errbuf); + return; + } + +#ifdef _WIN32 + // + // Put the socket back into blocking mode; doing WSAEventSelect() + // on the listen socket makes that socket non-blocking, and it + // appears that sockets returned from an accept() on that socket + // are also non-blocking. + // + // First, we have to un-WSAEventSelect() this socket, and then + // we can turn non-blocking mode off. + // + // If this fails, we aren't guaranteed that, for example, any + // of the error message will be sent - if it can't be put in + // the socket queue, the send will just fail. + // + // So we just log the message and close the connection. + // + if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "WSAEventSelect() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + sock_close(sockctrl, NULL, 0); + return; + } + if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR) + { + sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, + "ioctlsocket(FIONBIO) failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", errbuf); + sock_close(sockctrl, NULL, 0); + return; + } + + // + // Make a copy of the host list to pass to the new thread, so that + // if we update it in the main thread, it won't catch us in the + // middle of updating it. + // + // daemon_serviceloop() will free it once it's done with it. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + sock_close(sockctrl, NULL, 0); + return; + } + + // + // Allocate a location to hold the values of sockctrl. + // It will be freed in the newly-created thread once it's + // finished with it. + // + params_copy = malloc(sizeof(*params_copy)); + if (params_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure"); + free(hostlist_copy); + sock_close(sockctrl, NULL, 0); + return; + } + params_copy->sockctrl = sockctrl; + params_copy->hostlist = hostlist_copy; + + threadId = (HANDLE)_beginthreadex(NULL, 0, + main_passive_serviceloop_thread, (void *) params_copy, 0, NULL); + if (threadId == 0) + { + rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread"); + free(params_copy); + free(hostlist_copy); + sock_close(sockctrl, NULL, 0); + return; + } + CloseHandle(threadId); +#else /* _WIN32 */ + pid = fork(); + if (pid == -1) + { + rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s", + strerror(errno)); + sock_close(sockctrl, NULL, 0); + return; + } + if (pid == 0) + { + // + // Child process. + // + // Close the socket on which we're listening (must + // be open only in the parent). + // + closesocket(listen_sock); + +#if 0 + // + // Modify thread params so that it can be killed at any time + // XXX - is this necessary? This is the main and, currently, + // only thread in the child process, and nobody tries to + // cancel us, although *we* may cancel the thread that's + // handling the capture loop. + // + if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) + goto end; + if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) + goto end; +#endif + + // + // Run the service loop. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + exit(0); + } + (void)daemon_serviceloop(sockctrl, 0, hostlist_copy, + nullAuthAllowed, uses_ssl); + + exit(0); + } + + // I am the parent + // Close the socket for this session (must be open only in the child) + closesocket(sockctrl); +#endif /* _WIN32 */ +} + +/*! + \brief 'true' main of the program in case the active mode is turned on. + + This function loops forever trying to connect to the remote host, until the + daemon is turned down. + + \param ptr: it keeps the 'activepars' parameters. It is a 'void *' + just because the thread APIs want this format. +*/ +#ifdef _WIN32 +static unsigned __stdcall +#else +static void * +#endif +main_active(void *ptr) +{ + char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed + PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection + struct addrinfo hints; // temporary struct to keep settings needed to open the new socket + struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket + struct active_pars *activepars; + + activepars = (struct active_pars *) ptr; + + // Prepare to open a new server socket + memset(&hints, 0, sizeof(struct addrinfo)); + // WARNING Currently it supports only ONE socket family among IPv4 and IPv6 + hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = activepars->ai_family; + + rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s", + activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": + (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); + + // Initialize errbuf + memset(errbuf, 0, sizeof(errbuf)); + + // Do the work + addrinfo = sock_initaddress(activepars->address, activepars->port, + &hints, errbuf, PCAP_ERRBUF_SIZE); + if (addrinfo == NULL) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + return 0; + } + + for (;;) + { + int activeclose; + + if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET) + { + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + + DIAG_OFF_FORMAT_TRUNCATION + snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s", + activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": + (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified"); + DIAG_ON_FORMAT_TRUNCATION + + rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf); + + sleep_secs(RPCAP_ACTIVE_WAIT); + + continue; + } + + char *hostlist_copy = strdup(hostlist); + if (hostlist_copy == NULL) + { + rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list"); + activeclose = 0; + sock_close(sockctrl, NULL, 0); + } + else + { + // + // daemon_serviceloop() will free the copy. + // + activeclose = daemon_serviceloop(sockctrl, 1, + hostlist_copy, nullAuthAllowed, uses_ssl); + } + + // If the connection is closed by the user explicitly, don't try to connect to it again + // just exit the program + if (activeclose == 1) + break; + } + + freeaddrinfo(addrinfo); + return 0; +} + +#ifdef _WIN32 +// +// Main routine of a passive-mode service thread. +// +unsigned __stdcall main_passive_serviceloop_thread(void *ptr) +{ + struct params_copy params = *(struct params_copy *)ptr; + free(ptr); + + // + // Handle this client. + // This is passive mode, so we don't care whether we were + // told by the client to close. + // + (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist, + nullAuthAllowed, uses_ssl); + + return 0; +} +#endif diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.h b/src/libpcap-1.10.5/rpcapd/rpcapd.h new file mode 100644 index 0000000000..90ba7ffa71 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __RPCAPD_H__ +#define __RPCAPD_H__ + +#define PROGRAM_NAME "rpcapd" +#define SOCKET_MAXCONN 10 /* Maximum number of connections queued into the accept() */ +#ifdef _WIN32 +void send_shutdown_notification(void); // Send notification to shut down the daemon +void send_reread_configuration_notification(void); // Send notification to re-read the configuration file +#endif +void main_startup(void); + +#endif diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.inetd.conf b/src/libpcap-1.10.5/rpcapd/rpcapd.inetd.conf new file mode 100644 index 0000000000..86823f043a --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.inetd.conf @@ -0,0 +1 @@ +2002 stream tcp nowait root /usr/local/sbin/rpcapd rpcapd -i diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.manadmin.in b/src/libpcap-1.10.5/rpcapd/rpcapd.manadmin.in new file mode 100644 index 0000000000..724a0fc62a --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.manadmin.in @@ -0,0 +1,320 @@ +.\" rpcapd.8 +.\" +.\" Copyright (c) 2002-2005 NetGroup, Politecnico di Torino (Italy) +.\" Copyright (c) 2005-2009 CACE Technologies +.\" Copyright (c) 2018- The TCPdump Group +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the Politecnico di Torino nor the names of its +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.TH RPCAPD @MAN_ADMIN_COMMANDS@ "20 January 2023" +.SH NAME +rpcapd \- capture daemon to be controlled by a remote libpcap application +.SH SYNOPSIS +.na +rpcapd +[ +.B \-b +.I address +] [ +.B \-p +.I port +] [ +.B \-4 +] [ +.B \-l +.I host_list +] +.ti +8 +[ +.B \-a +.IR host , port +] [ +.B \-n +] [ +.B \-v +] [ +.B \-d +] [ +.B \-i +] +.ti +8 +[ +.B \-D +] [ +.B \-s +.I config_file +] +[ +.B \-f +.I config_file +] +[ +.B \-S +] +.ti +8 +[ +.B \-K +.I ssl_keyfile +] [ +.B \-X +.I ssl_certfile +] [ +.B \-C +] +.br +.ad +.SH DESCRIPTION +.LP +\fIRpcapd\fP is a daemon (Unix) or service (Win32) that allows the capture +and filter part of libpcap to be run on a remote system. +.LP +Rpcapd can run in two modes: passive mode (default) and active mode. +.LP +In passive mode, the client (e.g., a network sniffer) connects to +.IR rpcapd . +The client then sends the appropriate commands to +.I rpcapd +to start the capture. +.LP +In active mode, +.I rpcapd +tries to establish a connection toward the client +(e.g., a network sniffer). The client then sends the appropriate commands +to rpcapd to start the capture. +.LP +Active mode is useful in case +.I rpcapd +is run behind a firewall and +cannot receive connections from the external world. In this case, +.I rpcapd +can be configured to establish the connection to a given host, +which has to be configured in order to wait for that connection. After +establishing the connection, the protocol continues its job in almost +the same way in both active and passive mode. +.SH Configuration file +.LP +The user can create a configuration file in the same directory as the +executable, and put the configuration commands in there. In order for +.I rpcapd +to execute the commands, it needs to be restarted on Win32, i.e. +the configuration file is parsed only at the beginning. The UNIX +version of +.I rpcapd +will reread the configuration file upon receiving a +.B HUP +signal. In that case, all the existing connections remain in place, +while the new connections will be created according to the new parameters. +.LP +In case a user does not want to create the configuration file manually, +they can launch +.I rpcapd +with the desired flags plus +.BR "-s filename" . +Rpcapd will parse all the parameters and save them into the specified +configuration file. +.SH Installing rpcapd on Win32 +.LP +The remote daemon is installed automatically when installing WinPcap. +The installation process places the +.I rpcapd +executable file into the WinPcap folder. +This file can be executed either from the command line, or as a service. +For instance, the installation process updates the list of available +services list and it creates a new item (Remote Packet Capture Protocol +v.0 (experimental)). To avoid security problems, the service is +inactive and it has to be started manually (control panel - +administrative tools - services - start). +.LP +The service has a set of "standard" parameters, i.e. it is launched +with the +.B \-d +flag (in order to make it run as a service) and the +.B "-f rpcapd.ini" +flag. +.SH Starting rpcapd on Win32 +.LP +The +.I rpcapd +executable can be launched directly, i.e. it can run in the +foreground as well (not as a daemon/service). The procedure is quite +simple: you have to invoke the executable from the command line with all +the requested parameters except for the +.B \-d +flag. The capture server will +start in the foreground. +.SH Installing rpcapd on Unix-like systems +TBD +.SH Starting rpcapd on Unix-like systems +.I rpcapd +needs sufficient privileges to perform packet capture, e.g. +run as root or be owned by root and have suid set. Most operating +systems provide more elegant solutions when run as user than the +above solutions, all of them different. +.LP +If your system supports +.BR systemd (1) +and the corresponding +.B rpcapd.socket +and +.B rpcapd@.service +service files have been +installed, the rpcapd service can be enabled by enabling the +.B rpcapd.socket +unit. +.LP +If your system supports +.BR launchd (@MAN_ADMIN_COMMANDS@) +and the +.B org.tcpdump.rpcapd.plist +file has been installed, the rpcapd service can be enabled by loading +the +.B org.tcpdump.rpcapd +service. +.LP +If your system supports +.BR inetd (@MAN_ADMIN_COMMANDS@) +and the +.B rpcapd.inetd.conf +entry has been added to +.BR inetd.conf (@MAN_FILE_FORMATS@), +the rpcapd service can be enabled by telling inetd +to reread its configuration file. +.LP +If your system supports +.BR xinetd (@MAN_ADMIN_COMMANDS@) +and the +.B rpcapd.xinetd.conf +entry has been added to +.BR xinetd.conf (@MAN_FILE_FORMATS@), +the rpcapd service can be enabled by telling xinetd +to reread its configuration file. +.SH OPTIONS +.TP +.BI \-b " address" +Bind to the IP address specified by +.I address +(either numeric or literal). +By default, +.I rpcapd +binds to all local IPv4 and IPv6 addresses. +.TP +.BI \-p " port" +Bind to the port specified by +.IR port . +By default, +.I rpcapd +binds to port 2002. +.TP +.B \-4 +Listen only on IPv4 addresses. +By default, +.I rpcapd +listens on both IPv4 and IPv6 addresses. +.TP +.BI \-l " host_list" +Only allow hosts specified in the +.I host_list +argument to connect to this server. +.I host_list +is a list of host names or IP addresses, separated by commas. +We suggest that you use host names rather than literal IP addresses +in order to avoid problems with different address families. +.TP +.B \-n +Permit NULL authentication (usually used with the +.B \-l +flag). +.TP +.BI \-a " host" , "port" +Run in active mode, connecting to host +.I host +on port +.IR port . +In case +.I port +is omitted, the default port (2003) is used. +.TP +.B -v +Run in active mode only; by default, if +.B \-a +is specified, +.I rpcapd +accepts passive connections as well. +.TP +.B \-d +Run in daemon mode (UNIX only) or as a service (Win32 only). +Warning (Win32): this flag is specified automatically when +the service is started from the control panel. +.TP +.B \-i +Run in inetd mode (UNIX only). +.TP +.B \-D +Log debugging messages. +.TP +.BI \-s " config_file" +Save the current configuration to +.I config_file +in the format specified by +.BR rpcapd-config (@MAN_FILE_FORMATS@). +.TP +.BI \-f " config_file" +Load the current configuration from +.I config_file +in the format specified by +.BR rpcapd-config (@MAN_FILE_FORMATS@) +and ignore all flags specified on the command line. +.TP +.B \-h +Print this help screen. +.LP +If +.I rpcapd +was compiled with SSL support, the following options are also +available: +.TP +.B \-S +Require that SSL be used on connections. +.TP +.B \-C +With SSL enabled, XXX - I'm not sure how *fetching* the list of +compression mechanisms does anything to compression. +.TP +.BI \-S " ssl_keyfile" +With SSL enabled, use +.I ssl_keyfile +as the SSL key file. +.TP +.BI \-X " ssl_certfile" +With SSL enabled, use +.I ssl_certfile +as the SSL certificate file. +.br +.ad +.SH "SEE ALSO" +.BR pcap (3PCAP), +.BR rpcapd-config (@MAN_FILE_FORMATS@) diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.rc b/src/libpcap-1.10.5/rpcapd/rpcapd.rc new file mode 100644 index 0000000000..695c00b6f2 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.rc @@ -0,0 +1,39 @@ +#include "config.h" +#undef PACKAGE_NAME +#include +#include +#define PACKAGE_NAME PROGRAM_NAME + + VS_VERSION_INFO VERSIONINFO + FILEVERSION PACKAGE_VERSION_DLL + PRODUCTVERSION PACKAGE_VERSION_DLL + FILEFLAGSMASK 0x3fL + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "https://github.com/the-tcpdump-group/libpcap/" + VALUE "CompanyName", "The TCPdump Group" + VALUE "FileDescription", "Remote Packet Capture Daemon" + VALUE "FileVersion", "PACKAGE_VERSION_DLL" + VALUE "InternalName", PACKAGE_NAME + VALUE "LegalCopyright", "Copyright (c) The TCPdump Group" + VALUE "LegalTrademarks", "" + VALUE "OriginalFilename", "rpcapd.exe" + VALUE "ProductName", PACKAGE_NAME + VALUE "ProductVersion", PACKAGE_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END + END diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.socket b/src/libpcap-1.10.5/rpcapd/rpcapd.socket new file mode 100644 index 0000000000..9d5a0bda71 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Rpcap Socket for Per-Connection Servers + +[Socket] +ListenStream=2002 +Accept=yes + +[Install] +WantedBy=sockets.target diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd.xinetd.conf b/src/libpcap-1.10.5/rpcapd/rpcapd.xinetd.conf new file mode 100644 index 0000000000..2c79348e79 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd.xinetd.conf @@ -0,0 +1,8 @@ +service rpcap { + socket_type = stream + protocol = tcp + wait = no + user = root + server = /usr/local/sbin/rpcapd + server_args = -i +} diff --git a/src/libpcap-1.10.5/rpcapd/rpcapd@.service b/src/libpcap-1.10.5/rpcapd/rpcapd@.service new file mode 100644 index 0000000000..92d11719b1 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/rpcapd@.service @@ -0,0 +1,6 @@ +[Unit] +Description=Rpcap Per-Connection Server + +[Service] +ExecStart=-/usr/local/sbin/rpcapd -i +StandardInput=socket diff --git a/src/libpcap-1.10.5/rpcapd/win32-svc.c b/src/libpcap-1.10.5/rpcapd/win32-svc.c new file mode 100644 index 0000000000..b4a5fa9939 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/win32-svc.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "rpcapd.h" +#include // for PCAP_ERRBUF_SIZE +#include "fmtutils.h" +#include "portability.h" +#include "fileconf.h" +#include "log.h" + +#include "win32-svc.h" // for Win32 service stuff + +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; + +static void WINAPI svc_main(DWORD argc, char **argv); +static void WINAPI svc_control_handler(DWORD Opcode); +static void update_svc_status(DWORD state, DWORD progress_indicator); + +BOOL svc_start(void) +{ + BOOL rc; + SERVICE_TABLE_ENTRY ste[] = + { + { PROGRAM_NAME, svc_main }, + { NULL, NULL } + }; + char string[PCAP_ERRBUF_SIZE]; + + // This call is blocking. A new thread is created which will launch + // the svc_main() function + if ((rc = StartServiceCtrlDispatcher(ste)) == 0) { + pcapint_fmt_errmsg_for_win32_err(string, sizeof (string), + GetLastError(), "StartServiceCtrlDispatcher() failed"); + rpcapd_log(LOGPRIO_ERROR, "%s", string); + } + + return rc; // FALSE if this is not started as a service +} + +static void WINAPI +svc_control_handler(DWORD Opcode) +{ + switch(Opcode) + { + case SERVICE_CONTROL_STOP: + // + // XXX - is this sufficient to clean up the service? + // To be really honest, only the main socket and + // such these stuffs are cleared; however the threads + // that are running are not stopped. + // This can be seen by placing a breakpoint at the + // end of svc_main(), in which you will see that is + // never reached. However, as soon as you set the + // service status to "stopped", the + // StartServiceCtrlDispatcher() returns and the main + // thread ends. Then, Win32 has a good automatic + // cleanup, so that all the threads which are still + // running are stopped when the main thread ends. + // + send_shutdown_notification(); + + update_svc_status(SERVICE_STOP_PENDING, 0); + break; + + /* + Pause and Continue have an usual meaning and they are used just to be able + to change the running parameters at run-time. In other words, they act + like the SIGHUP signal on UNIX. All the running threads continue to run and + they are not paused at all. + Particularly, + - PAUSE does nothing + - CONTINUE re-reads the configuration file and creates the new threads that + can be needed according to the new configuration. + */ + case SERVICE_CONTROL_PAUSE: + update_svc_status(SERVICE_PAUSED, 0); + break; + + case SERVICE_CONTROL_CONTINUE: + update_svc_status(SERVICE_RUNNING, 0); + // + // Tell the main loop to re-read the configuration. + // + send_reread_configuration_notification(); + break; + + case SERVICE_CONTROL_INTERROGATE: + // Fall through to send current status. + // WARNING: not implemented + update_svc_status(SERVICE_RUNNING, 0); + MessageBox(NULL, "Not implemented", "warning", MB_OK); + break; + + case SERVICE_CONTROL_PARAMCHANGE: + // + // Tell the main loop to re-read the configuration. + // + send_reread_configuration_notification(); + break; + } + + // Send current status. + return; +} + +static void WINAPI +svc_main(DWORD argc, char **argv) +{ + service_status_handle = RegisterServiceCtrlHandler(PROGRAM_NAME, svc_control_handler); + + if (!service_status_handle) + return; + + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_PARAMCHANGE; + // | SERVICE_ACCEPT_SHUTDOWN ; + update_svc_status(SERVICE_RUNNING, 0); + + // + // Service requests until we're told to stop. + // + main_startup(); + + // + // It returned, so we were told to stop. + // + update_svc_status(SERVICE_STOPPED, 0); +} + +static void +update_svc_status(DWORD state, DWORD progress_indicator) +{ + service_status.dwWin32ExitCode = NO_ERROR; + service_status.dwCurrentState = state; + service_status.dwCheckPoint = progress_indicator; + service_status.dwWaitHint = 0; + SetServiceStatus(service_status_handle, &service_status); +} + +/* +sc create rpcapd DisplayName= "Remote Packet Capture Protocol v.0 (experimental)" binpath= "C:\cvsroot\winpcap\wpcap\PRJ\Debug\rpcapd -d -f rpcapd.ini" +sc description rpcapd "Allows to capture traffic on this host from a remote machine." +*/ diff --git a/src/libpcap-1.10.5/rpcapd/win32-svc.h b/src/libpcap-1.10.5/rpcapd/win32-svc.h new file mode 100644 index 0000000000..60b25ecff1 --- /dev/null +++ b/src/libpcap-1.10.5/rpcapd/win32-svc.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +BOOL svc_start(void); diff --git a/src/libpcap-1.10.5/savefile.c b/src/libpcap-1.10.5/savefile.c new file mode 100644 index 0000000000..c711a81c37 --- /dev/null +++ b/src/libpcap-1.10.5/savefile.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * savefile.c - supports offline use of tcpdump + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#include + +#include +#ifdef _WIN32 +#include +#include +#endif /* _WIN32 */ + +#include +#include +#include +#include +#include +#include /* for INT_MAX */ + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcap.h" +#include "sf-pcapng.h" +#include "pcap-common.h" +#include "charconv.h" + +#ifdef _WIN32 +/* + * This isn't exported on Windows, because it would only work if both + * WinPcap/Npcap and the code using it were to use the Universal CRT; otherwise, + * a FILE structure in WinPcap/Npcap and a FILE structure in the code using it + * could be different if they're using different versions of the C runtime. + * + * Instead, pcap/pcap.h defines it as a macro that wraps the hopen version, + * with the wrapper calling _fileno() and _get_osfhandle() themselves, + * so that it convert the appropriate CRT version's FILE structure to + * a HANDLE (which is OS-defined, not CRT-defined, and is part of the Win32 + * and Win64 ABIs). + */ +static pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *, u_int, char *); +#endif + +/* + * Setting O_BINARY on DOS/Windows is a bit tricky + */ +#if defined(_WIN32) + #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) +#elif defined(MSDOS) + #if defined(__HIGHC__) + #define SET_BINMODE(f) setmode(f, O_BINARY) + #else + #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) + #endif +#endif + +static int +sf_getnonblock(pcap_t *p _U_) +{ + /* + * This is a savefile, not a live capture file, so never say + * it's in non-blocking mode. + */ + return (0); +} + +static int +sf_setnonblock(pcap_t *p, int nonblock _U_) +{ + /* + * This is a savefile, not a live capture file, so reject + * requests to put it in non-blocking mode. (If it's a + * pipe, it could be put in non-blocking mode, but that + * would significantly complicate the code to read packets, + * as it would have to handle reading partial packets and + * keeping the state of the read.) + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Savefiles cannot be put into non-blocking mode"); + return (-1); +} + +static int +sf_cant_set_rfmon(pcap_t *p _U_) +{ + /* + * This is a savefile, not a device on which you can capture, + * so never say it supports being put into monitor mode. + */ + return (0); +} + +static int +sf_stats(pcap_t *p, struct pcap_stat *ps _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from savefiles"); + return (-1); +} + +#ifdef _WIN32 +static struct pcap_stat * +sf_stats_ex(pcap_t *p, int *size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Statistics aren't available from savefiles"); + return (NULL); +} + +static int +sf_setbuff(pcap_t *p, int dim _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The kernel buffer size cannot be set while reading from a file"); + return (-1); +} + +static int +sf_setmode(pcap_t *p, int mode _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "impossible to set mode while reading from a file"); + return (-1); +} + +static int +sf_setmintocopy(pcap_t *p, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The mintocopy parameter cannot be set while reading from a file"); + return (-1); +} + +static HANDLE +sf_getevent(pcap_t *pcap) +{ + (void)snprintf(pcap->errbuf, sizeof(pcap->errbuf), + "The read event cannot be retrieved while reading from a file"); + return (INVALID_HANDLE_VALUE); +} + +static int +sf_oid_get_request(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID get request cannot be performed on a file"); + return (PCAP_ERROR); +} + +static int +sf_oid_set_request(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_, + size_t *lenp _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "An OID set request cannot be performed on a file"); + return (PCAP_ERROR); +} + +static u_int +sf_sendqueue_transmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_) +{ + pcapint_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + PCAP_ERRBUF_SIZE); + return (0); +} + +static int +sf_setuserbuffer(pcap_t *p, int size _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "The user buffer cannot be set when reading from a file"); + return (-1); +} + +static int +sf_live_dump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed when reading from a file"); + return (-1); +} + +static int +sf_live_dump_ended(pcap_t *p, int sync _U_) +{ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Live packet dumping cannot be performed on a pcap_open_dead pcap_t"); + return (-1); +} + +static PAirpcapHandle +sf_get_airpcap_handle(pcap_t *pcap _U_) +{ + return (NULL); +} +#endif + +static int +sf_inject(pcap_t *p, const void *buf _U_, int size _U_) +{ + pcapint_strlcpy(p->errbuf, "Sending packets isn't supported on savefiles", + PCAP_ERRBUF_SIZE); + return (-1); +} + +/* + * Set direction flag: Which packets do we accept on a forwarding + * single device? IN, OUT or both? + */ +static int +sf_setdirection(pcap_t *p, pcap_direction_t d _U_) +{ + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction is not supported on savefiles"); + return (-1); +} + +void +pcapint_sf_cleanup(pcap_t *p) +{ + if (p->rfile != stdin) + (void)fclose(p->rfile); + if (p->buffer != NULL) + free(p->buffer); + pcap_freecode(&p->fcode); +} + +#ifdef _WIN32 +/* + * Wrapper for fopen() and _wfopen(). + * + * If we're in UTF-8 mode, map the pathname from UTF-8 to UTF-16LE and + * call _wfopen(). + * + * If we're not, just use fopen(); that'll treat it as being in the + * local code page. + */ +FILE * +pcapint_charset_fopen(const char *path, const char *mode) +{ + wchar_t *utf16_path; +#define MAX_MODE_LEN 16 + wchar_t utf16_mode[MAX_MODE_LEN+1]; + int i; + char c; + FILE *fp; + int save_errno; + + if (pcapint_utf_8_mode) { + /* + * Map from UTF-8 to UTF-16LE. + * Fail if there are invalid characters in the input + * string, rather than converting them to REPLACEMENT + * CHARACTER; the latter is appropriate for strings + * to be displayed to the user, but for file names + * you just want the attempt to open the file to fail. + */ + utf16_path = cp_to_utf_16le(CP_UTF8, path, + MB_ERR_INVALID_CHARS); + if (utf16_path == NULL) { + /* + * Error. Assume errno has been set. + * + * XXX - what about Windows errors? + */ + return (NULL); + } + + /* + * Now convert the mode to UTF-16LE as well. + * We assume the mode is ASCII, and that + * it's short, so that's easy. + */ + for (i = 0; (c = *mode) != '\0'; i++, mode++) { + if (c > 0x7F) { + /* Not an ASCII character; fail with EINVAL. */ + free(utf16_path); + errno = EINVAL; + return (NULL); + } + if (i >= MAX_MODE_LEN) { + /* The mode string is longer than we allow. */ + free(utf16_path); + errno = EINVAL; + return (NULL); + } + utf16_mode[i] = c; + } + utf16_mode[i] = '\0'; + + /* + * OK, we have UTF-16LE strings; hand them to + * _wfopen(). + */ + fp = _wfopen(utf16_path, utf16_mode); + + /* + * Make sure freeing the UTF-16LE string doesn't + * overwrite the error code we got from _wfopen(). + */ + save_errno = errno; + free(utf16_path); + errno = save_errno; + + return (fp); + } else { + /* + * This takes strings in the local code page as an + * argument. + */ + return (fopen(path, mode)); + } +} +#endif + +pcap_t * +pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision, + char *errbuf) +{ + FILE *fp; + pcap_t *p; + + if (fname == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return (NULL); + } + if (fname[0] == '-' && fname[1] == '\0') + { + fp = stdin; + if (fp == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "The standard input is not open"); + return (NULL); + } +#if defined(_WIN32) || defined(MSDOS) + /* + * We're reading from the standard input, so put it in binary + * mode, as savefiles are binary files. + */ + SET_BINMODE(fp); +#endif + } + else { + /* + * Use pcapint_charset_fopen(); on Windows, it tests whether we're + * in "local code page" or "UTF-8" mode, and treats the + * pathname appropriately, and on other platforms, it just + * wraps fopen(). + * + * "b" is supported as of C90, so *all* UN*Xes should + * support it, even though it does nothing. For MS-DOS, + * we again need it. + */ + fp = pcapint_charset_fopen(fname, "rb"); + if (fp == NULL) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "%s", fname); + return (NULL); + } + } + p = pcap_fopen_offline_with_tstamp_precision(fp, precision, errbuf); + if (p == NULL) { + if (fp != stdin) + fclose(fp); + } + return (p); +} + +pcap_t * +pcap_open_offline(const char *fname, char *errbuf) +{ + return (pcap_open_offline_with_tstamp_precision(fname, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); +} + +#ifdef _WIN32 +pcap_t* pcap_hopen_offline_with_tstamp_precision(intptr_t osfd, u_int precision, + char *errbuf) +{ + int fd; + FILE *file; + + fd = _open_osfhandle(osfd, _O_RDONLY); + if ( fd < 0 ) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "_open_osfhandle"); + return NULL; + } + + file = _fdopen(fd, "rb"); + if ( file == NULL ) + { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "_fdopen"); + _close(fd); + return NULL; + } + + return pcap_fopen_offline_with_tstamp_precision(file, precision, + errbuf); +} + +pcap_t* pcap_hopen_offline(intptr_t osfd, char *errbuf) +{ + return pcap_hopen_offline_with_tstamp_precision(osfd, + PCAP_TSTAMP_PRECISION_MICRO, errbuf); +} +#endif + +/* + * Given a link-layer header type and snapshot length, return a + * snapshot length to use when reading the file; it's guaranteed + * to be > 0 and <= INT_MAX. + * + * XXX - the only reason why we limit it to <= INT_MAX is so that + * it fits in p->snapshot, and the only reason that p->snapshot is + * signed is that pcap_snapshot() returns an int, not an unsigned int. + */ +bpf_u_int32 +pcapint_adjust_snapshot(bpf_u_int32 linktype, bpf_u_int32 snaplen) +{ + if (snaplen == 0 || snaplen > INT_MAX) { + /* + * Bogus snapshot length; use the maximum for this + * link-layer type as a fallback. + * + * XXX - we don't clamp snapshot lengths that are + * <= INT_MAX but > max_snaplen_for_dlt(linktype), + * so a capture file could cause us to allocate + * a Really Big Buffer. + */ + snaplen = max_snaplen_for_dlt(linktype); + } + return snaplen; +} + +static pcap_t *(*check_headers[])(const uint8_t *, FILE *, u_int, char *, int *) = { + pcap_check_header, + pcap_ng_check_header +}; + +#define N_FILE_TYPES (sizeof check_headers / sizeof check_headers[0]) + +#ifdef _WIN32 +static +#endif +pcap_t * +pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision, + char *errbuf) +{ + register pcap_t *p; + uint8_t magic[4]; + size_t amt_read; + u_int i; + int err; + + /* + * Fail if we were passed a NULL fp. + * + * That shouldn't happen if we're opening with a path name, but + * it could happen if buggy code is opening with a FILE * and + * didn't bother to make sure the FILE * isn't null. + */ + if (fp == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Null FILE * pointer provided to savefile open routine"); + return (NULL); + } + + /* + * Read the first 4 bytes of the file; the network analyzer dump + * file formats we support (pcap and pcapng), and several other + * formats we might support in the future (such as snoop, DOS and + * Windows Sniffer, and Microsoft Network Monitor) all have magic + * numbers that are unique in their first 4 bytes. + */ + amt_read = fread(&magic, 1, sizeof(magic), fp); + if (amt_read != sizeof(magic)) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %zu file header bytes, only got %zu", + sizeof(magic), amt_read); + } + return (NULL); + } + + /* + * Try all file types. + */ + for (i = 0; i < N_FILE_TYPES; i++) { + p = (*check_headers[i])(magic, fp, precision, errbuf, &err); + if (p != NULL) { + /* Yup, that's it. */ + goto found; + } + if (err) { + /* + * Error trying to read the header. + */ + return (NULL); + } + } + + /* + * Well, who knows what this mess is.... + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown file format"); + return (NULL); + +found: + p->rfile = fp; + + /* Padding only needed for live capture fcode */ + p->fddipad = 0; + +#if !defined(_WIN32) && !defined(MSDOS) + /* + * You can do "select()" and "poll()" on plain files on most + * platforms, and should be able to do so on pipes. + * + * You can't do "select()" on anything other than sockets in + * Windows, so, on Win32 systems, we don't have "selectable_fd". + */ + p->selectable_fd = fileno(fp); +#endif + + p->can_set_rfmon_op = sf_cant_set_rfmon; + p->read_op = pcapint_offline_read; + p->inject_op = sf_inject; + p->setfilter_op = pcapint_install_bpf_program; + p->setdirection_op = sf_setdirection; + p->set_datalink_op = NULL; /* we don't support munging link-layer headers */ + p->getnonblock_op = sf_getnonblock; + p->setnonblock_op = sf_setnonblock; + p->stats_op = sf_stats; +#ifdef _WIN32 + p->stats_ex_op = sf_stats_ex; + p->setbuff_op = sf_setbuff; + p->setmode_op = sf_setmode; + p->setmintocopy_op = sf_setmintocopy; + p->getevent_op = sf_getevent; + p->oid_get_request_op = sf_oid_get_request; + p->oid_set_request_op = sf_oid_set_request; + p->sendqueue_transmit_op = sf_sendqueue_transmit; + p->setuserbuffer_op = sf_setuserbuffer; + p->live_dump_op = sf_live_dump; + p->live_dump_ended_op = sf_live_dump_ended; + p->get_airpcap_handle_op = sf_get_airpcap_handle; +#endif + + /* + * For offline captures, the standard one-shot callback can + * be used for pcap_next()/pcap_next_ex(). + */ + p->oneshot_callback = pcapint_oneshot; + + /* + * Default breakloop operation. + */ + p->breakloop_op = pcapint_breakloop_common; + + /* + * Savefiles never require special BPF code generation. + */ + p->bpf_codegen_flags = 0; + + p->activated = 1; + + return (p); +} + +/* + * This isn't needed on Windows; we #define pcap_fopen_offline() as + * a wrapper around pcap_hopen_offline(), and we don't call it from + * inside this file, so it's unused. + */ +#ifndef _WIN32 +pcap_t * +pcap_fopen_offline(FILE *fp, char *errbuf) +{ + return (pcap_fopen_offline_with_tstamp_precision(fp, + PCAP_TSTAMP_PRECISION_MICRO, errbuf)); +} +#endif + +/* + * Read packets from a capture file, and call the callback for each + * packet. + * If cnt > 0, return after 'cnt' packets, otherwise continue until eof. + */ +int +pcapint_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) +{ + struct bpf_insn *fcode; + int n = 0; + u_char *data; + + /* + * This can conceivably process more than INT_MAX packets, + * which would overflow the packet count, causing it either + * to look like a negative number, and thus cause us to + * return a value that looks like an error, or overflow + * back into positive territory, and thus cause us to + * return a too-low count. + * + * Therefore, if the packet count is unlimited, we clip + * it at INT_MAX; this routine is not expected to + * process packets indefinitely, so that's not an issue. + */ + if (PACKET_COUNT_IS_UNLIMITED(cnt)) + cnt = INT_MAX; + + for (;;) { + struct pcap_pkthdr h; + int status; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else + return (n); + } + + status = p->next_packet_op(p, &h, &data); + if (status < 0) { + /* + * Error. Pass it back to the caller. + */ + return (status); + } + if (status == 0) { + /* + * EOF. Nothing more to process; + */ + break; + } + + /* + * OK, we've read a packet; run it through the filter + * and, if it passes, process it. + */ + if ((fcode = p->fcode.bf_insns) == NULL || + pcapint_filter(fcode, data, h.len, h.caplen)) { + (*callback)(user, &h, data); + n++; /* count the packet */ + if (n >= cnt) + break; + } + } + /*XXX this breaks semantics tcpslice expects */ + return (n); +} diff --git a/src/libpcap-1.10.5/scanner.l b/src/libpcap-1.10.5/scanner.l new file mode 100644 index 0000000000..82e7b318d5 --- /dev/null +++ b/src/libpcap-1.10.5/scanner.l @@ -0,0 +1,690 @@ +%top { +/* Must come first for _LARGE_FILE_API on AIX. */ +#include + +/* + * Must come first to avoid warnings on Windows. + * + * Flex-generated scanners may only include if __STDC_VERSION__ + * is defined with a value >= 199901, meaning "full C99", and MSVC may not + * define it with that value, because it isn't 100% C99-compliant, even + * though it has an capable of defining everything the Flex + * scanner needs. + * + * We, however, will include it if we know we have an MSVC version that has + * it; this means that we may define the INTn_MAX and UINTn_MAX values in + * scanner.c, and then include , which may define them differently + * (same value, but different string of characters), causing compiler warnings. + * + * If we include it here, and they're defined, that'll prevent scanner.c + * from defining them. So we include , to get + * if we have it. + */ +#include + +/* + * grammar.h requires gencode.h and sometimes breaks in a polluted namespace + * (see ftmacros.h), so include it early. + */ +#include "gencode.h" +#include "grammar.h" + +#include "diag-control.h" + +/* + * Convert string to 32-bit unsigned integer; the string starts at + * string and is string_len bytes long. + * + * On success, sets *val to the value and returns 1. + * On failure, sets the BPF error string and returns 0. + * + * Also used in gencode.c + */ +typedef enum { + STOULEN_OK, + STOULEN_NOT_HEX_NUMBER, + STOULEN_NOT_OCTAL_NUMBER, + STOULEN_NOT_DECIMAL_NUMBER, + STOULEN_ERROR +} stoulen_ret; + +stoulen_ret stoulen(const char *string, size_t stringlen, bpf_u_int32 *val, + compiler_state_t *cstate); +} + +/* + * We want a reentrant scanner. + */ +%option reentrant + +/* + * And we need to pass the compiler state to the scanner. + */ +%option extra-type="compiler_state_t *" + +/* + * We don't use input, so don't generate code for it. + */ +%option noinput + +/* + * We don't use unput, so don't generate code for it. + */ +%option nounput + +/* + * We don't read from the terminal. + */ +%option never-interactive + +/* + * We want to stop processing when we get to the end of the input. + */ +%option noyywrap + +/* + * We want to generate code that can be used by a reentrant parser + * generated by Bison or Berkeley YACC. + */ +%option bison-bridge + +%{ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include + +#include "pcap-int.h" + +/* + * Earlier versions of Flex don't declare these, so we declare them + * ourselves to squelch warnings. + */ +int pcap_get_column(yyscan_t); +void pcap_set_column(int, yyscan_t); + +#ifdef INET6 + +#ifdef _WIN32 +#include +#include +/* + * To quote the MSDN page for getaddrinfo() at + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + * + * "Support for getaddrinfo on Windows 2000 and older versions + * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and + * later. To execute an application that uses this function on earlier + * versions of Windows, then you need to include the Ws2tcpip.h and + * Wspiapi.h files. When the Wspiapi.h include file is added, the + * getaddrinfo function is defined to the WspiapiGetAddrInfo inline + * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo + * function is implemented in such a way that if the Ws2_32.dll or the + * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology + * Preview for Windows 2000) does not include getaddrinfo, then a + * version of getaddrinfo is implemented inline based on code in the + * Wspiapi.h header file. This inline code will be used on older Windows + * platforms that do not natively support the getaddrinfo function." + * + * We use getaddrinfo(), so we include Wspiapi.h here. + */ +#include +#else /* _WIN32 */ +#include /* for "struct sockaddr" in "struct addrinfo" */ +#include /* for "struct addrinfo" */ +#endif /* _WIN32 */ + +/* Workaround for AIX 4.3 */ +#if !defined(AI_NUMERICHOST) +#define AI_NUMERICHOST 0x04 +#endif + +#endif /*INET6*/ + +#include +#include "grammar.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +static int stou(const char *, YYSTYPE *, compiler_state_t *); + +/* + * Disable diagnostics in the code generated by Flex. + */ +DIAG_OFF_FLEX + +%} + +N ([0-9]+|(0X|0x)[0-9A-Fa-f]+) +B ([0-9A-Fa-f][0-9A-Fa-f]?) +B2 ([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) +W ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?) + +%a 18400 +%o 21500 +%e 7600 +%k 4550 +%p 27600 +%n 2000 + +V680 {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W} + +V670 ::{W}:{W}:{W}:{W}:{W}:{W}:{W} +V671 {W}::{W}:{W}:{W}:{W}:{W}:{W} +V672 {W}:{W}::{W}:{W}:{W}:{W}:{W} +V673 {W}:{W}:{W}::{W}:{W}:{W}:{W} +V674 {W}:{W}:{W}:{W}::{W}:{W}:{W} +V675 {W}:{W}:{W}:{W}:{W}::{W}:{W} +V676 {W}:{W}:{W}:{W}:{W}:{W}::{W} +V677 {W}:{W}:{W}:{W}:{W}:{W}:{W}:: + +V660 ::{W}:{W}:{W}:{W}:{W}:{W} +V661 {W}::{W}:{W}:{W}:{W}:{W} +V662 {W}:{W}::{W}:{W}:{W}:{W} +V663 {W}:{W}:{W}::{W}:{W}:{W} +V664 {W}:{W}:{W}:{W}::{W}:{W} +V665 {W}:{W}:{W}:{W}:{W}::{W} +V666 {W}:{W}:{W}:{W}:{W}:{W}:: + +V650 ::{W}:{W}:{W}:{W}:{W} +V651 {W}::{W}:{W}:{W}:{W} +V652 {W}:{W}::{W}:{W}:{W} +V653 {W}:{W}:{W}::{W}:{W} +V654 {W}:{W}:{W}:{W}::{W} +V655 {W}:{W}:{W}:{W}:{W}:: + +V640 ::{W}:{W}:{W}:{W} +V641 {W}::{W}:{W}:{W} +V642 {W}:{W}::{W}:{W} +V643 {W}:{W}:{W}::{W} +V644 {W}:{W}:{W}:{W}:: + +V630 ::{W}:{W}:{W} +V631 {W}::{W}:{W} +V632 {W}:{W}::{W} +V633 {W}:{W}:{W}:: + +V620 ::{W}:{W} +V621 {W}::{W} +V622 {W}:{W}:: + +V610 ::{W} +V611 {W}:: + +V600 :: + +V6604 {W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} + +V6504 ::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6514 {W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6524 {W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6534 {W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6544 {W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6554 {W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6404 ::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6414 {W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6424 {W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6434 {W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6444 {W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6304 ::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N} +V6314 {W}::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6324 {W}:{W}::{W}:{N}\.{N}\.{N}\.{N} +V6334 {W}:{W}:{W}::{N}\.{N}\.{N}\.{N} + +V6204 ::{W}:{W}:{N}\.{N}\.{N}\.{N} +V6214 {W}::{W}:{N}\.{N}\.{N}\.{N} +V6224 {W}:{W}::{N}\.{N}\.{N}\.{N} + +V6104 ::{W}:{N}\.{N}\.{N}\.{N} +V6114 {W}::{N}\.{N}\.{N}\.{N} + +V6004 ::{N}\.{N}\.{N}\.{N} + + +V6 ({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004}) + +MAC ({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3}) + + + +%% +dst return DST; +src return SRC; + +link|ether|ppp|slip return LINK; +fddi|tr|wlan return LINK; +arp return ARP; +rarp return RARP; +ip return IP; +sctp return SCTP; +tcp return TCP; +udp return UDP; +icmp return ICMP; +igmp return IGMP; +igrp return IGRP; +pim return PIM; +vrrp return VRRP; +carp return CARP; +radio return RADIO; + +ip6 return IPV6; +icmp6 return ICMPV6; +ah return AH; +esp return ESP; + +atalk return ATALK; +aarp return AARP; +decnet return DECNET; +lat return LAT; +sca return SCA; +moprc return MOPRC; +mopdl return MOPDL; + +iso return ISO; +esis return ESIS; +es-is return ESIS; +isis return ISIS; +is-is return ISIS; +l1 return L1; +l2 return L2; +iih return IIH; +lsp return LSP; +snp return SNP; +csnp return CSNP; +psnp return PSNP; + +clnp return CLNP; + +stp return STP; + +ipx return IPX; + +netbeui return NETBEUI; + +host return HOST; +net return NET; +mask return NETMASK; +port return PORT; +portrange return PORTRANGE; +proto return PROTO; +protochain return PROTOCHAIN; + +gateway return GATEWAY; + +type return TYPE; +subtype return SUBTYPE; +direction|dir return DIR; +address1|addr1 return ADDR1; +address2|addr2 return ADDR2; +address3|addr3 return ADDR3; +address4|addr4 return ADDR4; +ra return RA; +ta return TA; + +less return LESS; +greater return GREATER; +byte return CBYTE; +broadcast return TK_BROADCAST; +multicast return TK_MULTICAST; + +and|"&&" return AND; +or|"||" return OR; +not return '!'; + +len|length return LEN; +inbound return INBOUND; +outbound return OUTBOUND; + +ifindex return IFINDEX; + +vlan return VLAN; +mpls return MPLS; +pppoed return PPPOED; +pppoes return PPPOES; +geneve return GENEVE; + +lane return LANE; +llc return LLC; +metac return METAC; +bcc return BCC; +oam return OAM; +oamf4 return OAMF4; +oamf4ec return OAMF4EC; +oamf4sc return OAMF4SC; +sc return SC; +ilmic return ILMIC; +vpi return VPI; +vci return VCI; +connectmsg return CONNECTMSG; +metaconnect return METACONNECT; + +on|ifname return PF_IFNAME; +rset|ruleset return PF_RSET; +rnr|rulenum return PF_RNR; +srnr|subrulenum return PF_SRNR; +reason return PF_REASON; +action return PF_ACTION; + +fisu return FISU; +lssu return LSSU; +lsu return LSSU; +msu return MSU; +hfisu return HFISU; +hlssu return HLSSU; +hmsu return HMSU; +sio return SIO; +opc return OPC; +dpc return DPC; +sls return SLS; +hsio return HSIO; +hopc return HOPC; +hdpc return HDPC; +hsls return HSLS; + +[ \r\n\t] ; +[+\-*/%:\[\]!<>()&|\^=] return yytext[0]; +">=" return GEQ; +"<=" return LEQ; +"!=" return NEQ; +"==" return '='; +"<<" return LSH; +">>" return RSH; +${B} { yylval->s = sdup(yyextra, yytext); return AID; } +{MAC} { yylval->s = sdup(yyextra, yytext); return EID; } +{N} { return stou(yytext, yylval, yyextra); } +({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) { + yylval->s = sdup(yyextra, (char *)yytext); return HID; } +{V6} { +#ifdef INET6 + struct addrinfo hints, *res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(yytext, NULL, &hints, &res)) { + bpf_set_error(yyextra, "bogus IPv6 address %s", yytext); + yylval->s = NULL; + } else { + freeaddrinfo(res); + yylval->s = sdup(yyextra, (char *)yytext); + } +#else + bpf_set_error(yyextra, "IPv6 address %s not supported", yytext); + yylval->s = NULL; +#endif /*INET6*/ + return HID6; + } +{B}:+({B}:+)+ { bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; } +icmptype { yylval->h = 0; return NUM; } +icmpcode { yylval->h = 1; return NUM; } +icmp-echoreply { yylval->h = 0; return NUM; } +icmp-unreach { yylval->h = 3; return NUM; } +icmp-sourcequench { yylval->h = 4; return NUM; } +icmp-redirect { yylval->h = 5; return NUM; } +icmp-echo { yylval->h = 8; return NUM; } +icmp-routeradvert { yylval->h = 9; return NUM; } +icmp-routersolicit { yylval->h = 10; return NUM; } +icmp-timxceed { yylval->h = 11; return NUM; } +icmp-paramprob { yylval->h = 12; return NUM; } +icmp-tstamp { yylval->h = 13; return NUM; } +icmp-tstampreply { yylval->h = 14; return NUM; } +icmp-ireq { yylval->h = 15; return NUM; } +icmp-ireqreply { yylval->h = 16; return NUM; } +icmp-maskreq { yylval->h = 17; return NUM; } +icmp-maskreply { yylval->h = 18; return NUM; } + +icmp6type { yylval->h = 0; return NUM; } +icmp6code { yylval->h = 1; return NUM; } + +icmp6-destinationunreach { yylval->h = 1; return NUM; } +icmp6-packettoobig { yylval->h = 2; return NUM; } +icmp6-timeexceeded { yylval->h = 3; return NUM; } +icmp6-parameterproblem { yylval->h = 4; return NUM; } +icmp6-echo { yylval->h = 128; return NUM; } +icmp6-echoreply { yylval->h = 129; return NUM; } +icmp6-multicastlistenerquery { yylval->h = 130; return NUM; } +icmp6-multicastlistenerreportv1 { yylval->h = 131; return NUM; } +icmp6-multicastlistenerdone { yylval->h = 132; return NUM; } +icmp6-routersolicit { yylval->h = 133; return NUM; } +icmp6-routeradvert { yylval->h = 134; return NUM; } +icmp6-neighborsolicit { yylval->h = 135; return NUM; } +icmp6-neighboradvert { yylval->h = 136; return NUM; } +icmp6-redirect { yylval->h = 137; return NUM; } +icmp6-routerrenum { yylval->h = 138; return NUM; } +icmp6-nodeinformationquery { yylval->h = 139; return NUM; } +icmp6-nodeinformationresponse { yylval->h = 140; return NUM; } +icmp6-ineighbordiscoverysolicit { yylval->h = 141; return NUM; } +icmp6-ineighbordiscoveryadvert { yylval->h = 142; return NUM; } +icmp6-multicastlistenerreportv2 { yylval->h = 143; return NUM; } +icmp6-homeagentdiscoveryrequest { yylval->h = 144; return NUM; } +icmp6-homeagentdiscoveryreply { yylval->h = 145; return NUM; } +icmp6-mobileprefixsolicit { yylval->h = 146; return NUM; } +icmp6-mobileprefixadvert { yylval->h = 147; return NUM; } +icmp6-certpathsolicit { yylval->h = 148; return NUM; } +icmp6-certpathadvert { yylval->h = 149; return NUM; } +icmp6-multicastrouteradvert { yylval->h = 151; return NUM; } +icmp6-multicastroutersolicit { yylval->h = 152; return NUM; } +icmp6-multicastrouterterm { yylval->h = 153; return NUM; } + +tcpflags { yylval->h = 13; return NUM; } +tcp-fin { yylval->h = 0x01; return NUM; } +tcp-syn { yylval->h = 0x02; return NUM; } +tcp-rst { yylval->h = 0x04; return NUM; } +tcp-push { yylval->h = 0x08; return NUM; } +tcp-ack { yylval->h = 0x10; return NUM; } +tcp-urg { yylval->h = 0x20; return NUM; } +tcp-ece { yylval->h = 0x40; return NUM; } +tcp-cwr { yylval->h = 0x80; return NUM; } +[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? { + yylval->s = sdup(yyextra, (char *)yytext); return ID; } +"\\"[^ !()\n\t]+ { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; } +. { return LEX_ERROR; } +%% + +/* + * Turn diagnostics back on, so we check the code that we've written. + */ +DIAG_ON_FLEX + +stoulen_ret +stoulen(const char *string, size_t string_len, bpf_u_int32 *val, + compiler_state_t *cstate) +{ + bpf_u_int32 n = 0; + unsigned int digit; + const char *s = string; + + /* + * string is guaranteed either to be a string of decimal digits + * or 0[xX] followed by a string of hex digits. + */ + if (string_len >= 1 && *s == '0') { + if (string_len >= 2 && (s[1] == 'x' || s[1] == 'X')) { + /* + * Begins with 0x or 0X, so hex. + * Guaranteed to be all hex digits following the + * prefix, so anything that's not 0-9 or a-f is + * A-F. + */ + s += 2; /* skip the prefix */ + string_len -= 2; + while (string_len != 0) { + digit = *s++; + string_len--; + if (digit >= '0' && digit <= '9') + digit = digit - '0'; + else if (digit >= 'a' && digit <= 'f') + digit = digit - 'a' + 10; + else if (digit >= 'A' && digit <= 'F') + digit = digit - 'A' + 10; + else { + /* + * Not a valid hex number. + * Don't treat this as an error, + * in case the caller wants to + * interpret it as something else. + */ + return STOULEN_NOT_HEX_NUMBER; + } + + /* + * Check for overflow. + */ + if (n > 0xFFFFFFFU) { + /* + * We have more than 28 bits of + * number, and are about to + * add 4 more; that won't fit + * in 32 bits. + */ + bpf_set_error(cstate, + "number %.*s overflows 32 bits", + (int)string_len, string); + return STOULEN_ERROR; + } + n = (n << 4) + digit; + } + } else { + /* + * Begins with 0, but not 0x or 0X, so octal. + * Guaranteed to be all *decimal* digits following + * the prefix, so we need to catch 8 and 9 and + * report an error. + */ + s += 1; + string_len -= 1; + while (string_len != 0) { + digit = *s++; + string_len--; + if (digit >= '0' && digit <= '7') + digit = digit - '0'; + else { + /* + * Not a valid octal number. + * Don't treat this as an error, + * in case the caller wants to + * interpret it as something else. + */ + return STOULEN_NOT_OCTAL_NUMBER; + } + if (n > 03777777777U) { + /* + * We have more than 29 bits of + * number, and are about to add + * 3 more; that won't fit in + * 32 bits. + */ + bpf_set_error(cstate, + "number %.*s overflows 32 bits", + (int)string_len, string); + return STOULEN_ERROR; + } + n = (n << 3) + digit; + } + } + } else { + /* + * Decimal. + */ + while (string_len != 0) { + digit = *s++; + string_len--; + if (digit >= '0' && digit <= '9') + digit = digit - '0'; + else { + /* + * Not a valid decimal number. + * Don't treat this as an error, + * in case the caller wants to + * interpret it as something else. + */ + return STOULEN_NOT_DECIMAL_NUMBER; + } +#define CUTOFF_DEC (0xFFFFFFFFU / 10U) +#define CUTLIM_DEC (0xFFFFFFFFU % 10U) + if (n > CUTOFF_DEC || + (n == CUTOFF_DEC && digit > CUTLIM_DEC)) { + /* + * Adding that digit will result in a + * number that won't fit in 32 bits. + */ + bpf_set_error(cstate, + "number %.*s overflows 32 bits", + (int)string_len, string); + return STOULEN_ERROR; + } + n = (n * 10) + digit; + } + } + + *val = n; + return STOULEN_OK; +} + +/* + * Convert string to 32-bit unsigned integer. Just like atoi(), but checks for + * preceding 0x or 0 and uses hex or octal instead of decimal. + * + * On success, sets yylval->h to the value and returns NUM. + * On failure, sets the BPF error string and returns LEX_ERROR, to force + * the parse to stop. + */ +static int +stou(const char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg) +{ + stoulen_ret ret; + + ret = stoulen(yytext_arg, strlen(yytext_arg), &yylval_arg->h, + yyextra_arg); + switch (ret) { + + case STOULEN_OK: + return NUM; + + case STOULEN_NOT_OCTAL_NUMBER: + bpf_set_error(yyextra_arg, "number %s contains non-octal digit", + yytext_arg); + return LEX_ERROR; + + case STOULEN_NOT_HEX_NUMBER: + bpf_set_error(yyextra_arg, "number %s contains non-hex digit", + yytext_arg); + return LEX_ERROR; + + case STOULEN_NOT_DECIMAL_NUMBER: + bpf_set_error(yyextra_arg, "number %s contains non-decimal digit", + yytext_arg); + return LEX_ERROR; + + case STOULEN_ERROR: + /* Error already set. */ + return LEX_ERROR; + + default: + /* Should not happen */ + bpf_set_error(yyextra_arg, "stoulen returned %d - this should not happen", ret); + return LEX_ERROR; + } +} diff --git a/src/libpcap-1.10.5/sf-pcap.c b/src/libpcap-1.10.5/sf-pcap.c new file mode 100644 index 0000000000..659480b44d --- /dev/null +++ b/src/libpcap-1.10.5/sf-pcap.c @@ -0,0 +1,1272 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap.c - libpcap-file-format-specific code from savefile.c + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#include + +#include +#ifdef _WIN32 +#include +#include +#endif /* _WIN32 */ + +#include +#include +#include +#include +#include +#include /* for INT_MAX */ + +#include "pcap-int.h" +#include "pcap-util.h" + +#include "pcap-common.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcap.h" + +/* + * Setting O_BINARY on DOS/Windows is a bit tricky + */ +#if defined(_WIN32) + #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) +#elif defined(MSDOS) + #if defined(__HIGHC__) + #define SET_BINMODE(f) setmode(f, O_BINARY) + #else + #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) + #endif +#endif + +/* + * Standard libpcap format. + * + * The same value is used in the rpcap protocol as an indication of + * the server byte order, to let the client know whether it needs to + * byte-swap some host-byte-order metadata. + */ +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +/* + * Alexey Kuznetzov's modified libpcap format. + */ +#define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34 + +/* + * Reserved for Francisco Mesquita + * for another modified format. + */ +#define FMESQUITA_TCPDUMP_MAGIC 0xa1b234cd + +/* + * Navtel Communications' format, with nanosecond timestamps, + * as per a request from Dumas Hwang . + */ +#define NAVTEL_TCPDUMP_MAGIC 0xa12b3c4d + +/* + * Normal libpcap format, except for seconds/nanoseconds timestamps, + * as per a request by Ulf Lamping + */ +#define NSEC_TCPDUMP_MAGIC 0xa1b23c4d + +/* + * This is a timeval as stored in a savefile. + * It has to use the same types everywhere, independent of the actual + * `struct timeval'; `struct timeval' has 32-bit tv_sec values on some + * platforms and 64-bit tv_sec values on other platforms, and writing + * out native `struct timeval' values would mean files could only be + * read on systems with the same tv_sec size as the system on which + * the file was written. + * + * THe fields are unsigned, as that's what the pcap draft specification + * says they are. (That gives pcap a 68-year Y2.038K reprieve, although + * in 2106 it runs out for good. pcapng doesn't have that problem, + * unless you pick a *really* high time stamp precision.) + */ + +struct pcap_timeval { + bpf_u_int32 tv_sec; /* seconds */ + bpf_u_int32 tv_usec; /* microseconds */ +}; + +/* + * This is a `pcap_pkthdr' as actually stored in a savefile. + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure), + * and do not make the time stamp anything other than seconds and + * microseconds (e.g., seconds and nanoseconds). Instead: + * + * introduce a new structure for the new format; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed record + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old record header as well as files with the new record header + * (using the magic number to determine the header format). + * + * Then supply the changes by forking the branch at + * + * https://github.com/the-tcpdump-group/libpcap/tree/master + * + * and issuing a pull request, so that future versions of libpcap and + * programs that use it (such as tcpdump) will be able to read your new + * capture file format. + */ + +struct pcap_sf_pkthdr { + struct pcap_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length of this packet (off wire) */ +}; + +/* + * How a `pcap_pkthdr' is actually stored in savefiles written + * by some patched versions of libpcap (e.g. the ones in Red + * Hat Linux 6.1 and 6.2). + * + * Do not change the format of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * Instead, introduce a new structure, as per the above. + */ + +struct pcap_sf_patched_pkthdr { + struct pcap_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length of this packet (off wire) */ + int index; + unsigned short protocol; + unsigned char pkt_type; +}; + +static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); + +#ifdef _WIN32 +/* + * This isn't exported on Windows, because it would only work if both + * libpcap and the code using it were using the same C runtime; otherwise they + * would be using different definitions of a FILE structure. + * + * Instead we define this as a macro in pcap/pcap.h that wraps the hopen + * version that we do export, passing it a raw OS HANDLE, as defined by the + * Win32 / Win64 ABI, obtained from the _fileno() and _get_osfhandle() + * functions of the appropriate CRT. + */ +static pcap_dumper_t *pcap_dump_fopen(pcap_t *p, FILE *f); +#endif /* _WIN32 */ + +/* + * Private data for reading pcap savefiles. + */ +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef enum { + PASS_THROUGH, + SCALE_UP, + SCALE_DOWN +} tstamp_scale_type_t; + +struct pcap_sf { + size_t hdrsize; + swapped_type_t lengths_swapped; + tstamp_scale_type_t scale_type; +}; + +/* + * Check whether this is a pcap savefile and, if it is, extract the + * relevant information from the header. + */ +pcap_t * +pcap_check_header(const uint8_t *magic, FILE *fp, u_int precision, char *errbuf, + int *err) +{ + bpf_u_int32 magic_int; + struct pcap_file_header hdr; + size_t amt_read; + pcap_t *p; + int swapped = 0; + struct pcap_sf *ps; + + /* + * Assume no read errors. + */ + *err = 0; + + /* + * Check whether the first 4 bytes of the file are the magic + * number for a pcap savefile, or for a byte-swapped pcap + * savefile. + */ + memcpy(&magic_int, magic, sizeof(magic_int)); + if (magic_int != TCPDUMP_MAGIC && + magic_int != KUZNETZOV_TCPDUMP_MAGIC && + magic_int != NSEC_TCPDUMP_MAGIC) { + magic_int = SWAPLONG(magic_int); + if (magic_int != TCPDUMP_MAGIC && + magic_int != KUZNETZOV_TCPDUMP_MAGIC && + magic_int != NSEC_TCPDUMP_MAGIC) + return (NULL); /* nope */ + swapped = 1; + } + + /* + * They are. Put the magic number in the header, and read + * the rest of the header. + */ + hdr.magic = magic_int; + amt_read = fread(((char *)&hdr) + sizeof hdr.magic, 1, + sizeof(hdr) - sizeof(hdr.magic), fp); + if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + } else { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %zu file header bytes, only got %zu", + sizeof(hdr), amt_read); + } + *err = 1; + return (NULL); + } + + /* + * If it's a byte-swapped capture file, byte-swap the header. + */ + if (swapped) { + hdr.version_major = SWAPSHORT(hdr.version_major); + hdr.version_minor = SWAPSHORT(hdr.version_minor); + hdr.thiszone = SWAPLONG(hdr.thiszone); + hdr.sigfigs = SWAPLONG(hdr.sigfigs); + hdr.snaplen = SWAPLONG(hdr.snaplen); + hdr.linktype = SWAPLONG(hdr.linktype); + } + + if (hdr.version_major < PCAP_VERSION_MAJOR) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "archaic pcap savefile format"); + *err = 1; + return (NULL); + } + + /* + * currently only versions 2.[0-4] are supported with + * the exception of 543.0 for DG/UX tcpdump. + */ + if (! ((hdr.version_major == PCAP_VERSION_MAJOR && + hdr.version_minor <= PCAP_VERSION_MINOR) || + (hdr.version_major == 543 && + hdr.version_minor == 0))) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unsupported pcap savefile version %u.%u", + hdr.version_major, hdr.version_minor); + *err = 1; + return NULL; + } + + /* + * Check the main reserved field. + */ + if (LT_RESERVED1(hdr.linktype) != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "savefile linktype reserved field not zero (0x%08x)", + LT_RESERVED1(hdr.linktype)); + *err = 1; + return NULL; + } + + /* + * OK, this is a good pcap file. + * Allocate a pcap_t for it. + */ + p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_sf); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); + } + p->swapped = swapped; + p->version_major = hdr.version_major; + p->version_minor = hdr.version_minor; + p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); + p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); + p->snapshot = pcapint_adjust_snapshot(p->linktype, hdr.snaplen); + + p->next_packet_op = pcap_next_packet; + + ps = p->priv; + + p->opt.tstamp_precision = precision; + + /* + * Will we need to scale the timestamps to match what the + * user wants? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + if (magic_int == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the user + * wants microseconds; scale the + * precision down. + */ + ps->scale_type = SCALE_DOWN; + } else { + /* + * The file has microseconds, the + * user wants microseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } + break; + + case PCAP_TSTAMP_PRECISION_NANO: + if (magic_int == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the + * user wants nanoseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } else { + /* + * The file has microseconds, the user + * wants nanoseconds; scale the + * precision up. + */ + ps->scale_type = SCALE_UP; + } + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } + + /* + * We interchanged the caplen and len fields at version 2.3, + * in order to match the bpf header layout. But unfortunately + * some files were written with version 2.3 in their headers + * but without the interchanged fields. + * + * In addition, DG/UX tcpdump writes out files with a version + * number of 543.0, and with the caplen and len fields in the + * pre-2.3 order. + */ + switch (hdr.version_major) { + + case 2: + if (hdr.version_minor < 3) + ps->lengths_swapped = SWAPPED; + else if (hdr.version_minor == 3) + ps->lengths_swapped = MAYBE_SWAPPED; + else + ps->lengths_swapped = NOT_SWAPPED; + break; + + case 543: + ps->lengths_swapped = SWAPPED; + break; + + default: + ps->lengths_swapped = NOT_SWAPPED; + break; + } + + if (magic_int == KUZNETZOV_TCPDUMP_MAGIC) { + /* + * XXX - the patch that's in some versions of libpcap + * changes the packet header but not the magic number, + * and some other versions with this magic number have + * some extra debugging information in the packet header; + * we'd have to use some hacks^H^H^H^H^Hheuristics to + * detect those variants. + * + * Ethereal does that, but it does so by trying to read + * the first two packets of the file with each of the + * record header formats. That currently means it seeks + * backwards and retries the reads, which doesn't work + * on pipes. We want to be able to read from a pipe, so + * that strategy won't work; we'd have to buffer some + * data ourselves and read from that buffer in order to + * make that work. + */ + ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); + + if (p->linktype == DLT_EN10MB) { + /* + * This capture might have been done in raw mode + * or cooked mode. + * + * If it was done in cooked mode, p->snapshot was + * passed to recvfrom() as the buffer size, meaning + * that the most packet data that would be copied + * would be p->snapshot. However, a faked Ethernet + * header would then have been added to it, so the + * most data that would be in a packet in the file + * would be p->snapshot + 14. + * + * We can't easily tell whether the capture was done + * in raw mode or cooked mode, so we'll assume it was + * cooked mode, and add 14 to the snapshot length. + * That means that, for a raw capture, the snapshot + * length will be misleading if you use it to figure + * out why a capture doesn't have all the packet data, + * but there's not much we can do to avoid that. + * + * But don't grow the snapshot length past the + * maximum value of an int. + */ + if (p->snapshot <= INT_MAX - 14) + p->snapshot += 14; + else + p->snapshot = INT_MAX; + } + } else + ps->hdrsize = sizeof(struct pcap_sf_pkthdr); + + /* + * Allocate a buffer for the packet data. + * Choose the minimum of the file's snapshot length and 2K bytes; + * that should be enough for most network packets - we'll grow it + * if necessary. That way, we don't allocate a huge chunk of + * memory just because there's a huge snapshot length, as the + * snapshot length might be larger than the size of the largest + * packet. + */ + p->bufsize = p->snapshot; + if (p->bufsize > 2048) + p->bufsize = 2048; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); + } + + p->cleanup_op = pcapint_sf_cleanup; + + return (p); +} + +/* + * Grow the packet buffer to the specified size. + */ +static int +grow_buffer(pcap_t *p, u_int bufsize) +{ + void *bigger_buffer; + + bigger_buffer = realloc(p->buffer, bufsize); + if (bigger_buffer == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + return (0); + } + p->buffer = bigger_buffer; + p->bufsize = bufsize; + return (1); +} + +/* + * Read and return the next packet from the savefile. Return the header + * in hdr and a pointer to the contents in data. Return 1 on success, 0 + * if there were no more packets, and -1 on an error. + */ +static int +pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) +{ + struct pcap_sf *ps = p->priv; + struct pcap_sf_patched_pkthdr sf_hdr; + FILE *fp = p->rfile; + size_t amt_read; + bpf_u_int32 t; + + /* + * Read the packet header; the structure we use as a buffer + * is the longer structure for files generated by the patched + * libpcap, but if the file has the magic number for an + * unpatched libpcap we only read as many bytes as the regular + * header has. + */ + amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); + if (amt_read != ps->hdrsize) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + return (-1); + } else { + if (amt_read != 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %zu header bytes, only got %zu", + ps->hdrsize, amt_read); + return (-1); + } + /* EOF */ + return (0); + } + } + + if (p->swapped) { + /* these were written in opposite byte order */ + hdr->caplen = SWAPLONG(sf_hdr.caplen); + hdr->len = SWAPLONG(sf_hdr.len); + hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); + hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); + } else { + hdr->caplen = sf_hdr.caplen; + hdr->len = sf_hdr.len; + hdr->ts.tv_sec = sf_hdr.ts.tv_sec; + hdr->ts.tv_usec = sf_hdr.ts.tv_usec; + } + + switch (ps->scale_type) { + + case PASS_THROUGH: + /* + * Just pass the time stamp through. + */ + break; + + case SCALE_UP: + /* + * File has microseconds, user wants nanoseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; + break; + + case SCALE_DOWN: + /* + * File has nanoseconds, user wants microseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; + break; + } + + /* Swap the caplen and len fields, if necessary. */ + switch (ps->lengths_swapped) { + + case NOT_SWAPPED: + break; + + case MAYBE_SWAPPED: + if (hdr->caplen <= hdr->len) { + /* + * The captured length is <= the actual length, + * so presumably they weren't swapped. + */ + break; + } + /* FALLTHROUGH */ + + case SWAPPED: + t = hdr->caplen; + hdr->caplen = hdr->len; + hdr->len = t; + break; + } + + /* + * Is the packet bigger than we consider sane? + */ + if (hdr->caplen > max_snaplen_for_dlt(p->linktype)) { + /* + * Yes. This may be a damaged or fuzzed file. + * + * Is it bigger than the snapshot length? + * (We don't treat that as an error if it's not + * bigger than the maximum we consider sane; see + * below.) + */ + if (hdr->caplen > (bpf_u_int32)p->snapshot) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "invalid packet capture length %u, bigger than " + "snaplen of %d", hdr->caplen, p->snapshot); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "invalid packet capture length %u, bigger than " + "maximum of %u", hdr->caplen, + max_snaplen_for_dlt(p->linktype)); + } + return (-1); + } + + if (hdr->caplen > (bpf_u_int32)p->snapshot) { + /* + * The packet is bigger than the snapshot length + * for this file. + * + * This can happen due to Solaris 2.3 systems tripping + * over the BUFMOD problem and not setting the snapshot + * length correctly in the savefile header. + * + * libpcap 0.4 and later on Solaris 2.3 should set the + * snapshot length correctly in the pcap file header, + * even though they don't set a snapshot length in bufmod + * (the buggy bufmod chops off the *beginning* of the + * packet if a snapshot length is specified); they should + * also reduce the captured length, as supplied to the + * per-packet callback, to the snapshot length if it's + * greater than the snapshot length, so the code using + * libpcap should see the packet cut off at the snapshot + * length, even though the full packet is copied up to + * userland. + * + * However, perhaps some versions of libpcap failed to + * set the snapshot length correctly in the file header + * or the per-packet header, or perhaps this is a + * corrupted savefile or a savefile built/modified by a + * fuzz tester, so we check anyway. We grow the buffer + * to be big enough for the snapshot length, read up + * to the snapshot length, discard the rest of the + * packet, and report the snapshot length as the captured + * length; we don't want to hand our caller a packet + * bigger than the snapshot length, because they might + * be assuming they'll never be handed such a packet, + * and might copy the packet into a snapshot-length- + * sized buffer, assuming it'll fit. + */ + size_t bytes_to_discard; + size_t bytes_to_read, bytes_read; + char discard_buf[4096]; + + if (hdr->caplen > p->bufsize) { + /* + * Grow the buffer to the snapshot length. + */ + if (!grow_buffer(p, p->snapshot)) + return (-1); + } + + /* + * Read the first p->snapshot bytes into the buffer. + */ + amt_read = fread(p->buffer, 1, p->snapshot, fp); + if (amt_read != (bpf_u_int32)p->snapshot) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "error reading dump file"); + } else { + /* + * Yes, this uses hdr->caplen; technically, + * it's true, because we would try to read + * and discard the rest of those bytes, and + * that would fail because we got EOF before + * the read finished. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %d captured bytes, only got %zu", + p->snapshot, amt_read); + } + return (-1); + } + + /* + * Now read and discard what's left. + */ + bytes_to_discard = hdr->caplen - p->snapshot; + bytes_read = amt_read; + while (bytes_to_discard != 0) { + bytes_to_read = bytes_to_discard; + if (bytes_to_read > sizeof (discard_buf)) + bytes_to_read = sizeof (discard_buf); + amt_read = fread(discard_buf, 1, bytes_to_read, fp); + bytes_read += amt_read; + if (amt_read != bytes_to_read) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "error reading dump file"); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %zu", + hdr->caplen, bytes_read); + } + return (-1); + } + bytes_to_discard -= amt_read; + } + + /* + * Adjust caplen accordingly, so we don't get confused later + * as to how many bytes we have to play with. + */ + hdr->caplen = p->snapshot; + } else { + /* + * The packet is within the snapshot length for this file. + */ + if (hdr->caplen > p->bufsize) { + /* + * Grow the buffer to the next power of 2, or + * the snaplen, whichever is lower. + */ + u_int new_bufsize; + + new_bufsize = hdr->caplen; + /* + * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + */ + new_bufsize--; + new_bufsize |= new_bufsize >> 1; + new_bufsize |= new_bufsize >> 2; + new_bufsize |= new_bufsize >> 4; + new_bufsize |= new_bufsize >> 8; + new_bufsize |= new_bufsize >> 16; + new_bufsize++; + + if (new_bufsize > (u_int)p->snapshot) + new_bufsize = p->snapshot; + + if (!grow_buffer(p, new_bufsize)) + return (-1); + } + + /* read the packet itself */ + amt_read = fread(p->buffer, 1, hdr->caplen, fp); + if (amt_read != hdr->caplen) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "error reading dump file"); + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %zu", + hdr->caplen, amt_read); + } + return (-1); + } + } + *data = p->buffer; + + pcapint_post_process(p->linktype, p->swapped, hdr, *data); + + return (1); +} + +static int +sf_write_header(pcap_t *p, FILE *fp, int linktype, int snaplen) +{ + struct pcap_file_header hdr; + + hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + + /* + * https://www.tcpdump.org/manpages/pcap-savefile.5.txt states: + * thiszone (Reserved1): 4-byte not used - SHOULD be filled with 0 + * sigfigs (Reserved2): 4-byte not used - SHOULD be filled with 0 + */ + hdr.thiszone = 0; + hdr.sigfigs = 0; + hdr.snaplen = snaplen; + hdr.linktype = linktype; + + if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) + return (-1); + + return (0); +} + +/* + * Output a packet to the initialized dump file. + */ +void +pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) +{ + register FILE *f; + struct pcap_sf_pkthdr sf_hdr; + + f = (FILE *)user; + /* + * If the output file handle is in an error state, don't write + * anything. + * + * While in principle a file handle can return from an error state + * to a normal state (for example if a disk that is full has space + * freed), we have possibly left a broken file already, and won't + * be able to clean it up. The safest option is to do nothing. + * + * Note that if we could guarantee that fwrite() was atomic we + * might be able to insure that we don't produce a corrupted file, + * but the standard defines fwrite() as a series of fputc() calls, + * so we really have no insurance that things are not fubared. + * + * http://pubs.opengroup.org/onlinepubs/009695399/functions/fwrite.html + */ + if (ferror(f)) + return; + /* + * Better not try writing pcap files after + * 2106-02-07 06:28:15 UTC; switch to pcapng. + * (And better not try writing pcap files with time stamps + * that predate 1970-01-01 00:00:00 UTC; that's not supported. + * You could try using pcapng with the if_tsoffset field in + * the IDB for the interface(s) with packets with those time + * stamps, but you may also have to get a link-layer type for + * IBM Bisync or whatever link layer even older forms + * of computer communication used.) + */ + sf_hdr.ts.tv_sec = (bpf_u_int32)h->ts.tv_sec; + sf_hdr.ts.tv_usec = (bpf_u_int32)h->ts.tv_usec; + sf_hdr.caplen = h->caplen; + sf_hdr.len = h->len; + /* + * We only write the packet if we can write the header properly. + * + * This doesn't prevent us from having corrupted output, and if we + * for some reason don't get a complete write we don't have any + * way to set ferror() to prevent future writes from being + * attempted, but it is better than nothing. + */ + if (fwrite(&sf_hdr, sizeof(sf_hdr), 1, f) == 1) { + (void)fwrite(sp, h->caplen, 1, f); + } +} + +static pcap_dumper_t * +pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) +{ + +#if defined(_WIN32) || defined(MSDOS) + /* + * If we're writing to the standard output, put it in binary + * mode, as savefiles are binary files. + * + * Otherwise, we turn off buffering. + * XXX - why? And why not on the standard output? + */ + if (f == stdout) + SET_BINMODE(f); + else + setvbuf(f, NULL, _IONBF, 0); +#endif + if (sf_write_header(p, f, linktype, p->snapshot) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't write to %s", fname); + if (f != stdout) + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + +/* + * Initialize so that sf_write() will output to the file named 'fname'. + */ +pcap_dumper_t * +pcap_dump_open(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + + /* + * If this pcap_t hasn't been activated, it doesn't have a + * link-layer type, so we can't use it. + */ + if (!p->activated) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not-yet-activated pcap_t passed to pcap_dump_open", + fname); + return (NULL); + } + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, p->linktype); + return (NULL); + } + linktype |= p->linktype_ext; + + if (fname == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } + if (fname[0] == '-' && fname[1] == '\0') { + f = stdout; + fname = "standard output"; + } else { + /* + * "b" is supported as of C90, so *all* UN*Xes should + * support it, even though it does nothing. It's + * required on Windows, as the file is a binary file + * and must be written in binary mode. + */ + f = pcapint_charset_fopen(fname, "wb"); + if (f == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s", fname); + return (NULL); + } + } + return (pcap_setup_dump(p, linktype, f, fname)); +} + +#ifdef _WIN32 +/* + * Initialize so that sf_write() will output to a stream wrapping the given raw + * OS file HANDLE. + */ +pcap_dumper_t * +pcap_dump_hopen(pcap_t *p, intptr_t osfd) +{ + int fd; + FILE *file; + + fd = _open_osfhandle(osfd, _O_APPEND); + if (fd < 0) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "_open_osfhandle"); + return NULL; + } + + file = _fdopen(fd, "wb"); + if (file == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "_fdopen"); + _close(fd); + return NULL; + } + + return pcap_dump_fopen(p, file); +} +#endif /* _WIN32 */ + +/* + * Initialize so that sf_write() will output to the given stream. + */ +#ifdef _WIN32 +static +#endif /* _WIN32 */ +pcap_dumper_t * +pcap_dump_fopen(pcap_t *p, FILE *f) +{ + int linktype; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "stream: link-layer type %d isn't supported in savefiles", + p->linktype); + return (NULL); + } + linktype |= p->linktype_ext; + + return (pcap_setup_dump(p, linktype, f, "stream")); +} + +pcap_dumper_t * +pcap_dump_open_append(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + size_t amt_read; + struct pcap_file_header ph; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, linktype); + return (NULL); + } + + if (fname == NULL) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } + if (fname[0] == '-' && fname[1] == '\0') + return (pcap_setup_dump(p, linktype, stdout, "standard output")); + + /* + * "a" will cause the file *not* to be truncated if it exists + * but will cause it to be created if it doesn't. It will + * also cause all writes to be done at the end of the file, + * but will allow reads to be done anywhere in the file. This + * is what we need, because we need to read from the beginning + * of the file to see if it already has a header and packets + * or if it doesn't. + * + * "b" is supported as of C90, so *all* UN*Xes should support it, + * even though it does nothing. It's required on Windows, as the + * file is a binary file and must be read in binary mode. + */ + f = pcapint_charset_fopen(fname, "ab+"); + if (f == NULL) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s", fname); + return (NULL); + } + + /* + * Try to read a pcap header. + * + * We do not assume that the file will be positioned at the + * beginning immediately after we've opened it - we seek to + * the beginning. ISO C says it's implementation-defined + * whether the file position indicator is at the beginning + * or the end of the file after an append-mode open, and + * it wasn't obvious from the Single UNIX Specification + * or the Microsoft documentation how that works on SUS- + * compliant systems or on Windows. + */ + if (fseek(f, 0, SEEK_SET) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't seek to the beginning of %s", fname); + (void)fclose(f); + return (NULL); + } + amt_read = fread(&ph, 1, sizeof (ph), f); + if (amt_read != sizeof (ph)) { + if (ferror(f)) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "%s", fname); + (void)fclose(f); + return (NULL); + } else if (feof(f) && amt_read > 0) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: truncated pcap file header", fname); + (void)fclose(f); + return (NULL); + } + } + +#if defined(_WIN32) || defined(MSDOS) + /* + * We turn off buffering. + * XXX - why? And why not on the standard output? + */ + setvbuf(f, NULL, _IONBF, 0); +#endif + + /* + * If a header is already present and: + * + * it's not for a pcap file of the appropriate resolution + * and the right byte order for this machine; + * + * the link-layer header types don't match; + * + * the snapshot lengths don't match; + * + * return an error. + */ + if (amt_read > 0) { + /* + * A header is already present. + * Do the checks. + */ + switch (ph.magic) { + + case TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + (void)fclose(f); + return (NULL); + } + break; + + case NSEC_TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + (void)fclose(f); + return (NULL); + } + break; + + case SWAPLONG(TCPDUMP_MAGIC): + case SWAPLONG(NSEC_TCPDUMP_MAGIC): + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different byte order, cannot append to file", fname); + (void)fclose(f); + return (NULL); + + case KUZNETZOV_TCPDUMP_MAGIC: + case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): + case NAVTEL_TCPDUMP_MAGIC: + case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file to which we can append", fname); + (void)fclose(f); + return (NULL); + + default: + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file", fname); + (void)fclose(f); + return (NULL); + } + + /* + * Good version? + */ + if (ph.version_major != PCAP_VERSION_MAJOR || + ph.version_minor != PCAP_VERSION_MINOR) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: version is %u.%u, cannot append to file", fname, + ph.version_major, ph.version_minor); + (void)fclose(f); + return (NULL); + } + if ((bpf_u_int32)linktype != ph.linktype) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different linktype, cannot append to file", fname); + (void)fclose(f); + return (NULL); + } + if ((bpf_u_int32)p->snapshot != ph.snaplen) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different snaplen, cannot append to file", fname); + (void)fclose(f); + return (NULL); + } + } else { + /* + * A header isn't present; attempt to write it. + */ + if (sf_write_header(p, f, linktype, p->snapshot) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't write to %s", fname); + (void)fclose(f); + return (NULL); + } + } + + /* + * Start writing at the end of the file. + * + * XXX - this shouldn't be necessary, given that we're opening + * the file in append mode, and ISO C specifies that all writes + * are done at the end of the file in that mode. + */ + if (fseek(f, 0, SEEK_END) == -1) { + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "Can't seek to the end of %s", fname); + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + +FILE * +pcap_dump_file(pcap_dumper_t *p) +{ + return ((FILE *)p); +} + +long +pcap_dump_ftell(pcap_dumper_t *p) +{ + return (ftell((FILE *)p)); +} + +#if defined(HAVE_FSEEKO) +/* + * We have fseeko(), so we have ftello(). + * If we have large file support (files larger than 2^31-1 bytes), + * ftello() will give us a current file position with more than 32 + * bits. + */ +int64_t +pcap_dump_ftell64(pcap_dumper_t *p) +{ + return (ftello((FILE *)p)); +} +#elif defined(_MSC_VER) +/* + * We have Visual Studio; we support only 2005 and later, so we have + * _ftelli64(). + */ +int64_t +pcap_dump_ftell64(pcap_dumper_t *p) +{ + return (_ftelli64((FILE *)p)); +} +#else +/* + * We don't have ftello() or _ftelli64(), so fall back on ftell(). + * Either long is 64 bits, in which case ftell() should suffice, + * or this is probably an older 32-bit UN*X without large file + * support, which means you'll probably get errors trying to + * write files > 2^31-1, so it won't matter anyway. + * + * XXX - what about MinGW? + */ +int64_t +pcap_dump_ftell64(pcap_dumper_t *p) +{ + return (ftell((FILE *)p)); +} +#endif + +int +pcap_dump_flush(pcap_dumper_t *p) +{ + + if (fflush((FILE *)p) == EOF) + return (-1); + else + return (0); +} + +void +pcap_dump_close(pcap_dumper_t *p) +{ + +#ifdef notyet + if (ferror((FILE *)p)) + return-an-error; + /* XXX should check return from fclose() too */ +#endif + (void)fclose((FILE *)p); +} diff --git a/src/libpcap-1.10.5/sf-pcap.h b/src/libpcap-1.10.5/sf-pcap.h new file mode 100644 index 0000000000..bc7150f4f4 --- /dev/null +++ b/src/libpcap-1.10.5/sf-pcap.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcap.h - libpcap-file-format-specific routines + * Extraction/creation by Jeffrey Mogul, DECWRL + * Modified by Steve McCanne, LBL. + * + * Used to save the received packet headers, after filtering, to + * a file, and then read them later. + * The first record in the file contains saved values for the machine + * dependent values so we can print the dump file on any architecture. + */ + +#ifndef sf_pcap_h +#define sf_pcap_h + +extern pcap_t *pcap_check_header(const uint8_t *magic, FILE *fp, + u_int precision, char *errbuf, int *err); + +#endif diff --git a/src/libpcap-1.10.5/sf-pcapng.c b/src/libpcap-1.10.5/sf-pcapng.c new file mode 100644 index 0000000000..2a756b4f90 --- /dev/null +++ b/src/libpcap-1.10.5/sf-pcapng.c @@ -0,0 +1,1516 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcapng.c - pcapng-file-format-specific code from savefile.c + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "pcap-int.h" +#include "pcap-util.h" + +#include "pcap-common.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#include "sf-pcapng.h" + +/* + * Block types. + */ + +/* + * Common part at the beginning of all blocks. + */ +struct block_header { + bpf_u_int32 block_type; + bpf_u_int32 total_length; +}; + +/* + * Common trailer at the end of all blocks. + */ +struct block_trailer { + bpf_u_int32 total_length; +}; + +/* + * Common options. + */ +#define OPT_ENDOFOPT 0 /* end of options */ +#define OPT_COMMENT 1 /* comment string */ + +/* + * Option header. + */ +struct option_header { + u_short option_code; + u_short option_length; +}; + +/* + * Structures for the part of each block type following the common + * part. + */ + +/* + * Section Header Block. + */ +#define BT_SHB 0x0A0D0D0A +#define BT_SHB_INSANE_MAX 1024U*1024U*1U /* 1MB should be enough */ +struct section_header_block { + bpf_u_int32 byte_order_magic; + u_short major_version; + u_short minor_version; + uint64_t section_length; + /* followed by options and trailer */ +}; + +/* + * Byte-order magic value. + */ +#define BYTE_ORDER_MAGIC 0x1A2B3C4D + +/* + * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR, + * or if minor_version isn't PCAP_NG_VERSION_MINOR or 2, that means that + * this code can't read the file. + */ +#define PCAP_NG_VERSION_MAJOR 1 +#define PCAP_NG_VERSION_MINOR 0 + +/* + * Interface Description Block. + */ +#define BT_IDB 0x00000001 + +struct interface_description_block { + u_short linktype; + u_short reserved; + bpf_u_int32 snaplen; + /* followed by options and trailer */ +}; + +/* + * Options in the IDB. + */ +#define IF_NAME 2 /* interface name string */ +#define IF_DESCRIPTION 3 /* interface description string */ +#define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */ +#define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */ +#define IF_MACADDR 6 /* interface's MAC address */ +#define IF_EUIADDR 7 /* interface's EUI address */ +#define IF_SPEED 8 /* interface's speed, in bits/s */ +#define IF_TSRESOL 9 /* interface's time stamp resolution */ +#define IF_TZONE 10 /* interface's time zone */ +#define IF_FILTER 11 /* filter used when capturing on interface */ +#define IF_OS 12 /* string OS on which capture on this interface was done */ +#define IF_FCSLEN 13 /* FCS length for this interface */ +#define IF_TSOFFSET 14 /* time stamp offset for this interface */ + +/* + * Enhanced Packet Block. + */ +#define BT_EPB 0x00000006 + +struct enhanced_packet_block { + bpf_u_int32 interface_id; + bpf_u_int32 timestamp_high; + bpf_u_int32 timestamp_low; + bpf_u_int32 caplen; + bpf_u_int32 len; + /* followed by packet data, options, and trailer */ +}; + +/* + * Simple Packet Block. + */ +#define BT_SPB 0x00000003 + +struct simple_packet_block { + bpf_u_int32 len; + /* followed by packet data and trailer */ +}; + +/* + * Packet Block. + */ +#define BT_PB 0x00000002 + +struct packet_block { + u_short interface_id; + u_short drops_count; + bpf_u_int32 timestamp_high; + bpf_u_int32 timestamp_low; + bpf_u_int32 caplen; + bpf_u_int32 len; + /* followed by packet data, options, and trailer */ +}; + +/* + * Block cursor - used when processing the contents of a block. + * Contains a pointer into the data being processed and a count + * of bytes remaining in the block. + */ +struct block_cursor { + u_char *data; + size_t data_remaining; + bpf_u_int32 block_type; +}; + +typedef enum { + PASS_THROUGH, + SCALE_UP_DEC, + SCALE_DOWN_DEC, + SCALE_UP_BIN, + SCALE_DOWN_BIN +} tstamp_scale_type_t; + +/* + * Per-interface information. + */ +struct pcap_ng_if { + uint32_t snaplen; /* snapshot length */ + uint64_t tsresol; /* time stamp resolution */ + tstamp_scale_type_t scale_type; /* how to scale */ + uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */ + int64_t tsoffset; /* time stamp offset */ +}; + +/* + * Per-pcap_t private data. + * + * max_blocksize is the maximum size of a block that we'll accept. We + * reject blocks bigger than this, so we don't consume too much memory + * with a truly huge block. It can change as we see IDBs with different + * link-layer header types. (Currently, we don't support IDBs with + * different link-layer header types, but we will support it in the + * future, when we offer file-reading APIs that support it.) + * + * XXX - that's an issue on ILP32 platforms, where the maximum block + * size of 2^31-1 would eat all but one byte of the entire address space. + * It's less of an issue on ILP64/LLP64 platforms, but the actual size + * of the address space may be limited by 1) the number of *significant* + * address bits (currently, x86-64 only supports 48 bits of address), 2) + * any limitations imposed by the operating system; 3) any limitations + * imposed by the amount of available backing store for anonymous pages, + * so we impose a limit regardless of the size of a pointer. + */ +struct pcap_ng_sf { + uint64_t user_tsresol; /* time stamp resolution requested by the user */ + u_int max_blocksize; /* don't grow buffer size past this */ + bpf_u_int32 ifcount; /* number of interfaces seen in this capture */ + bpf_u_int32 ifaces_size; /* size of array below */ + struct pcap_ng_if *ifaces; /* array of interface information */ +}; + +/* + * The maximum block size we start with; we use an arbitrary value of + * 16 MiB. + */ +#define INITIAL_MAX_BLOCKSIZE (16*1024*1024) + +/* + * Maximum block size for a given maximum snapshot length; we define it + * as the size of an EPB with a max_snaplen-sized packet and 128KB of + * options. + */ +#define MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen) \ + (sizeof (struct block_header) + \ + sizeof (struct enhanced_packet_block) + \ + (max_snaplen) + 131072 + \ + sizeof (struct block_trailer)) + +static void pcap_ng_cleanup(pcap_t *p); +static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, + u_char **data); + +static int +read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof, + char *errbuf) +{ + size_t amt_read; + + amt_read = fread(buf, 1, bytes_to_read, fp); + if (amt_read != bytes_to_read) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + } else { + if (amt_read == 0 && !fail_on_eof) + return (0); /* EOF */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "truncated pcapng dump file; tried to read %zu bytes, only got %zu", + bytes_to_read, amt_read); + } + return (-1); + } + return (1); +} + +static int +read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + struct pcap_ng_sf *ps; + int status; + struct block_header bhdr; + struct block_trailer *btrlr; + u_char *bdata; + size_t data_remaining; + + ps = p->priv; + + status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf); + if (status <= 0) + return (status); /* error or EOF */ + + if (p->swapped) { + bhdr.block_type = SWAPLONG(bhdr.block_type); + bhdr.total_length = SWAPLONG(bhdr.total_length); + } + + /* + * Is this block "too small" - i.e., is it shorter than a block + * header plus a block trailer? + */ + if (bhdr.total_length < sizeof(struct block_header) + + sizeof(struct block_trailer)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block in pcapng dump file has a length of %u < %zu", + bhdr.total_length, + sizeof(struct block_header) + sizeof(struct block_trailer)); + return (-1); + } + + /* + * Is the block total length a multiple of 4? + */ + if ((bhdr.total_length % 4) != 0) { + /* + * No. Report that as an error. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block in pcapng dump file has a length of %u that is not a multiple of 4", + bhdr.total_length); + return (-1); + } + + /* + * Is the buffer big enough? + */ + if (p->bufsize < bhdr.total_length) { + /* + * No - make it big enough, unless it's too big, in + * which case we fail. + */ + void *bigger_buffer; + + if (bhdr.total_length > ps->max_blocksize) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcapng block size %u > maximum %u", bhdr.total_length, + ps->max_blocksize); + return (-1); + } + bigger_buffer = realloc(p->buffer, bhdr.total_length); + if (bigger_buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + return (-1); + } + p->buffer = bigger_buffer; + } + + /* + * Copy the stuff we've read to the buffer, and read the rest + * of the block. + */ + memcpy(p->buffer, &bhdr, sizeof(bhdr)); + bdata = (u_char *)p->buffer + sizeof(bhdr); + data_remaining = bhdr.total_length - sizeof(bhdr); + if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1) + return (-1); + + /* + * Get the block size from the trailer. + */ + btrlr = (struct block_trailer *)(bdata + data_remaining - sizeof (struct block_trailer)); + if (p->swapped) + btrlr->total_length = SWAPLONG(btrlr->total_length); + + /* + * Is the total length from the trailer the same as the total + * length from the header? + */ + if (bhdr.total_length != btrlr->total_length) { + /* + * No. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block total length in header and trailer don't match"); + return (-1); + } + + /* + * Initialize the cursor. + */ + cursor->data = bdata; + cursor->data_remaining = data_remaining - sizeof(struct block_trailer); + cursor->block_type = bhdr.block_type; + return (1); +} + +static void * +get_from_block_data(struct block_cursor *cursor, size_t chunk_size, + char *errbuf) +{ + void *data; + + /* + * Make sure we have the specified amount of data remaining in + * the block data. + */ + if (cursor->data_remaining < chunk_size) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "block of type %u in pcapng dump file is too short", + cursor->block_type); + return (NULL); + } + + /* + * Return the current pointer, and skip past the chunk. + */ + data = cursor->data; + cursor->data += chunk_size; + cursor->data_remaining -= chunk_size; + return (data); +} + +static struct option_header * +get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) +{ + struct option_header *opthdr; + + opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf); + if (opthdr == NULL) { + /* + * Option header is cut short. + */ + return (NULL); + } + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + opthdr->option_code = SWAPSHORT(opthdr->option_code); + opthdr->option_length = SWAPSHORT(opthdr->option_length); + } + + return (opthdr); +} + +static void * +get_optvalue_from_block_data(struct block_cursor *cursor, + struct option_header *opthdr, char *errbuf) +{ + size_t padded_option_len; + void *optvalue; + + /* Pad option length to 4-byte boundary */ + padded_option_len = opthdr->option_length; + padded_option_len = ((padded_option_len + 3)/4)*4; + + optvalue = get_from_block_data(cursor, padded_option_len, errbuf); + if (optvalue == NULL) { + /* + * Option value is cut short. + */ + return (NULL); + } + + return (optvalue); +} + +static int +process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol, + int64_t *tsoffset, int *is_binary, char *errbuf) +{ + struct option_header *opthdr; + void *optvalue; + int saw_tsresol, saw_tsoffset; + uint8_t tsresol_opt; + u_int i; + + saw_tsresol = 0; + saw_tsoffset = 0; + while (cursor->data_remaining != 0) { + /* + * Get the option header. + */ + opthdr = get_opthdr_from_block_data(p, cursor, errbuf); + if (opthdr == NULL) { + /* + * Option header is cut short. + */ + return (-1); + } + + /* + * Get option value. + */ + optvalue = get_optvalue_from_block_data(cursor, opthdr, + errbuf); + if (optvalue == NULL) { + /* + * Option value is cut short. + */ + return (-1); + } + + switch (opthdr->option_code) { + + case OPT_ENDOFOPT: + if (opthdr->option_length != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has opt_endofopt option with length %u != 0", + opthdr->option_length); + return (-1); + } + goto done; + + case IF_TSRESOL: + if (opthdr->option_length != 1) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has if_tsresol option with length %u != 1", + opthdr->option_length); + return (-1); + } + if (saw_tsresol) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has more than one if_tsresol option"); + return (-1); + } + saw_tsresol = 1; + memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); + if (tsresol_opt & 0x80) { + /* + * Resolution is negative power of 2. + */ + uint8_t tsresol_shift = (tsresol_opt & 0x7F); + + if (tsresol_shift > 63) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 2^-%u is too high", + tsresol_shift); + return (-1); + } + *is_binary = 1; + *tsresol = ((uint64_t)1) << tsresol_shift; + } else { + /* + * Resolution is negative power of 10. + */ + if (tsresol_opt > 19) { + /* + * Resolution is too high; 2^-{res} + * won't fit in a 64-bit value (the + * largest power of 10 that fits + * in a 64-bit value is 10^19, as + * the largest 64-bit unsigned + * value is ~1.8*10^19). + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block if_tsresol option resolution 10^-%u is too high", + tsresol_opt); + return (-1); + } + *is_binary = 0; + *tsresol = 1; + for (i = 0; i < tsresol_opt; i++) + *tsresol *= 10; + } + break; + + case IF_TSOFFSET: + if (opthdr->option_length != 8) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has if_tsoffset option with length %u != 8", + opthdr->option_length); + return (-1); + } + if (saw_tsoffset) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Interface Description Block has more than one if_tsoffset option"); + return (-1); + } + saw_tsoffset = 1; + memcpy(tsoffset, optvalue, sizeof(*tsoffset)); + if (p->swapped) + *tsoffset = SWAPLL(*tsoffset); + break; + + default: + break; + } + } + +done: + return (0); +} + +static int +add_interface(pcap_t *p, struct interface_description_block *idbp, + struct block_cursor *cursor, char *errbuf) +{ + struct pcap_ng_sf *ps; + uint64_t tsresol; + int64_t tsoffset; + int is_binary; + + ps = p->priv; + + /* + * Count this interface. + */ + ps->ifcount++; + + /* + * Grow the array of per-interface information as necessary. + */ + if (ps->ifcount > ps->ifaces_size) { + /* + * We need to grow the array. + */ + bpf_u_int32 new_ifaces_size; + struct pcap_ng_if *new_ifaces; + + if (ps->ifaces_size == 0) { + /* + * It's currently empty. + * + * (The Clang static analyzer doesn't do enough, + * err, umm, dataflow *analysis* to realize that + * ps->ifaces_size == 0 if ps->ifaces == NULL, + * and so complains about a possible zero argument + * to realloc(), so we check for the former + * condition to shut it up. + * + * However, it doesn't complain that one of the + * multiplications below could overflow, which is + * a real, albeit extremely unlikely, problem (you'd + * need a pcapng file with tens of millions of + * interfaces).) + */ + new_ifaces_size = 1; + new_ifaces = malloc(sizeof (struct pcap_ng_if)); + } else { + /* + * It's not currently empty; double its size. + * (Perhaps overkill once we have a lot of interfaces.) + * + * Check for overflow if we double it. + */ + if (ps->ifaces_size * 2 < ps->ifaces_size) { + /* + * The maximum number of interfaces before + * ps->ifaces_size overflows is the largest + * possible 32-bit power of 2, as we do + * size doubling. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "more than %u interfaces in the file", + 0x80000000U); + return (0); + } + + /* + * ps->ifaces_size * 2 doesn't overflow, so it's + * safe to multiply. + */ + new_ifaces_size = ps->ifaces_size * 2; + + /* + * Now make sure that's not so big that it overflows + * if we multiply by sizeof (struct pcap_ng_if). + * + * That can happen on 32-bit platforms, with a 32-bit + * size_t; it shouldn't happen on 64-bit platforms, + * with a 64-bit size_t, as new_ifaces_size is + * 32 bits. + */ + if (new_ifaces_size * sizeof (struct pcap_ng_if) < new_ifaces_size) { + /* + * As this fails only with 32-bit size_t, + * the multiplication was 32x32->32, and + * the largest 32-bit value that can safely + * be multiplied by sizeof (struct pcap_ng_if) + * without overflow is the largest 32-bit + * (unsigned) value divided by + * sizeof (struct pcap_ng_if). + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "more than %u interfaces in the file", + 0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if))); + return (0); + } + new_ifaces = realloc(ps->ifaces, new_ifaces_size * sizeof (struct pcap_ng_if)); + } + if (new_ifaces == NULL) { + /* + * We ran out of memory. + * Give up. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "out of memory for per-interface information (%u interfaces)", + ps->ifcount); + return (0); + } + ps->ifaces_size = new_ifaces_size; + ps->ifaces = new_ifaces; + } + + ps->ifaces[ps->ifcount - 1].snaplen = idbp->snaplen; + + /* + * Set the default time stamp resolution and offset. + */ + tsresol = 1000000; /* microsecond resolution */ + is_binary = 0; /* which is a power of 10 */ + tsoffset = 0; /* absolute timestamps */ + + /* + * Now look for various time stamp options, so we know + * how to interpret the time stamps for this interface. + */ + if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary, + errbuf) == -1) + return (0); + + ps->ifaces[ps->ifcount - 1].tsresol = tsresol; + ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; + + /* + * Determine whether we're scaling up or down or not + * at all for this interface. + */ + if (tsresol == ps->user_tsresol) { + /* + * The resolution is the resolution the user wants, + * so we don't have to do scaling. + */ + ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH; + } else if (tsresol > ps->user_tsresol) { + /* + * The resolution is greater than what the user wants, + * so we have to scale the timestamps down. + */ + if (is_binary) + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_BIN; + else { + /* + * Calculate the scale factor. + */ + ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol; + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC; + } + } else { + /* + * The resolution is less than what the user wants, + * so we have to scale the timestamps up. + */ + if (is_binary) + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_BIN; + else { + /* + * Calculate the scale factor. + */ + ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol; + ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC; + } + } + return (1); +} + +/* + * Check whether this is a pcapng savefile and, if it is, extract the + * relevant information from the header. + */ +pcap_t * +pcap_ng_check_header(const uint8_t *magic, FILE *fp, u_int precision, + char *errbuf, int *err) +{ + bpf_u_int32 magic_int; + size_t amt_read; + bpf_u_int32 total_length; + bpf_u_int32 byte_order_magic; + struct block_header *bhdrp; + struct section_header_block *shbp; + pcap_t *p; + int swapped = 0; + struct pcap_ng_sf *ps; + int status; + struct block_cursor cursor; + struct interface_description_block *idbp; + + /* + * Assume no read errors. + */ + *err = 0; + + /* + * Check whether the first 4 bytes of the file are the block + * type for a pcapng savefile. + */ + memcpy(&magic_int, magic, sizeof(magic_int)); + if (magic_int != BT_SHB) { + /* + * XXX - check whether this looks like what the block + * type would be after being munged by mapping between + * UN*X and DOS/Windows text file format and, if it + * does, look for the byte-order magic number in + * the appropriate place and, if we find it, report + * this as possibly being a pcapng file transferred + * between UN*X and Windows in text file format? + */ + return (NULL); /* nope */ + } + + /* + * OK, they are. However, that's just \n\r\r\n, so it could, + * conceivably, be an ordinary text file. + * + * It could not, however, conceivably be any other type of + * capture file, so we can read the rest of the putative + * Section Header Block; put the block type in the common + * header, read the rest of the common header and the + * fixed-length portion of the SHB, and look for the byte-order + * magic value. + */ + amt_read = fread(&total_length, 1, sizeof(total_length), fp); + if (amt_read < sizeof(total_length)) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + *err = 1; + return (NULL); /* fail */ + } + + /* + * Possibly a weird short text file, so just say + * "not pcapng". + */ + return (NULL); + } + amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp); + if (amt_read < sizeof(byte_order_magic)) { + if (ferror(fp)) { + pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "error reading dump file"); + *err = 1; + return (NULL); /* fail */ + } + + /* + * Possibly a weird short text file, so just say + * "not pcapng". + */ + return (NULL); + } + if (byte_order_magic != BYTE_ORDER_MAGIC) { + byte_order_magic = SWAPLONG(byte_order_magic); + if (byte_order_magic != BYTE_ORDER_MAGIC) { + /* + * Not a pcapng file. + */ + return (NULL); + } + swapped = 1; + total_length = SWAPLONG(total_length); + } + + /* + * Check the sanity of the total length. + */ + if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer) || + (total_length > BT_SHB_INSANE_MAX)) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "Section Header Block in pcapng dump file has invalid length %zu < _%u_ < %u (BT_SHB_INSANE_MAX)", + sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer), + total_length, + BT_SHB_INSANE_MAX); + + *err = 1; + return (NULL); + } + + /* + * OK, this is a good pcapng file. + * Allocate a pcap_t for it. + */ + p = PCAP_OPEN_OFFLINE_COMMON(errbuf, struct pcap_ng_sf); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); + } + p->swapped = swapped; + ps = p->priv; + + /* + * What precision does the user want? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + ps->user_tsresol = 1000000; + break; + + case PCAP_TSTAMP_PRECISION_NANO: + ps->user_tsresol = 1000000000; + break; + + default: + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } + + p->opt.tstamp_precision = precision; + + /* + * Allocate a buffer into which to read blocks. We default to + * the maximum of: + * + * the total length of the SHB for which we read the header; + * + * 2K, which should be more than large enough for an Enhanced + * Packet Block containing a full-size Ethernet frame, and + * leaving room for some options. + * + * If we find a bigger block, we reallocate the buffer, up to + * the maximum size. We start out with a maximum size of + * INITIAL_MAX_BLOCKSIZE; if we see any link-layer header types + * with a maximum snapshot that results in a larger maximum + * block length, we boost the maximum. + */ + p->bufsize = 2048; + if (p->bufsize < total_length) + p->bufsize = total_length; + p->buffer = malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); + free(p); + *err = 1; + return (NULL); + } + ps->max_blocksize = INITIAL_MAX_BLOCKSIZE; + + /* + * Copy the stuff we've read to the buffer, and read the rest + * of the SHB. + */ + bhdrp = (struct block_header *)p->buffer; + shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header)); + bhdrp->block_type = magic_int; + bhdrp->total_length = total_length; + shbp->byte_order_magic = byte_order_magic; + if (read_bytes(fp, + (u_char *)p->buffer + (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), + total_length - (sizeof(magic_int) + sizeof(total_length) + sizeof(byte_order_magic)), + 1, errbuf) == -1) + goto fail; + + if (p->swapped) { + /* + * Byte-swap the fields we've read. + */ + shbp->major_version = SWAPSHORT(shbp->major_version); + shbp->minor_version = SWAPSHORT(shbp->minor_version); + + /* + * XXX - we don't care about the section length. + */ + } + /* Currently only SHB versions 1.0 and 1.2 are supported; + version 1.2 is treated as being the same as version 1.0. + See the current version of the pcapng specification. + + Version 1.2 is written by some programs that write additional + block types (which can be read by any code that handles them, + regardless of whether the minor version if 0 or 2, so that's + not a reason to change the minor version number). + + XXX - the pcapng specification says that readers should + just ignore sections with an unsupported version number; + presumably they can also report an error if they skip + all the way to the end of the file without finding + any versions that they support. */ + if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR && + (shbp->minor_version == PCAP_NG_VERSION_MINOR || + shbp->minor_version == 2))) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unsupported pcapng savefile version %u.%u", + shbp->major_version, shbp->minor_version); + goto fail; + } + p->version_major = shbp->major_version; + p->version_minor = shbp->minor_version; + + /* + * Save the time stamp resolution the user requested. + */ + p->opt.tstamp_precision = precision; + + /* + * Now start looking for an Interface Description Block. + */ + for (;;) { + /* + * Read the next block. + */ + status = read_block(fp, p, &cursor, errbuf); + if (status == 0) { + /* EOF - no IDB in this file */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "the capture file has no Interface Description Blocks"); + goto fail; + } + if (status == -1) + goto fail; /* error */ + switch (cursor.block_type) { + + case BT_IDB: + /* + * Get a pointer to the fixed-length portion of the + * IDB. + */ + idbp = get_from_block_data(&cursor, sizeof(*idbp), + errbuf); + if (idbp == NULL) + goto fail; /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + idbp->linktype = SWAPSHORT(idbp->linktype); + idbp->snaplen = SWAPLONG(idbp->snaplen); + } + + /* + * Try to add this interface. + */ + if (!add_interface(p, idbp, &cursor, errbuf)) + goto fail; + + goto done; + + case BT_EPB: + case BT_SPB: + case BT_PB: + /* + * Saw a packet before we saw any IDBs. That's + * not valid, as we don't know what link-layer + * encapsulation the packet has. + */ + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "the capture file has a packet block before any Interface Description Blocks"); + goto fail; + + default: + /* + * Just ignore it. + */ + break; + } + } + +done: + p->linktype = linktype_to_dlt(idbp->linktype); + p->snapshot = pcapint_adjust_snapshot(p->linktype, idbp->snaplen); + p->linktype_ext = 0; + + /* + * If the maximum block size for a packet with the maximum + * snapshot length for this DLT_ is bigger than the current + * maximum block size, increase the maximum. + */ + if (MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize) + ps->max_blocksize = MAX_BLOCKSIZE_FOR_SNAPLEN(max_snaplen_for_dlt(p->linktype)); + + p->next_packet_op = pcap_ng_next_packet; + p->cleanup_op = pcap_ng_cleanup; + + return (p); + +fail: + free(ps->ifaces); + free(p->buffer); + free(p); + *err = 1; + return (NULL); +} + +static void +pcap_ng_cleanup(pcap_t *p) +{ + struct pcap_ng_sf *ps = p->priv; + + free(ps->ifaces); + pcapint_sf_cleanup(p); +} + +/* + * Read and return the next packet from the savefile. Return the header + * in hdr and a pointer to the contents in data. Return 1 on success, 0 + * if there were no more packets, and -1 on an error. + */ +static int +pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) +{ + struct pcap_ng_sf *ps = p->priv; + struct block_cursor cursor; + int status; + struct enhanced_packet_block *epbp; + struct simple_packet_block *spbp; + struct packet_block *pbp; + bpf_u_int32 interface_id = 0xFFFFFFFF; + struct interface_description_block *idbp; + struct section_header_block *shbp; + FILE *fp = p->rfile; + uint64_t t, sec, frac; + + /* + * Look for an Enhanced Packet Block, a Simple Packet Block, + * or a Packet Block. + */ + for (;;) { + /* + * Read the block type and length; those are common + * to all blocks. + */ + status = read_block(fp, p, &cursor, p->errbuf); + if (status == 0) + return (0); /* EOF */ + if (status == -1) + return (-1); /* error */ + switch (cursor.block_type) { + + case BT_EPB: + /* + * Get a pointer to the fixed-length portion of the + * EPB. + */ + epbp = get_from_block_data(&cursor, sizeof(*epbp), + p->errbuf); + if (epbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + interface_id = SWAPLONG(epbp->interface_id); + hdr->caplen = SWAPLONG(epbp->caplen); + hdr->len = SWAPLONG(epbp->len); + t = ((uint64_t)SWAPLONG(epbp->timestamp_high)) << 32 | + SWAPLONG(epbp->timestamp_low); + } else { + interface_id = epbp->interface_id; + hdr->caplen = epbp->caplen; + hdr->len = epbp->len; + t = ((uint64_t)epbp->timestamp_high) << 32 | + epbp->timestamp_low; + } + goto found; + + case BT_SPB: + /* + * Get a pointer to the fixed-length portion of the + * SPB. + */ + spbp = get_from_block_data(&cursor, sizeof(*spbp), + p->errbuf); + if (spbp == NULL) + return (-1); /* error */ + + /* + * SPB packets are assumed to have arrived on + * the first interface. + */ + interface_id = 0; + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + hdr->len = SWAPLONG(spbp->len); + } else + hdr->len = spbp->len; + + /* + * The SPB doesn't give the captured length; + * it's the minimum of the snapshot length + * and the packet length. + */ + hdr->caplen = hdr->len; + if (hdr->caplen > (bpf_u_int32)p->snapshot) + hdr->caplen = p->snapshot; + t = 0; /* no time stamps */ + goto found; + + case BT_PB: + /* + * Get a pointer to the fixed-length portion of the + * PB. + */ + pbp = get_from_block_data(&cursor, sizeof(*pbp), + p->errbuf); + if (pbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + /* these were written in opposite byte order */ + interface_id = SWAPSHORT(pbp->interface_id); + hdr->caplen = SWAPLONG(pbp->caplen); + hdr->len = SWAPLONG(pbp->len); + t = ((uint64_t)SWAPLONG(pbp->timestamp_high)) << 32 | + SWAPLONG(pbp->timestamp_low); + } else { + interface_id = pbp->interface_id; + hdr->caplen = pbp->caplen; + hdr->len = pbp->len; + t = ((uint64_t)pbp->timestamp_high) << 32 | + pbp->timestamp_low; + } + goto found; + + case BT_IDB: + /* + * Interface Description Block. Get a pointer + * to its fixed-length portion. + */ + idbp = get_from_block_data(&cursor, sizeof(*idbp), + p->errbuf); + if (idbp == NULL) + return (-1); /* error */ + + /* + * Byte-swap it if necessary. + */ + if (p->swapped) { + idbp->linktype = SWAPSHORT(idbp->linktype); + idbp->snaplen = SWAPLONG(idbp->snaplen); + } + + /* + * If the link-layer type or snapshot length + * differ from the ones for the first IDB we + * saw, quit. + * + * XXX - just discard packets from those + * interfaces? + */ + if (p->linktype != idbp->linktype) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "an interface has a type %u different from the type of the first interface", + idbp->linktype); + return (-1); + } + + /* + * Check against the *adjusted* value of this IDB's + * snapshot length. + */ + if ((bpf_u_int32)p->snapshot != + pcapint_adjust_snapshot(p->linktype, idbp->snaplen)) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "an interface has a snapshot length %u different from the snapshot length of the first interface", + idbp->snaplen); + return (-1); + } + + /* + * Try to add this interface. + */ + if (!add_interface(p, idbp, &cursor, p->errbuf)) + return (-1); + break; + + case BT_SHB: + /* + * Section Header Block. Get a pointer + * to its fixed-length portion. + */ + shbp = get_from_block_data(&cursor, sizeof(*shbp), + p->errbuf); + if (shbp == NULL) + return (-1); /* error */ + + /* + * Assume the byte order of this section is + * the same as that of the previous section. + * We'll check for that later. + */ + if (p->swapped) { + shbp->byte_order_magic = + SWAPLONG(shbp->byte_order_magic); + shbp->major_version = + SWAPSHORT(shbp->major_version); + } + + /* + * Make sure the byte order doesn't change; + * pcap_is_swapped() shouldn't change its + * return value in the middle of reading a capture. + */ + switch (shbp->byte_order_magic) { + + case BYTE_ORDER_MAGIC: + /* + * OK. + */ + break; + + case SWAPLONG(BYTE_ORDER_MAGIC): + /* + * Byte order changes. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "the file has sections with different byte orders"); + return (-1); + + default: + /* + * Not a valid SHB. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "the file has a section with a bad byte order magic field"); + return (-1); + } + + /* + * Make sure the major version is the version + * we handle. + */ + if (shbp->major_version != PCAP_NG_VERSION_MAJOR) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "unknown pcapng savefile major version number %u", + shbp->major_version); + return (-1); + } + + /* + * Reset the interface count; this section should + * have its own set of IDBs. If any of them + * don't have the same interface type, snapshot + * length, or resolution as the first interface + * we saw, we'll fail. (And if we don't see + * any IDBs, we'll fail when we see a packet + * block.) + */ + ps->ifcount = 0; + break; + + default: + /* + * Not a packet block, IDB, or SHB; ignore it. + */ + break; + } + } + +found: + /* + * Is the interface ID an interface we know? + */ + if (interface_id >= ps->ifcount) { + /* + * Yes. Fail. + */ + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "a packet arrived on interface %u, but there's no Interface Description Block for that interface", + interface_id); + return (-1); + } + + if (hdr->caplen > (bpf_u_int32)p->snapshot) { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "invalid packet capture length %u, bigger than " + "snaplen of %d", hdr->caplen, p->snapshot); + return (-1); + } + + /* + * Convert the time stamp to seconds and fractions of a second, + * with the fractions being in units of the file-supplied resolution. + */ + sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; + frac = t % ps->ifaces[interface_id].tsresol; + + /* + * Convert the fractions from units of the file-supplied resolution + * to units of the user-requested resolution. + */ + switch (ps->ifaces[interface_id].scale_type) { + + case PASS_THROUGH: + /* + * The interface resolution is what the user wants, + * so we're done. + */ + break; + + case SCALE_UP_DEC: + /* + * The interface resolution is less than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * Those resolutions are both powers of 10, and the user- + * requested resolution is greater than the file-supplied + * resolution, so the quotient in question is an integer. + * We've calculated that quotient already, so we just + * multiply by it. + */ + frac *= ps->ifaces[interface_id].scale_factor; + break; + + case SCALE_UP_BIN: + /* + * The interface resolution is less than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * The file-supplied resolution is a power of 2, so the + * quotient is not an integer, so, in order to do this + * entirely with integer arithmetic, we multiply by the + * user-requested resolution and divide by the file- + * supplied resolution. + * + * XXX - Is there something clever we could do here, + * given that we know that the file-supplied resolution + * is a power of 2? Doing a multiplication followed by + * a division runs the risk of overflowing, and involves + * two non-simple arithmetic operations. + */ + frac *= ps->user_tsresol; + frac /= ps->ifaces[interface_id].tsresol; + break; + + case SCALE_DOWN_DEC: + /* + * The interface resolution is greater than what the user + * wants; scale the fractional part up to the units of + * the resolution the user requested by multiplying by + * the quotient of the user-requested resolution and the + * file-supplied resolution. + * + * Those resolutions are both powers of 10, and the user- + * requested resolution is less than the file-supplied + * resolution, so the quotient in question isn't an + * integer, but its reciprocal is, and we can just divide + * by the reciprocal of the quotient. We've calculated + * the reciprocal of that quotient already, so we must + * divide by it. + */ + frac /= ps->ifaces[interface_id].scale_factor; + break; + + + case SCALE_DOWN_BIN: + /* + * The interface resolution is greater than what the user + * wants; convert the fractional part to units of the + * resolution the user requested by multiplying by the + * quotient of the user-requested resolution and the + * file-supplied resolution. We do that by multiplying + * by the user-requested resolution and dividing by the + * file-supplied resolution, as the quotient might not + * fit in an integer. + * + * The file-supplied resolution is a power of 2, so the + * quotient is not an integer, and neither is its + * reciprocal, so, in order to do this entirely with + * integer arithmetic, we multiply by the user-requested + * resolution and divide by the file-supplied resolution. + * + * XXX - Is there something clever we could do here, + * given that we know that the file-supplied resolution + * is a power of 2? Doing a multiplication followed by + * a division runs the risk of overflowing, and involves + * two non-simple arithmetic operations. + */ + frac *= ps->user_tsresol; + frac /= ps->ifaces[interface_id].tsresol; + break; + } +#ifdef _WIN32 + /* + * tv_sec and tv_usec in the Windows struct timeval are both + * longs. + */ + hdr->ts.tv_sec = (long)sec; + hdr->ts.tv_usec = (long)frac; +#else + /* + * tv_sec in the UN*X struct timeval is a time_t; tv_usec is + * suseconds_t in UN*Xes that work the way the current Single + * UNIX Standard specify - but not all older UN*Xes necessarily + * support that type, so just cast to int. + */ + hdr->ts.tv_sec = (time_t)sec; + hdr->ts.tv_usec = (int)frac; +#endif + + /* + * Get a pointer to the packet data. + */ + *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf); + if (*data == NULL) + return (-1); + + pcapint_post_process(p->linktype, p->swapped, hdr, *data); + + return (1); +} diff --git a/src/libpcap-1.10.5/sf-pcapng.h b/src/libpcap-1.10.5/sf-pcapng.h new file mode 100644 index 0000000000..835082a509 --- /dev/null +++ b/src/libpcap-1.10.5/sf-pcapng.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * sf-pcapng.h - pcapng-file-format-specific routines + * + * Used to read pcapng savefiles. + */ + +#ifndef sf_pcapng_h +#define sf_pcapng_h + +extern pcap_t *pcap_ng_check_header(const uint8_t *magic, FILE *fp, + u_int precision, char *errbuf, int *err); + +#endif diff --git a/src/libpcap-1.10.5/sockutils.c b/src/libpcap-1.10.5/sockutils.c new file mode 100644 index 0000000000..e1cc4e3066 --- /dev/null +++ b/src/libpcap-1.10.5/sockutils.c @@ -0,0 +1,2117 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +/* + * \file sockutils.c + * + * The goal of this file is to provide a common set of primitives for socket + * manipulation. + * + * Although the socket interface defined in the RFC 2553 (and its updates) + * is excellent, there are still differences between the behavior of those + * routines on UN*X and Windows, and between UN*Xes. + * + * These calls provide an interface similar to the socket interface, but + * that hides the differences between operating systems. It does not + * attempt to significantly improve on the socket interface in other + * ways. + */ + +#include "ftmacros.h" + +#include +#include /* for the errno variable */ +#include /* for the stderr file */ +#include /* for malloc() and free() */ +#include /* for INT_MAX */ + +#include "pcap-int.h" + +#include "sockutils.h" +#include "portability.h" + +#ifdef _WIN32 + /* + * Winsock initialization. + * + * Ask for Winsock 2.2. + */ + #define WINSOCK_MAJOR_VERSION 2 + #define WINSOCK_MINOR_VERSION 2 + + static int sockcount = 0; /*!< Variable that allows calling the WSAStartup() only one time */ +#endif + +/* Some minor differences between UNIX and Win32 */ +#ifdef _WIN32 + #define SHUT_WR SD_SEND /* The control code for shutdown() is different in Win32 */ +#endif + +/* Size of the buffer that has to keep error messages */ +#define SOCK_ERRBUF_SIZE 1024 + +/* Constants; used in order to keep strings here */ +#define SOCKET_NO_NAME_AVAILABLE "No name available" +#define SOCKET_NO_PORT_AVAILABLE "No port available" +#define SOCKET_NAME_NULL_DAD "Null address (possibly DAD Phase)" + +/* + * On UN*X, send() and recv() return ssize_t. + * + * On Windows, send() and recv() return an int. + * + * With MSVC, there *is* no ssize_t. + * + * With MinGW, there is an ssize_t type; it is either an int (32 bit) + * or a long long (64 bit). + * + * So, on Windows, if we don't have ssize_t defined, define it as an + * int, so we can use it, on all platforms, as the type of variables + * that hold the return values from send() and recv(). + */ +#if defined(_WIN32) && !defined(_SSIZE_T_DEFINED) +typedef int ssize_t; +#endif + +/**************************************************** + * * + * Locally defined functions * + * * + ****************************************************/ + +static int sock_ismcastaddr(const struct sockaddr *saddr); + +/**************************************************** + * * + * Function bodies * + * * + ****************************************************/ + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +const uint8_t *fuzzBuffer; +size_t fuzzSize; +size_t fuzzPos; + +void sock_initfuzz(const uint8_t *Data, size_t Size) { + fuzzPos = 0; + fuzzSize = Size; + fuzzBuffer = Data; +} + +static int fuzz_recv(char *bufp, int remaining) { + if (remaining > fuzzSize - fuzzPos) { + remaining = fuzzSize - fuzzPos; + } + if (fuzzPos < fuzzSize) { + memcpy(bufp, fuzzBuffer + fuzzPos, remaining); + } + fuzzPos += remaining; + return remaining; +} +#endif + +int sock_geterrcode(void) +{ +#ifdef _WIN32 + return GetLastError(); +#else + return errno; +#endif +} + +/* + * Format an error message given an errno value (UN*X) or a Winsock error + * (Windows). + */ +void sock_vfmterrmsg(char *errbuf, size_t errbuflen, int errcode, + const char *fmt, va_list ap) +{ + if (errbuf == NULL) + return; + +#ifdef _WIN32 + pcapint_vfmt_errmsg_for_win32_err(errbuf, errbuflen, errcode, + fmt, ap); +#else + pcapint_vfmt_errmsg_for_errno(errbuf, errbuflen, errcode, + fmt, ap); +#endif +} + +void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sock_vfmterrmsg(errbuf, errbuflen, errcode, fmt, ap); + va_end(ap); +} + +/* + * Format an error message for the last socket error. + */ +void sock_geterrmsg(char *errbuf, size_t errbuflen, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sock_vfmterrmsg(errbuf, errbuflen, sock_geterrcode(), fmt, ap); + va_end(ap); +} + +/* + * Types of error. + * + * These are sorted by how likely they are to be the "underlying" problem, + * so that lower-rated errors for a given address in a given family + * should not overwrite higher-rated errors for another address in that + * family, and higher-rated errors should overwrite lower-rated errors. + */ +typedef enum { + SOCK_CONNERR, /* connection error */ + SOCK_HOSTERR, /* host error */ + SOCK_NETERR, /* network error */ + SOCK_AFNOTSUPERR, /* address family not supported */ + SOCK_UNKNOWNERR, /* unknown error */ + SOCK_NOERR /* no error */ +} sock_errtype; + +static sock_errtype sock_geterrtype(int errcode) +{ + switch (errcode) { + +#ifdef _WIN32 + case WSAECONNRESET: + case WSAECONNABORTED: + case WSAECONNREFUSED: +#else + case ECONNRESET: + case ECONNABORTED: + case ECONNREFUSED: +#endif + /* + * Connection error; this means the problem is probably + * that there's no server set up on the remote machine, + * or that it is set up, but it's IPv4-only or IPv6-only + * and we're trying the wrong address family. + * + * These overwrite all other errors, as they indicate + * that, even if something else went wrong in another + * attempt, this probably wouldn't work even if the + * other problems were fixed. + */ + return (SOCK_CONNERR); + +#ifdef _WIN32 + case WSAENETUNREACH: + case WSAETIMEDOUT: + case WSAEHOSTDOWN: + case WSAEHOSTUNREACH: +#else + case ENETUNREACH: + case ETIMEDOUT: + case EHOSTDOWN: + case EHOSTUNREACH: +#endif + /* + * Network errors that could be IPv4-specific, IPv6- + * specific, or present with both. + * + * Don't overwrite connection errors, but overwrite + * everything else. + */ + return (SOCK_HOSTERR); + +#ifdef _WIN32 + case WSAENETDOWN: + case WSAENETRESET: +#else + case ENETDOWN: + case ENETRESET: +#endif + /* + * Network error; this means we don't know whether + * there's a server set up on the remote machine, + * and we don't have a reason to believe that IPv6 + * any worse or better than IPv4. + * + * These probably indicate a local failure, e.g. + * an interface is down. + * + * Don't overwrite connection errors or host errors, + * but overwrite everything else. + */ + return (SOCK_NETERR); + +#ifdef _WIN32 + case WSAEAFNOSUPPORT: +#else + case EAFNOSUPPORT: +#endif + /* + * "Address family not supported" probably means + * "No soup^WIPv6 for you!". + * + * Don't overwrite connection errors, host errors, or + * network errors (none of which we should get for this + * address family if it's not supported), but overwrite + * everything else. + */ + return (SOCK_AFNOTSUPERR); + + default: + /* + * Anything else. + * + * Don't overwrite any errors. + */ + return (SOCK_UNKNOWNERR); + } +} + +/* + * \brief This function initializes the socket mechanism if it hasn't + * already been initialized or reinitializes it after it has been + * cleaned up. + * + * On UN*Xes, it doesn't need to do anything; on Windows, it needs to + * initialize Winsock. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain + * the complete error message. This buffer has to be at least 'errbuflen' + * in length. It can be NULL; in this case no error message is supplied. + * + * \param errbuflen: length of the buffer that will contains the error. + * The error message cannot be larger than 'errbuflen - 1' because the + * last char is reserved for the string terminator. + * + * \return '0' if everything is fine, '-1' if some errors occurred. The + * error message is returned in the buffer pointed to by 'errbuf' variable. + */ +#ifdef _WIN32 +int sock_init(char *errbuf, int errbuflen) +{ + if (sockcount == 0) + { + WSADATA wsaData; /* helper variable needed to initialize Winsock */ + + if (WSAStartup(MAKEWORD(WINSOCK_MAJOR_VERSION, + WINSOCK_MINOR_VERSION), &wsaData) != 0) + { + if (errbuf) + snprintf(errbuf, errbuflen, "Failed to initialize Winsock\n"); + return -1; + } + } + + sockcount++; + return 0; +} +#else +int sock_init(char *errbuf _U_, int errbuflen _U_) +{ + /* + * Nothing to do on UN*Xes. + */ + return 0; +} +#endif + +/* + * \brief This function cleans up the socket mechanism if we have no + * sockets left open. + * + * On UN*Xes, it doesn't need to do anything; on Windows, it needs + * to clean up Winsock. + * + * \return No error values. + */ +void sock_cleanup(void) +{ +#ifdef _WIN32 + sockcount--; + + if (sockcount == 0) + WSACleanup(); +#endif +} + +/* + * \brief It checks if the sockaddr variable contains a multicast address. + * + * \return '0' if the address is multicast, '-1' if it is not. + */ +static int sock_ismcastaddr(const struct sockaddr *saddr) +{ + if (saddr->sa_family == PF_INET) + { + struct sockaddr_in *saddr4 = (struct sockaddr_in *) saddr; + if (IN_MULTICAST(ntohl(saddr4->sin_addr.s_addr))) return 0; + else return -1; + } + else + { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr; + if (IN6_IS_ADDR_MULTICAST(&saddr6->sin6_addr)) return 0; + else return -1; + } +} + +struct addr_status { + struct addrinfo *info; + int errcode; + sock_errtype errtype; +}; + +/* + * Sort by IPv4 address vs. IPv6 address. + */ +static int compare_addrs_to_try_by_address_family(const void *a, const void *b) +{ + const struct addr_status *addr_a = (const struct addr_status *)a; + const struct addr_status *addr_b = (const struct addr_status *)b; + + return addr_a->info->ai_family - addr_b->info->ai_family; +} + +/* + * Sort by error type and, within a given error type, by error code and, + * within a given error code, by IPv4 address vs. IPv6 address. + */ +static int compare_addrs_to_try_by_status(const void *a, const void *b) +{ + const struct addr_status *addr_a = (const struct addr_status *)a; + const struct addr_status *addr_b = (const struct addr_status *)b; + + if (addr_a->errtype == addr_b->errtype) + { + if (addr_a->errcode == addr_b->errcode) + { + return addr_a->info->ai_family - addr_b->info->ai_family; + } + return addr_a->errcode - addr_b->errcode; + } + + return addr_a->errtype - addr_b->errtype; +} + +static PCAP_SOCKET sock_create_socket(struct addrinfo *addrinfo, char *errbuf, + int errbuflen) +{ + PCAP_SOCKET sock; +#ifdef SO_NOSIGPIPE + int on = 1; +#endif + + sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (sock == INVALID_SOCKET) + { + sock_geterrmsg(errbuf, errbuflen, "socket() failed"); + return INVALID_SOCKET; + } + + /* + * Disable SIGPIPE, if we have SO_NOSIGPIPE. We don't want to + * have to deal with signals if the peer closes the connection, + * especially in client programs, which may not even be aware that + * they're sending to sockets. + */ +#ifdef SO_NOSIGPIPE + if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, + sizeof (int)) == -1) + { + sock_geterrmsg(errbuf, errbuflen, + "setsockopt(SO_NOSIGPIPE) failed"); + closesocket(sock); + return INVALID_SOCKET; + } +#endif + return sock; +} + +/* + * \brief It initializes a network connection both from the client and the server side. + * + * In case of a client socket, this function calls socket() and connect(). + * In the meanwhile, it checks for any socket error. + * If an error occurs, it writes the error message into 'errbuf'. + * + * In case of a server socket, the function calls socket(), bind() and listen(). + * + * This function is usually preceded by the sock_initaddress(). + * + * \param host: for client sockets, the host name to which we're trying + * to connect. + * + * \param addrinfo: pointer to an addrinfo variable which will be used to + * open the socket and such. This variable is the one returned by the previous call to + * sock_initaddress(). + * + * \param server: '1' if this is a server socket, '0' otherwise. + * + * \param nconn: number of the connections that are allowed to wait into the listen() call. + * This value has no meanings in case of a client socket. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return the socket that has been opened (that has to be used in the following sockets calls) + * if everything is fine, INVALID_SOCKET if some errors occurred. The error message is returned + * in the 'errbuf' variable. + */ +PCAP_SOCKET sock_open(const char *host, struct addrinfo *addrinfo, + int server, int nconn, char *errbuf, int errbuflen) +{ + PCAP_SOCKET sock; + + /* This is a server socket */ + if (server) + { + int on; + + /* + * Attempt to create the socket. + */ + sock = sock_create_socket(addrinfo, errbuf, errbuflen); + if (sock == INVALID_SOCKET) + { + return INVALID_SOCKET; + } + + /* + * Allow a new server to bind the socket after the old one + * exited, even if lingering sockets are still present. + * + * Don't treat an error as a failure. + */ + on = 1; + (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof (on)); + +#if defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) + /* + * Force the use of IPv6-only addresses. + * + * RFC 3493 indicates that you can support IPv4 on an + * IPv6 socket: + * + * https://tools.ietf.org/html/rfc3493#section-3.7 + * + * and that this is the default behavior. This means + * that if we first create an IPv6 socket bound to the + * "any" address, it is, in effect, also bound to the + * IPv4 "any" address, so when we create an IPv4 socket + * and try to bind it to the IPv4 "any" address, it gets + * EADDRINUSE. + * + * Not all network stacks support IPv4 on IPv6 sockets; + * pre-NT 6 Windows stacks don't support it, and the + * OpenBSD stack doesn't support it for security reasons + * (see the OpenBSD inet6(4) man page). Therefore, we + * don't want to rely on this behavior. + * + * So we try to disable it, using either the IPV6_V6ONLY + * option from RFC 3493: + * + * https://tools.ietf.org/html/rfc3493#section-5.3 + * + * or the IPV6_BINDV6ONLY option from older UN*Xes. + */ +#ifndef IPV6_V6ONLY + /* For older systems */ + #define IPV6_V6ONLY IPV6_BINDV6ONLY +#endif /* IPV6_V6ONLY */ + if (addrinfo->ai_family == PF_INET6) + { + on = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&on, sizeof (int)) == -1) + { + if (errbuf) + snprintf(errbuf, errbuflen, "setsockopt(IPV6_V6ONLY)"); + closesocket(sock); + return INVALID_SOCKET; + } + } +#endif /* defined(IPV6_V6ONLY) || defined(IPV6_BINDV6ONLY) */ + + /* WARNING: if the address is a mcast one, I should place the proper Win32 code here */ + if (bind(sock, addrinfo->ai_addr, (int) addrinfo->ai_addrlen) != 0) + { + sock_geterrmsg(errbuf, errbuflen, "bind() failed"); + closesocket(sock); + return INVALID_SOCKET; + } + + if (addrinfo->ai_socktype == SOCK_STREAM) + if (listen(sock, nconn) == -1) + { + sock_geterrmsg(errbuf, errbuflen, + "listen() failed"); + closesocket(sock); + return INVALID_SOCKET; + } + + /* server side ended */ + return sock; + } + else /* we're the client */ + { + struct addr_status *addrs_to_try; + struct addrinfo *tempaddrinfo; + size_t numaddrinfos; + size_t i; + int current_af = AF_UNSPEC; + + /* + * We have to loop though all the addrinfos returned. + * For instance, we can have both IPv6 and IPv4 addresses, + * but the service we're trying to connect to is unavailable + * in IPv6, so we have to try in IPv4 as well. + * + * How many addrinfos do we have? + */ + numaddrinfos = 0; + for (tempaddrinfo = addrinfo; tempaddrinfo != NULL; + tempaddrinfo = tempaddrinfo->ai_next) + { + numaddrinfos++; + } + + if (numaddrinfos == 0) + { + snprintf(errbuf, errbuflen, + "There are no addresses in the address list"); + return INVALID_SOCKET; + } + + /* + * Allocate an array of struct addr_status and fill it in. + */ + addrs_to_try = calloc(numaddrinfos, sizeof *addrs_to_try); + if (addrs_to_try == NULL) + { + snprintf(errbuf, errbuflen, + "Out of memory connecting to %s", host); + return INVALID_SOCKET; + } + + for (tempaddrinfo = addrinfo, i = 0; tempaddrinfo != NULL; + tempaddrinfo = tempaddrinfo->ai_next, i++) + { + addrs_to_try[i].info = tempaddrinfo; + addrs_to_try[i].errcode = 0; + addrs_to_try[i].errtype = SOCK_NOERR; + } + + /* + * Sort the structures to put the IPv4 addresses before the + * IPv6 addresses; we will have to create an IPv4 socket + * for the IPv4 addresses and an IPv6 socket for the IPv6 + * addresses (one of the arguments to socket() is the + * address/protocol family to use, and IPv4 and IPv6 are + * separate address/protocol families). + */ + qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, + compare_addrs_to_try_by_address_family); + + /* Start out with no socket. */ + sock = INVALID_SOCKET; + + /* + * Now try them all. + */ + for (i = 0; i < numaddrinfos; i++) + { + tempaddrinfo = addrs_to_try[i].info; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + break; +#endif + /* + * If we have a socket, but it's for a + * different address family, close it. + */ + if (sock != INVALID_SOCKET && + current_af != tempaddrinfo->ai_family) + { + closesocket(sock); + sock = INVALID_SOCKET; + } + + /* + * If we don't have a socket, open one + * for *this* address's address family. + */ + if (sock == INVALID_SOCKET) + { + sock = sock_create_socket(tempaddrinfo, + errbuf, errbuflen); + if (sock == INVALID_SOCKET) + { + free(addrs_to_try); + return INVALID_SOCKET; + } + } + if (connect(sock, tempaddrinfo->ai_addr, (int) tempaddrinfo->ai_addrlen) == -1) + { + addrs_to_try[i].errcode = sock_geterrcode(); + addrs_to_try[i].errtype = + sock_geterrtype(addrs_to_try[i].errcode); + } + else + break; + } + + /* + * Check how we exited from the previous loop. + * If tempaddrinfo is equal to NULL, it means that all + * the connect() attempts failed. Construct an + * error message. + */ + if (i == numaddrinfos) + { + int same_error_for_all; + int first_error; + + closesocket(sock); + + /* + * Sort the statuses to group together categories + * of errors, errors within categories, and + * address families within error sets. + */ + qsort(addrs_to_try, numaddrinfos, sizeof *addrs_to_try, + compare_addrs_to_try_by_status); + + /* + * Are all the errors the same? + */ + same_error_for_all = 1; + first_error = addrs_to_try[0].errcode; + for (i = 1; i < numaddrinfos; i++) + { + if (addrs_to_try[i].errcode != first_error) + { + same_error_for_all = 0; + break; + } + } + + if (same_error_for_all) { + /* + * Yes. No need to show the IP + * addresses. + */ + if (addrs_to_try[0].errtype == SOCK_CONNERR) { + /* + * Connection error; note that + * the daemon might not be set + * up correctly, or set up at all. + */ + sock_fmterrmsg(errbuf, errbuflen, + addrs_to_try[0].errcode, + "Is the server properly installed? Cannot connect to %s", + host); + } else { + sock_fmterrmsg(errbuf, errbuflen, + addrs_to_try[0].errcode, + "Cannot connect to %s", host); + } + } else { + /* + * Show all the errors and the IP addresses + * to which they apply. + */ + char *errbufptr; + size_t bufspaceleft; + size_t msglen; + + snprintf(errbuf, errbuflen, + "Connect to %s failed: ", host); + + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + for (i = 0; i < numaddrinfos && + addrs_to_try[i].errcode != SOCK_NOERR; + i++) + { + /* + * Get the string for the address + * and port that got this error. + */ + sock_getascii_addrport((struct sockaddr_storage *) addrs_to_try[i].info->ai_addr, + errbufptr, (int)bufspaceleft, + NULL, 0, NI_NUMERICHOST, NULL, 0); + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + if (i + 1 < numaddrinfos && + addrs_to_try[i + 1].errcode == addrs_to_try[i].errcode) + { + /* + * There's another error + * after this, and it has + * the same error code. + * + * Append a comma, as the + * list of addresses with + * this error has another + * entry. + */ + snprintf(errbufptr, bufspaceleft, + ", "); + } + else + { + /* + * Either there are no + * more errors after this, + * or the next error is + * different. + * + * Append a colon and + * the message for tis + * error, followed by a + * comma if there are + * more errors. + */ + sock_fmterrmsg(errbufptr, + bufspaceleft, + addrs_to_try[i].errcode, + "%s", ""); + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + + if (i + 1 < numaddrinfos && + addrs_to_try[i + 1].errcode != SOCK_NOERR) + { + /* + * More to come. + */ + snprintf(errbufptr, + bufspaceleft, + ", "); + } + } + msglen = strlen(errbuf); + errbufptr = errbuf + msglen; + bufspaceleft = errbuflen - msglen; + } + } + free(addrs_to_try); + return INVALID_SOCKET; + } + else + { + free(addrs_to_try); + return sock; + } + } +} + +/* + * \brief Closes the present (TCP and UDP) socket connection. + * + * This function sends a shutdown() on the socket in order to disable send() calls + * (while recv() ones are still allowed). Then, it closes the socket. + * + * \param sock: the socket identifier of the connection that has to be closed. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return '0' if everything is fine, '-1' if some errors occurred. The error message is returned + * in the 'errbuf' variable. + */ +int sock_close(PCAP_SOCKET sock, char *errbuf, int errbuflen) +{ + /* + * SHUT_WR: subsequent calls to the send function are disallowed. + * For TCP sockets, a FIN will be sent after all data is sent and + * acknowledged by the Server. + */ + if (shutdown(sock, SHUT_WR)) + { + sock_geterrmsg(errbuf, errbuflen, "shutdown() failed"); + /* close the socket anyway */ + closesocket(sock); + return -1; + } + + closesocket(sock); + return 0; +} + +/* + * gai_strerror() has some problems: + * + * 1) on Windows, Microsoft explicitly says it's not thread-safe; + * 2) on UN*X, the Single UNIX Specification doesn't say it *is* + * thread-safe, so an implementation might use a static buffer + * for unknown error codes; + * 3) the error message for the most likely error, EAI_NONAME, is + * truly horrible on several platforms ("nodename nor servname + * provided, or not known"? It's typically going to be "not + * known", not "oopsie, I passed null pointers for the host name + * and service name", not to mention they forgot the "neither"); + * + * so we roll our own. + */ +static void +get_gai_errstring(char *errbuf, int errbuflen, const char *prefix, int err, + const char *hostname, const char *portname) +{ + char hostport[PCAP_ERRBUF_SIZE]; + + if (hostname != NULL && portname != NULL) + snprintf(hostport, PCAP_ERRBUF_SIZE, "host and port %s:%s", + hostname, portname); + else if (hostname != NULL) + snprintf(hostport, PCAP_ERRBUF_SIZE, "host %s", + hostname); + else if (portname != NULL) + snprintf(hostport, PCAP_ERRBUF_SIZE, "port %s", + portname); + else + snprintf(hostport, PCAP_ERRBUF_SIZE, ""); + switch (err) + { +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: + snprintf(errbuf, errbuflen, + "%sAddress family for %s not supported", + prefix, hostport); + break; +#endif + + case EAI_AGAIN: + snprintf(errbuf, errbuflen, + "%s%s could not be resolved at this time", + prefix, hostport); + break; + + case EAI_BADFLAGS: + snprintf(errbuf, errbuflen, + "%sThe ai_flags parameter for looking up %s had an invalid value", + prefix, hostport); + break; + + case EAI_FAIL: + snprintf(errbuf, errbuflen, + "%sA non-recoverable error occurred when attempting to resolve %s", + prefix, hostport); + break; + + case EAI_FAMILY: + snprintf(errbuf, errbuflen, + "%sThe address family for looking up %s was not recognized", + prefix, hostport); + break; + + case EAI_MEMORY: + snprintf(errbuf, errbuflen, + "%sOut of memory trying to allocate storage when looking up %s", + prefix, hostport); + break; + + /* + * RFC 2553 had both EAI_NODATA and EAI_NONAME. + * + * RFC 3493 has only EAI_NONAME. + * + * Some implementations define EAI_NODATA and EAI_NONAME + * to the same value, others don't. If EAI_NODATA is + * defined and isn't the same as EAI_NONAME, we handle + * EAI_NODATA. + */ +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: + snprintf(errbuf, errbuflen, + "%sNo address associated with %s", + prefix, hostport); + break; +#endif + + case EAI_NONAME: + snprintf(errbuf, errbuflen, + "%sThe %s couldn't be resolved", + prefix, hostport); + break; + + case EAI_SERVICE: + snprintf(errbuf, errbuflen, + "%sThe service value specified when looking up %s as not recognized for the socket type", + prefix, hostport); + break; + + case EAI_SOCKTYPE: + snprintf(errbuf, errbuflen, + "%sThe socket type specified when looking up %s as not recognized", + prefix, hostport); + break; + +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + /* + * Assumed to be UN*X. + */ + pcapint_fmt_errmsg_for_errno(errbuf, errbuflen, errno, + "%sAn error occurred when looking up %s", + prefix, hostport); + break; +#endif + +#ifdef EAI_BADHINTS + case EAI_BADHINTS: + snprintf(errbuf, errbuflen, + "%sInvalid value for hints when looking up %s", + prefix, hostport); + break; +#endif + +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: + snprintf(errbuf, errbuflen, + "%sResolved protocol when looking up %s is unknown", + prefix, hostport); + break; +#endif + +#ifdef EAI_OVERFLOW + case EAI_OVERFLOW: + snprintf(errbuf, errbuflen, + "%sArgument buffer overflow when looking up %s", + prefix, hostport); + break; +#endif + + default: + snprintf(errbuf, errbuflen, + "%sgetaddrinfo() error %d when looking up %s", + prefix, err, hostport); + break; + } +} + +/* + * \brief Checks that the address, port and flags given are valid and it returns an 'addrinfo' structure. + * + * This function basically calls the getaddrinfo() calls, and it performs a set of sanity checks + * to control that everything is fine (e.g. a TCP socket cannot have a mcast address, and such). + * If an error occurs, it writes the error message into 'errbuf'. + * + * \param host: a pointer to a string identifying the host. It can be + * a host name, a numeric literal address, or NULL or "" (useful + * in case of a server socket which has to bind to all addresses). + * + * \param port: a pointer to a user-allocated buffer containing the network port to use. + * + * \param hints: an addrinfo variable (passed by reference) containing the flags needed to create the + * addrinfo structure appropriately. + * + * \param addrinfo: it represents the true returning value. This is a pointer to an addrinfo variable + * (passed by reference), which will be allocated by this function and returned back to the caller. + * This variable will be used in the next sockets calls. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return a pointer to the first element in a list of addrinfo structures + * if everything is fine, NULL if some errors occurred. The error message + * is returned in the 'errbuf' variable. + * + * \warning The list of addrinfo structures returned has to be deleted by + * the programmer by calling freeaddrinfo() when it is no longer needed. + * + * \warning This function requires the 'hints' variable as parameter. The semantic of this variable is the same + * of the one of the corresponding variable used into the standard getaddrinfo() socket function. We suggest + * the programmer to look at that function in order to set the 'hints' variable appropriately. + */ +struct addrinfo *sock_initaddress(const char *host, const char *port, + struct addrinfo *hints, char *errbuf, int errbuflen) +{ + struct addrinfo *addrinfo; + int retval; + + /* + * We allow both the host and port to be null, but getaddrinfo() + * is not guaranteed to do so; to handle that, if port is null, + * we provide "0" as the port number. + * + * This results in better error messages from get_gai_errstring(), + * as those messages won't talk about a problem with the port if + * no port was specified. + */ + retval = getaddrinfo(host, port == NULL ? "0" : port, hints, &addrinfo); + if (retval != 0) + { + /* + * That call failed. + * Determine whether the problem is that the host is bad. + */ + if (errbuf) + { + if (host != NULL && port != NULL) { + /* + * Try with just a host, to distinguish + * between "host is bad" and "port is + * bad". + */ + int try_retval; + + try_retval = getaddrinfo(host, NULL, hints, + &addrinfo); + if (try_retval == 0) { + /* + * Worked with just the host, + * so assume the problem is + * with the port. + * + * Free up the address info first. + */ + freeaddrinfo(addrinfo); + get_gai_errstring(errbuf, errbuflen, + "", retval, NULL, port); + } else { + /* + * Didn't work with just the host, + * so assume the problem is + * with the host; we assume + * the original error indicates + * the underlying problem. + */ + get_gai_errstring(errbuf, errbuflen, + "", retval, host, NULL); + } + } else { + /* + * Either the host or port was null, so + * there's nothing to determine; report + * the error from the original call. + */ + get_gai_errstring(errbuf, errbuflen, "", + retval, host, port); + } + } + return NULL; + } + /* + * \warning SOCKET: I should check all the accept() in order to bind to all addresses in case + * addrinfo has more han one pointers + */ + + /* + * This software only supports PF_INET and PF_INET6. + * + * XXX - should we just check that at least *one* address is + * either PF_INET or PF_INET6, and, when using the list, + * ignore all addresses that are neither? (What, no IPX + * support? :-)) + */ + if ((addrinfo->ai_family != PF_INET) && + (addrinfo->ai_family != PF_INET6)) + { + if (errbuf) + snprintf(errbuf, errbuflen, "getaddrinfo(): socket type not supported"); + freeaddrinfo(addrinfo); + return NULL; + } + + /* + * You can't do multicast (or broadcast) TCP. + */ + if ((addrinfo->ai_socktype == SOCK_STREAM) && + (sock_ismcastaddr(addrinfo->ai_addr) == 0)) + { + if (errbuf) + snprintf(errbuf, errbuflen, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); + freeaddrinfo(addrinfo); + return NULL; + } + + return addrinfo; +} + +/* + * \brief It sends the amount of data contained into 'buffer' on the given socket. + * + * This function basically calls the send() socket function and it checks that all + * the data specified in 'buffer' (of size 'size') will be sent. If an error occurs, + * it writes the error message into 'errbuf'. + * In case the socket buffer does not have enough space, it loops until all data + * has been sent. + * + * \param socket: the connected socket currently opened. + * + * \param buffer: a char pointer to a user-allocated buffer in which data is contained. + * + * \param size: number of bytes that have to be sent. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return '0' if everything is fine, '-1' if an error other than + * "connection reset" or "peer has closed the receive side" occurred, + * '-2' if we got one of those errors. + * For errors, an error message is returned in the 'errbuf' variable. + */ +int sock_send(PCAP_SOCKET sock, SSL *ssl _U_NOSSL_, const char *buffer, + size_t size, char *errbuf, int errbuflen) +{ + int remaining; + ssize_t nsent; + + if (size > INT_MAX) + { + if (errbuf) + { + snprintf(errbuf, errbuflen, + "Can't send more than %u bytes with sock_send", + INT_MAX); + } + return -1; + } + remaining = (int)size; + + do { +#ifdef HAVE_OPENSSL + if (ssl) return ssl_send(ssl, buffer, remaining, errbuf, errbuflen); +#endif + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + nsent = remaining; +#else +#ifdef MSG_NOSIGNAL + /* + * Send with MSG_NOSIGNAL, so that we don't get SIGPIPE + * on errors on stream-oriented sockets when the other + * end breaks the connection. + * The EPIPE error is still returned. + */ + nsent = send(sock, buffer, remaining, MSG_NOSIGNAL); +#else + nsent = send(sock, buffer, remaining, 0); +#endif +#endif //FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + + if (nsent == -1) + { + /* + * If the client closed the connection out from + * under us, there's no need to log that as an + * error. + */ + int errcode; + +#ifdef _WIN32 + errcode = GetLastError(); + if (errcode == WSAECONNRESET || + errcode == WSAECONNABORTED) + { + /* + * WSAECONNABORTED appears to be the error + * returned in Winsock when you try to send + * on a connection where the peer has closed + * the receive side. + */ + return -2; + } + sock_fmterrmsg(errbuf, errbuflen, errcode, + "send() failed"); +#else + errcode = errno; + if (errcode == ECONNRESET || errcode == EPIPE) + { + /* + * EPIPE is what's returned on UN*X when + * you try to send on a connection when + * the peer has closed the receive side. + */ + return -2; + } + sock_fmterrmsg(errbuf, errbuflen, errcode, + "send() failed"); +#endif + return -1; + } + + remaining -= nsent; + buffer += nsent; + } while (remaining != 0); + + return 0; +} + +/* + * \brief It copies the amount of data contained in 'data' into 'outbuf'. + * and it checks for buffer overflows. + * + * This function basically copies 'size' bytes of data contained in 'data' + * into 'outbuf', starting at offset 'offset'. Before that, it checks that the + * resulting buffer will not be larger than 'totsize'. Finally, it updates + * the 'offset' variable in order to point to the first empty location of the buffer. + * + * In case the function is called with 'checkonly' equal to 1, it does not copy + * the data into the buffer. It only checks for buffer overflows and it updates the + * 'offset' variable. This mode can be useful when the buffer already contains the + * data (maybe because the producer writes directly into the target buffer), so + * only the buffer overflow check has to be made. + * In this case, both 'data' and 'outbuf' can be NULL values. + * + * This function is useful in case the userland application does not know immediately + * all the data it has to write into the socket. This function provides a way to create + * the "stream" step by step, appending the new data to the old one. Then, when all the + * data has been bufferized, the application can call the sock_send() function. + * + * \param data: a void pointer to the data that has to be copied. + * + * \param size: number of bytes that have to be copied. + * + * \param outbuf: user-allocated buffer (of size 'totsize') into which data + * has to be copied. + * + * \param offset: an index into 'outbuf' which keeps the location of its first + * empty location. + * + * \param totsize: total size of the buffer into which data is being copied. + * + * \param checkonly: '1' if we do not want to copy data into the buffer and we + * want just do a buffer overflow control, '0' if data has to be copied as well. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return '0' if everything is fine, '-1' if some errors occurred. The error message + * is returned in the 'errbuf' variable. When the function returns, 'outbuf' will + * have the new string appended, and 'offset' will keep the length of that buffer. + * In case of 'checkonly == 1', data is not copied, but 'offset' is updated in any case. + * + * \warning This function assumes that the buffer in which data has to be stored is + * large 'totbuf' bytes. + * + * \warning In case of 'checkonly', be carefully to call this function *before* copying + * the data into the buffer. Otherwise, the control about the buffer overflow is useless. + */ +int sock_bufferize(const void *data, int size, char *outbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen) +{ + if ((*offset + size) > totsize) + { + if (errbuf) + snprintf(errbuf, errbuflen, "Not enough space in the temporary send buffer."); + return -1; + } + + if (!checkonly) + memcpy(outbuf + (*offset), data, size); + + (*offset) += size; + + return 0; +} + +/* + * \brief It waits on a connected socket and it manages to receive data. + * + * This function basically calls the recv() socket function and it checks that no + * error occurred. If that happens, it writes the error message into 'errbuf'. + * + * This function changes its behavior according to the 'receiveall' flag: if we + * want to receive exactly 'size' byte, it loops on the recv() until all the requested + * data is arrived. Otherwise, it returns the data currently available. + * + * In case the socket does not have enough data available, it cycles on the recv() + * until the requested data (of size 'size') is arrived. + * In this case, it blocks until the number of bytes read is equal to 'size'. + * + * \param sock: the connected socket currently opened. + * + * \param buffer: a char pointer to a user-allocated buffer in which data has to be stored + * + * \param size: size of the allocated buffer. WARNING: this indicates the number of bytes + * that we are expecting to be read. + * + * \param flags: + * + * SOCK_RECEIVALL_XXX: + * + * if SOCK_RECEIVEALL_NO, return as soon as some data is ready + * if SOCK_RECEIVALL_YES, wait until 'size' data has been + * received (in case the socket does not have enough data available). + * + * SOCK_EOF_XXX: + * + * if SOCK_EOF_ISNT_ERROR, if the first read returns 0, just return 0, + * and return an error on any subsequent read that returns 0; + * if SOCK_EOF_IS_ERROR, if any read returns 0, return an error. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return the number of bytes read if everything is fine, '-1' if some errors occurred. + * The error message is returned in the 'errbuf' variable. + */ + +int sock_recv(PCAP_SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, size_t size, + int flags, char *errbuf, int errbuflen) +{ + int recv_flags = 0; + char *bufp = buffer; + int remaining; + ssize_t nread; + + if (size == 0) + { + return 0; + } + if (size > INT_MAX) + { + if (errbuf) + { + snprintf(errbuf, errbuflen, + "Can't read more than %u bytes with sock_recv", + INT_MAX); + } + return -1; + } + + if (flags & SOCK_MSG_PEEK) + recv_flags |= MSG_PEEK; + + bufp = (char *) buffer; + remaining = (int) size; + + /* + * We don't use MSG_WAITALL because it's not supported in + * Win32. + */ + for (;;) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + nread = fuzz_recv(bufp, remaining); +#elif defined(HAVE_OPENSSL) + if (ssl) + { + /* + * XXX - what about MSG_PEEK? + */ + nread = ssl_recv(ssl, bufp, remaining, errbuf, errbuflen); + if (nread == -2) return -1; + } + else + nread = recv(sock, bufp, remaining, recv_flags); +#else + nread = recv(sock, bufp, remaining, recv_flags); +#endif + + if (nread == -1) + { +#ifndef _WIN32 + if (errno == EINTR) + return -3; +#endif + sock_geterrmsg(errbuf, errbuflen, "recv() failed"); + return -1; + } + + if (nread == 0) + { + if ((flags & SOCK_EOF_IS_ERROR) || + (remaining != (int) size)) + { + /* + * Either we've already read some data, + * or we're always supposed to return + * an error on EOF. + */ + if (errbuf) + { + snprintf(errbuf, errbuflen, + "The other host terminated the connection."); + } + return -1; + } + else + return 0; + } + + /* + * Do we want to read the amount requested, or just return + * what we got? + */ + if (!(flags & SOCK_RECEIVEALL_YES)) + { + /* + * Just return what we got. + */ + return (int) nread; + } + + bufp += nread; + remaining -= nread; + + if (remaining == 0) + return (int) size; + } +} + +/* + * Receives a datagram from a socket. + * + * Returns the size of the datagram on success or -1 on error. + */ +int sock_recv_dgram(PCAP_SOCKET sock, SSL *ssl _U_NOSSL_, void *buffer, + size_t size, char *errbuf, int errbuflen) +{ + ssize_t nread; +#ifndef _WIN32 + struct msghdr message; + struct iovec iov; +#endif + + if (size == 0) + { + return 0; + } + if (size > INT_MAX) + { + if (errbuf) + { + snprintf(errbuf, errbuflen, + "Can't read more than %u bytes with sock_recv_dgram", + INT_MAX); + } + return -1; + } + +#ifdef HAVE_OPENSSL + // TODO: DTLS + if (ssl) + { + snprintf(errbuf, errbuflen, "DTLS not implemented yet"); + return -1; + } +#endif + + /* + * This should be a datagram socket, so we should get the + * entire datagram in one recv() or recvmsg() call, and + * don't need to loop. + */ +#ifdef _WIN32 + nread = recv(sock, buffer, (int)size, 0); + if (nread == SOCKET_ERROR) + { + /* + * To quote the MSDN documentation for recv(), + * "If the datagram or message is larger than + * the buffer specified, the buffer is filled + * with the first part of the datagram, and recv + * generates the error WSAEMSGSIZE. For unreliable + * protocols (for example, UDP) the excess data is + * lost..." + * + * So if the message is bigger than the buffer + * supplied to us, the excess data is discarded, + * and we'll report an error. + */ + sock_fmterrmsg(errbuf, errbuflen, sock_geterrcode(), + "recv() failed"); + return -1; + } +#else /* _WIN32 */ + /* + * The Single UNIX Specification says that a recv() on + * a socket for a message-oriented protocol will discard + * the excess data. It does *not* indicate that the + * receive will fail with, for example, EMSGSIZE. + * + * Therefore, we use recvmsg(), which appears to be + * the only way to get a "message truncated" indication + * when receiving a message for a message-oriented + * protocol. + */ + message.msg_name = NULL; /* we don't care who it's from */ + message.msg_namelen = 0; + iov.iov_base = buffer; + iov.iov_len = size; + message.msg_iov = &iov; + message.msg_iovlen = 1; +#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL + message.msg_control = NULL; /* we don't care about control information */ + message.msg_controllen = 0; +#endif +#ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS + message.msg_flags = 0; +#endif +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + nread = fuzz_recv(buffer, size); +#else + nread = recvmsg(sock, &message, 0); +#endif + if (nread == -1) + { + if (errno == EINTR) + return -3; + sock_geterrmsg(errbuf, errbuflen, "recv() failed"); + return -1; + } +#ifdef HAVE_STRUCT_MSGHDR_MSG_FLAGS + /* + * XXX - Solaris supports this, but only if you ask for the + * X/Open version of recvmsg(); should we use that, or will + * that cause other problems? + */ + if (message.msg_flags & MSG_TRUNC) + { + /* + * Message was bigger than the specified buffer size. + * + * Report this as an error, as the Microsoft documentation + * implies we'd do in a similar case on Windows. + */ + snprintf(errbuf, errbuflen, "recv(): Message too long"); + return -1; + } +#endif /* HAVE_STRUCT_MSGHDR_MSG_FLAGS */ +#endif /* _WIN32 */ + + /* + * The size we're reading fits in an int, so the return value + * will fit in an int. + */ + return (int)nread; +} + +/* + * \brief It discards N bytes that are currently waiting to be read on the current socket. + * + * This function is useful in case we receive a message we cannot understand (e.g. + * wrong version number when receiving a network packet), so that we have to discard all + * data before reading a new message. + * + * This function will read 'size' bytes from the socket and discard them. + * It defines an internal buffer in which data will be copied; however, in case + * this buffer is not large enough, it will cycle in order to read everything as well. + * + * \param sock: the connected socket currently opened. + * + * \param size: number of bytes that have to be discarded. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return '0' if everything is fine, '-1' if some errors occurred. + * The error message is returned in the 'errbuf' variable. + */ +int sock_discard(PCAP_SOCKET sock, SSL *ssl, int size, char *errbuf, + int errbuflen) +{ +#define TEMP_BUF_SIZE 32768 + + char buffer[TEMP_BUF_SIZE]; /* network buffer, to be used when the message is discarded */ + + /* + * A static allocation avoids the need of a 'malloc()' each time we want to discard a message + * Our feeling is that a buffer if 32KB is enough for most of the application; + * in case this is not enough, the "while" loop discards the message by calling the + * sockrecv() several times. + * We do not want to create a bigger variable because this causes the program to exit on + * some platforms (e.g. BSD) + */ + while (size > TEMP_BUF_SIZE) + { + if (sock_recv(sock, ssl, buffer, TEMP_BUF_SIZE, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1) + return -1; + + size -= TEMP_BUF_SIZE; + } + + /* + * If there is still data to be discarded + * In this case, the data can fit into the temporary buffer + */ + if (size) + { + if (sock_recv(sock, ssl, buffer, size, SOCK_RECEIVEALL_YES, errbuf, errbuflen) == -1) + return -1; + } + + return 0; +} + +/* + * \brief Checks that one host (identified by the sockaddr_storage structure) belongs to an 'allowed list'. + * + * This function is useful after an accept() call in order to check if the connecting + * host is allowed to connect to me. To do that, we have a buffer that keeps the list of the + * allowed host; this function checks the sockaddr_storage structure of the connecting host + * against this host list, and it returns '0' is the host is included in this list. + * + * \param hostlist: pointer to a string that contains the list of the allowed host. + * + * \param sep: a string that keeps the separators used between the hosts (for example the + * space character) in the host list. + * + * \param from: a sockaddr_storage structure, as it is returned by the accept() call. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return It returns: + * - '1' if the host list is empty + * - '0' if the host belongs to the host list (and therefore it is allowed to connect) + * - '-1' in case the host does not belong to the host list (and therefore it is not allowed to connect + * - '-2' in case or error. The error message is returned in the 'errbuf' variable. + */ +int sock_check_hostlist(const char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen) +{ + /* checks if the connecting host is among the ones allowed */ + if ((hostlist) && (hostlist[0])) + { + char *token; /* temp, needed to separate items into the hostlist */ + struct addrinfo *addrinfo, *ai_next; + char *temphostlist; + char *lasts; + int getaddrinfo_failed = 0; + + /* + * The problem is that strtok modifies the original variable by putting '0' at the end of each token + * So, we have to create a new temporary string in which the original content is kept + */ + temphostlist = strdup(hostlist); + if (temphostlist == NULL) + { + sock_geterrmsg(errbuf, errbuflen, + "sock_check_hostlist(), malloc() failed"); + return -2; + } + + token = pcapint_strtok_r(temphostlist, sep, &lasts); + + /* it avoids a warning in the compilation ('addrinfo used but not initialized') */ + addrinfo = NULL; + + while (token != NULL) + { + struct addrinfo hints; + int retval; + + addrinfo = NULL; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + retval = getaddrinfo(token, NULL, &hints, &addrinfo); + if (retval != 0) + { + if (errbuf) + get_gai_errstring(errbuf, errbuflen, + "Allowed host list error: ", + retval, token, NULL); + + /* + * Note that at least one call to getaddrinfo() + * failed. + */ + getaddrinfo_failed = 1; + + /* Get next token */ + token = pcapint_strtok_r(NULL, sep, &lasts); + continue; + } + + /* ai_next is required to preserve the content of addrinfo, in order to deallocate it properly */ + ai_next = addrinfo; + while (ai_next) + { + if (sock_cmpaddr(from, (struct sockaddr_storage *) ai_next->ai_addr) == 0) + { + free(temphostlist); + freeaddrinfo(addrinfo); + return 0; + } + + /* + * If we are here, it means that the current address does not matches + * Let's try with the next one in the header chain + */ + ai_next = ai_next->ai_next; + } + + freeaddrinfo(addrinfo); + addrinfo = NULL; + + /* Get next token */ + token = pcapint_strtok_r(NULL, sep, &lasts); + } + + if (addrinfo) + { + freeaddrinfo(addrinfo); + addrinfo = NULL; + } + + free(temphostlist); + + if (getaddrinfo_failed) { + /* + * At least one getaddrinfo() call failed; + * treat that as an error, so rpcapd knows + * that it should log it locally as well + * as telling the client about it. + */ + return -2; + } else { + /* + * All getaddrinfo() calls succeeded, but + * the host wasn't in the list. + */ + if (errbuf) + snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused."); + return -1; + } + } + + /* No hostlist, so we have to return 'empty list' */ + return 1; +} + +/* + * \brief Compares two addresses contained into two sockaddr_storage structures. + * + * This function is useful to compare two addresses, given their internal representation, + * i.e. an sockaddr_storage structure. + * + * The two structures do not need to be sockaddr_storage; you can have both 'sockaddr_in' and + * sockaddr_in6, properly casted in order to be compliant to the function interface. + * + * This function will return '0' if the two addresses matches, '-1' if not. + * + * \param first: a sockaddr_storage structure, (for example the one that is returned by an + * accept() call), containing the first address to compare. + * + * \param second: a sockaddr_storage structure containing the second address to compare. + * + * \return '0' if the addresses are equal, '-1' if they are different. + */ +int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second) +{ + if (first->ss_family == second->ss_family) + { + if (first->ss_family == AF_INET) + { + if (memcmp(&(((struct sockaddr_in *) first)->sin_addr), + &(((struct sockaddr_in *) second)->sin_addr), + sizeof(struct in_addr)) == 0) + return 0; + } + else /* address family is AF_INET6 */ + { + if (memcmp(&(((struct sockaddr_in6 *) first)->sin6_addr), + &(((struct sockaddr_in6 *) second)->sin6_addr), + sizeof(struct in6_addr)) == 0) + return 0; + } + } + + return -1; +} + +/* + * \brief It gets the address/port the system picked for this socket (on connected sockets). + * + * It is used to return the address and port the server picked for our socket on the local machine. + * It works only on: + * - connected sockets + * - server sockets + * + * On unconnected client sockets it does not work because the system dynamically chooses a port + * only when the socket calls a send() call. + * + * \param sock: the connected socket currently opened. + * + * \param address: it contains the address that will be returned by the function. This buffer + * must be properly allocated by the user. The address can be either literal or numeric depending + * on the value of 'Flags'. + * + * \param addrlen: the length of the 'address' buffer. + * + * \param port: it contains the port that will be returned by the function. This buffer + * must be properly allocated by the user. + * + * \param portlen: the length of the 'port' buffer. + * + * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function) + * that determine if the resulting address must be in numeric / literal form, and so on. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return It returns '-1' if this function succeeds, '0' otherwise. + * The address and port corresponding are returned back in the buffers 'address' and 'port'. + * In any case, the returned strings are '0' terminated. + * + * \warning If the socket is using a connectionless protocol, the address may not be available + * until I/O occurs on the socket. + */ +int sock_getmyinfo(PCAP_SOCKET sock, char *address, int addrlen, char *port, + int portlen, int flags, char *errbuf, int errbuflen) +{ + struct sockaddr_storage mysockaddr; + socklen_t sockaddrlen; + + + sockaddrlen = sizeof(struct sockaddr_storage); + + if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1) + { + sock_geterrmsg(errbuf, errbuflen, "getsockname() failed"); + return 0; + } + + /* Returns the numeric address of the host that triggered the error */ + return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen); +} + +/* + * \brief It retrieves two strings containing the address and the port of a given 'sockaddr' variable. + * + * This function is basically an extended version of the inet_ntop(), which does not exist in + * Winsock because the same result can be obtained by using the getnameinfo(). + * However, differently from inet_ntop(), this function is able to return also literal names + * (e.g. 'localhost') dependently from the 'Flags' parameter. + * + * The function accepts a sockaddr_storage variable (which can be returned by several functions + * like bind(), connect(), accept(), and more) and it transforms its content into a 'human' + * form. So, for instance, it is able to translate an hex address (stored in binary form) into + * a standard IPv6 address like "::1". + * + * The behavior of this function depends on the parameters we have in the 'Flags' variable, which + * are the ones allowed in the standard getnameinfo() socket function. + * + * \param sockaddr: a 'sockaddr_in' or 'sockaddr_in6' structure containing the address that + * need to be translated from network form into the presentation form. This structure must be + * zero-ed prior using it, and the address family field must be filled with the proper value. + * The user must cast any 'sockaddr_in' or 'sockaddr_in6' structures to 'sockaddr_storage' before + * calling this function. + * + * \param address: it contains the address that will be returned by the function. This buffer + * must be properly allocated by the user. The address can be either literal or numeric depending + * on the value of 'Flags'. + * + * \param addrlen: the length of the 'address' buffer. + * + * \param port: it contains the port that will be returned by the function. This buffer + * must be properly allocated by the user. + * + * \param portlen: the length of the 'port' buffer. + * + * \param flags: a set of flags (the ones defined into the getnameinfo() standard socket function) + * that determine if the resulting address must be in numeric / literal form, and so on. + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return It returns '-1' if this function succeeds, '0' otherwise. + * The address and port corresponding to the given SockAddr are returned back in the buffers 'address' + * and 'port'. + * In any case, the returned strings are '0' terminated. + */ +int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, size_t errbuflen) +{ + socklen_t sockaddrlen; + int retval; /* Variable that keeps the return value; */ + + retval = -1; + +#ifdef _WIN32 + if (sockaddr->ss_family == AF_INET) + sockaddrlen = sizeof(struct sockaddr_in); + else + sockaddrlen = sizeof(struct sockaddr_in6); +#else + sockaddrlen = sizeof(struct sockaddr_storage); +#endif + + if ((flags & NI_NUMERICHOST) == 0) /* Check that we want literal names */ + { + if ((sockaddr->ss_family == AF_INET6) && + (memcmp(&((struct sockaddr_in6 *) sockaddr)->sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(struct in6_addr)) == 0)) + { + if (address) + pcapint_strlcpy(address, SOCKET_NAME_NULL_DAD, addrlen); + return retval; + } + } + + if (getnameinfo((struct sockaddr *) sockaddr, sockaddrlen, address, addrlen, port, portlen, flags) != 0) + { + /* If the user wants to receive an error message */ + if (errbuf) + { + sock_geterrmsg(errbuf, errbuflen, + "getnameinfo() failed"); + errbuf[errbuflen - 1] = 0; + } + + if (address) + { + pcapint_strlcpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen); + address[addrlen - 1] = 0; + } + + if (port) + { + pcapint_strlcpy(port, SOCKET_NO_PORT_AVAILABLE, portlen); + port[portlen - 1] = 0; + } + + retval = 0; + } + + return retval; +} + +/* + * \brief It translates an address from the 'presentation' form into the 'network' form. + * + * This function basically replaces inet_pton(), which does not exist in Winsock because + * the same result can be obtained by using the getaddrinfo(). + * An additional advantage is that 'Address' can be both a numeric address (e.g. '127.0.0.1', + * like in inet_pton() ) and a literal name (e.g. 'localhost'). + * + * This function does the reverse job of sock_getascii_addrport(). + * + * \param address: a zero-terminated string which contains the name you have to + * translate. The name can be either literal (e.g. 'localhost') or numeric (e.g. '::1'). + * + * \param sockaddr: a user-allocated sockaddr_storage structure which will contains the + * 'network' form of the requested address. + * + * \param addr_family: a constant which can assume the following values: + * - 'AF_INET' if we want to ping an IPv4 host + * - 'AF_INET6' if we want to ping an IPv6 host + * - 'AF_UNSPEC' if we do not have preferences about the protocol used to ping the host + * + * \param errbuf: a pointer to an user-allocated buffer that will contain the complete + * error message. This buffer has to be at least 'errbuflen' in length. + * It can be NULL; in this case the error cannot be printed. + * + * \param errbuflen: length of the buffer that will contains the error. The error message cannot be + * larger than 'errbuflen - 1' because the last char is reserved for the string terminator. + * + * \return '-1' if the translation succeeded, '-2' if there was some non critical error, '0' + * otherwise. In case it fails, the content of the SockAddr variable remains unchanged. + * A 'non critical error' can occur in case the 'Address' is a literal name, which can be mapped + * to several network addresses (e.g. 'foo.bar.com' => '10.2.2.2' and '10.2.2.3'). In this case + * the content of the SockAddr parameter will be the address corresponding to the first mapping. + * + * \warning The sockaddr_storage structure MUST be allocated by the user. + */ +int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen) +{ + struct addrinfo *addrinfo; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = addr_family; + + addrinfo = sock_initaddress(address, "22222" /* fake port */, &hints, + errbuf, errbuflen); + if (addrinfo == NULL) + return 0; + + if (addrinfo->ai_family == PF_INET) + memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in)); + else + memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in6)); + + if (addrinfo->ai_next != NULL) + { + freeaddrinfo(addrinfo); + + if (errbuf) + snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned"); + return -2; + } + + freeaddrinfo(addrinfo); + return -1; +} diff --git a/src/libpcap-1.10.5/sockutils.h b/src/libpcap-1.10.5/sockutils.h new file mode 100644 index 0000000000..34d4e95d76 --- /dev/null +++ b/src/libpcap-1.10.5/sockutils.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __SOCKUTILS_H__ +#define __SOCKUTILS_H__ + +#ifdef _MSC_VER +#pragma once +#endif + +#include /* we declare varargs functions */ + +#include "pcap/funcattrs.h" + +#include "pcap/socket.h" + +#ifndef _WIN32 + /* UN*X */ + #include /* close() */ + + /*! + * \brief In Winsock, the close() call cannot be used on a socket; + * closesocket() must be used. + * We define closesocket() to be a wrapper around close() on UN*X, + * so that it can be used on both platforms. + */ + #define closesocket(a) close(a) +#endif + +#include "sslutils.h" // for SSL type, whatever that turns out to be + +/* + * MingW headers include this definition, but only for Windows XP and above. + * MSDN states that this function is available for most versions on Windows. + */ +#if ((defined(__MINGW32__)) && (_WIN32_WINNT < 0x0501)) +int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, + char*,DWORD,int); +#endif + +/* + * \defgroup SockUtils Cross-platform socket utilities (IPv4-IPv6) + */ + +/* + * \addtogroup SockUtils + * \{ + */ + +/* + * \defgroup ExportedStruct Exported Structures and Definitions + */ + +/* + * \addtogroup ExportedStruct + * \{ + */ + +/**************************************************** + * * + * Exported functions / definitions * + * * + ****************************************************/ + +/* 'checkonly' flag, into the rpsock_bufferize() */ +#define SOCKBUF_CHECKONLY 1 +/* no 'checkonly' flag, into the rpsock_bufferize() */ +#define SOCKBUF_BUFFERIZE 0 + +/* no 'server' flag; it opens a client socket */ +#define SOCKOPEN_CLIENT 0 +/* 'server' flag; it opens a server socket */ +#define SOCKOPEN_SERVER 1 + +/* + * Flags for sock_recv(). + */ +#define SOCK_RECEIVEALL_NO 0x00000000 /* Don't wait to receive all data */ +#define SOCK_RECEIVEALL_YES 0x00000001 /* Wait to receive all data */ + +#define SOCK_EOF_ISNT_ERROR 0x00000000 /* Return 0 on EOF */ +#define SOCK_EOF_IS_ERROR 0x00000002 /* Return an error on EOF */ + +#define SOCK_MSG_PEEK 0x00000004 /* Return data but leave it in the socket queue */ + +/* + * \} + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * \defgroup ExportedFunc Exported Functions + */ + +/* + * \addtogroup ExportedFunc + * \{ + */ + +int sock_init(char *errbuf, int errbuflen); +void sock_cleanup(void); +int sock_geterrcode(void); +void sock_vfmterrmsg(char *errbuf, size_t errbuflen, int errcode, + PCAP_FORMAT_STRING(const char *fmt), va_list ap) PCAP_PRINTFLIKE(4, 0); +void sock_fmterrmsg(char *errbuf, size_t errbuflen, int errcode, + PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(4, 5); +void sock_geterrmsg(char *errbuf, size_t errbuflen, + PCAP_FORMAT_STRING(const char *fmt), ...) PCAP_PRINTFLIKE(3, 4); +struct addrinfo *sock_initaddress(const char *address, const char *port, + struct addrinfo *hints, char *errbuf, int errbuflen); +int sock_recv(PCAP_SOCKET sock, SSL *, void *buffer, size_t size, + int receiveall, char *errbuf, int errbuflen); +int sock_recv_dgram(PCAP_SOCKET sock, SSL *, void *buffer, size_t size, + char *errbuf, int errbuflen); +PCAP_SOCKET sock_open(const char *host, struct addrinfo *addrinfo, int server, + int nconn, char *errbuf, int errbuflen); +int sock_close(PCAP_SOCKET sock, char *errbuf, int errbuflen); + +int sock_send(PCAP_SOCKET sock, SSL *, const char *buffer, size_t size, + char *errbuf, int errbuflen); +int sock_bufferize(const void *data, int size, char *outbuf, int *offset, int totsize, int checkonly, char *errbuf, int errbuflen); +int sock_discard(PCAP_SOCKET sock, SSL *, int size, char *errbuf, + int errbuflen); +int sock_check_hostlist(const char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen); +int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second); + +int sock_getmyinfo(PCAP_SOCKET sock, char *address, int addrlen, char *port, + int portlen, int flags, char *errbuf, int errbuflen); + +int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, size_t errbuflen); +int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen); + +#ifdef __cplusplus +} +#endif + +/* + * \} + */ + +/* + * \} + */ + +#endif diff --git a/src/libpcap-1.10.5/sslutils.c b/src/libpcap-1.10.5/sslutils.c new file mode 100644 index 0000000000..c75b53784b --- /dev/null +++ b/src/libpcap-1.10.5/sslutils.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#ifdef HAVE_OPENSSL +#include + +#include "portability.h" + +#include "sslutils.h" + +static const char *ssl_keyfile = ""; //!< file containing the private key in PEM format +static const char *ssl_certfile = ""; //!< file containing the server's certificate in PEM format +static const char *ssl_rootfile = ""; //!< file containing the list of CAs trusted by the client +// TODO: a way to set ssl_rootfile from the command line, or an envvar? + +// TODO: lock? +static SSL_CTX *ctx; + +void ssl_set_certfile(const char *certfile) +{ + ssl_certfile = certfile; +} + +void ssl_set_keyfile(const char *keyfile) +{ + ssl_keyfile = keyfile; +} + +int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen) +{ + static int inited = 0; + if (inited) return 0; + + SSL_library_init(); + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + if (enable_compression) + SSL_COMP_get_compression_methods(); + + SSL_METHOD const *meth = + is_server ? SSLv23_server_method() : SSLv23_client_method(); + ctx = SSL_CTX_new(meth); + if (! ctx) + { + snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); + goto die; + } + + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + + if (is_server) + { + char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem"; + if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) + { + snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL)); + goto die; + } + + char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem"; + if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)) + { + snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL)); + goto die; + } + } + else + { + if (ssl_rootfile[0]) + { + if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0)) + { + snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile); + goto die; + } + } + else + { + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } + } + +#if 0 + if (! RAND_load_file(RANDOM, 1024*1024)) + { + snprintf(errbuf, errbuflen, "Cannot init random"); + goto die; + } + + if (is_server) + { + SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context)); + } +#endif + + inited = 1; + return 0; + +die: + return -1; +} + +SSL *ssl_promotion(int is_server, PCAP_SOCKET s, char *errbuf, size_t errbuflen) +{ + if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) { + return NULL; + } + + SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context + SSL_set_fd(ssl, (int)s); + + if (is_server) { + if (SSL_accept(ssl) <= 0) { + snprintf(errbuf, errbuflen, "SSL_accept(): %s", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + } else { + if (SSL_connect(ssl) <= 0) { + snprintf(errbuf, errbuflen, "SSL_connect(): %s", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + } + + return ssl; +} + +// Finish using an SSL handle; shut down the connection and free the +// handle. +void ssl_finish(SSL *ssl) +{ + // + // We won't be using this again, so we can just send the + // shutdown alert and free up the handle, and have our + // caller close the socket. + // + // XXX - presumably, if the connection is shut down on + // our side, either our peer won't have a problem sending + // their shutdown alert or will not treat such a problem + // as an error. If this causes errors to be reported, + // fix that as appropriate. + // + SSL_shutdown(ssl); + SSL_free(ssl); +} + +// Same return value as sock_send: +// 0 on OK, -1 on error but closed connection (-2). +int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen) +{ + int status = SSL_write(ssl, buffer, size); + if (status > 0) + { + // "SSL_write() will only return with success, when the complete contents (...) has been written." + return 0; + } + else + { + int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error? + if (ssl_err == SSL_ERROR_ZERO_RETURN) + { + return -2; + } + else if (ssl_err == SSL_ERROR_SYSCALL) + { +#ifndef _WIN32 + if (errno == ECONNRESET || errno == EPIPE) return -2; +#endif + } + snprintf(errbuf, errbuflen, "SSL_write(): %s", + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } +} + +// Returns the number of bytes read, or -1 on syserror, or -2 on SSL error. +int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen) +{ + int status = SSL_read(ssl, buffer, size); + if (status <= 0) + { + int ssl_err = SSL_get_error(ssl, status); + if (ssl_err == SSL_ERROR_ZERO_RETURN) + { + return 0; + } + else if (ssl_err == SSL_ERROR_SYSCALL) + { + return -1; + } + else + { + // Should not happen + snprintf(errbuf, errbuflen, "SSL_read(): %s", + ERR_error_string(ERR_get_error(), NULL)); + return -2; + } + } + else + { + return status; + } +} + +#endif // HAVE_OPENSSL diff --git a/src/libpcap-1.10.5/sslutils.h b/src/libpcap-1.10.5/sslutils.h new file mode 100644 index 0000000000..3a36c61b7f --- /dev/null +++ b/src/libpcap-1.10.5/sslutils.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __SSLUTILS_H__ +#define __SSLUTILS_H__ + +#ifdef HAVE_OPENSSL +#include "pcap/socket.h" // for PCAP_SOCKET +// If this is OpenSSL 1.0, at least one header may trigger a -Wdocumentation +// in Clang, which should not be a problem of this header or a file that +// includes it. +#include "diag-control.h" +DIAG_OFF_DOCUMENTATION +#include +#include +DIAG_ON_DOCUMENTATION + +/* + * Utility functions + */ + +void ssl_set_certfile(const char *certfile); +void ssl_set_keyfile(const char *keyfile); +int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen); +SSL *ssl_promotion(int is_server, PCAP_SOCKET s, char *errbuf, size_t errbuflen); +void ssl_finish(SSL *ssl); +int ssl_send(SSL *, char const *buffer, int size, char *errbuf, size_t errbuflen); +int ssl_recv(SSL *, char *buffer, int size, char *errbuf, size_t errbuflen); + +// The SSL parameters are used +#define _U_NOSSL_ + +#else // HAVE_OPENSSL + +// This saves us from a lot of ifdefs: +#define SSL void const + +// The SSL parameters are unused +#define _U_NOSSL_ _U_ + +#endif // HAVE_OPENSSL + +#endif // __SSLUTILS_H__ diff --git a/src/libpcap-1.10.5/sunatmpos.h b/src/libpcap-1.10.5/sunatmpos.h new file mode 100644 index 0000000000..787de85743 --- /dev/null +++ b/src/libpcap-1.10.5/sunatmpos.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1997 Yen Yen Lim and North Dakota State University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Yen Yen Lim and + North Dakota State University + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* SunATM header for ATM packet */ +#define SUNATM_DIR_POS 0 +#define SUNATM_VPI_POS 1 +#define SUNATM_VCI_POS 2 +#define SUNATM_PKT_BEGIN_POS 4 /* Start of ATM packet */ + +/* Protocol type values in the bottom for bits of the byte at SUNATM_DIR_POS. */ +#define PT_LANE 0x01 /* LANE */ +#define PT_LLC 0x02 /* LLC encapsulation */ +#define PT_ILMI 0x05 /* ILMI */ +#define PT_QSAAL 0x06 /* Q.SAAL */ diff --git a/src/libpcap-1.10.5/testprogs/CMakeLists.txt b/src/libpcap-1.10.5/testprogs/CMakeLists.txt new file mode 100644 index 0000000000..567f42aa6e --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/CMakeLists.txt @@ -0,0 +1,51 @@ +if(MSVC) + file(GLOB PROJECT_SOURCE_LIST_WIN32_C ${pcap_SOURCE_DIR}/missing/getopt.c) + include_directories(${pcap_SOURCE_DIR}/missing) +endif(MSVC) + +add_custom_target(testprogs) + +macro(add_test_executable _executable) + add_executable(${_executable} EXCLUDE_FROM_ALL + ${_executable}.c ${PROJECT_SOURCE_LIST_WIN32_C}) + if(NOT C_ADDITIONAL_FLAGS STREQUAL "") + set_target_properties(${_executable} PROPERTIES + COMPILE_FLAGS ${C_ADDITIONAL_FLAGS}) + endif() + if(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME} ${PCAP_LINK_LIBRARIES}) + else(WIN32) + target_link_libraries(${_executable} + ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) + endif(WIN32) + if(NOT "${LINKER_FLAGS}" STREQUAL "") + set_target_properties(${_executable} PROPERTIES + LINK_FLAGS "${LINKER_FLAGS}") + endif() + add_dependencies(testprogs ${_executable}) +endmacro() + +add_test_executable(can_set_rfmon_test) +add_test_executable(capturetest) +add_test_executable(filtertest) +add_test_executable(findalldevstest) +add_test_executable(findalldevstest-perf) +add_test_executable(opentest) +add_test_executable(reactivatetest) +add_test_executable(writecaptest) + +if(NOT WIN32) + add_test_executable(selpolltest) +endif() + +add_test_executable(threadsignaltest ${CMAKE_THREAD_LIBS_INIT}) + +# Same as in configure.ac. +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR + CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_test_executable(valgrindtest) +endif() + +add_subdirectory(fuzz) diff --git a/src/libpcap-1.10.5/testprogs/Makefile.in b/src/libpcap-1.10.5/testprogs/Makefile.in new file mode 100644 index 0000000000..d6b2351ed6 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/Makefile.in @@ -0,0 +1,172 @@ +# Copyright (c) 1993, 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +# Pathname of directory to install the configure program +bindir = @bindir@ +# Pathname of directory to install the rpcapd daemon +sbindir = @sbindir@ +# Pathname of directory to install the include files +includedir = @includedir@ +# Pathname of directory to install the library +libdir = @libdir@ +# Pathname of directory to install the man pages +mandir = @mandir@ + +# VPATH +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +# +# You shouldn't need to edit anything below. +# + +LD = /usr/bin/ld +CC = @CC@ +AR = @AR@ +LN_S = @LN_S@ +MKDEP = @MKDEP@ +CCOPT = @V_CCOPT@ +INCLS = -I. -I.. -I@srcdir@ -I@srcdir@/.. @V_INCLS@ +DEFS = @DEFS@ @V_DEFS@ +ADDLOBJS = @ADDLOBJS@ +ADDLARCHIVEOBJS = @ADDLARCHIVEOBJS@ +LIBS = @LIBS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +CROSSFLAGS= +CFLAGS = @CFLAGS@ ${CROSSFLAGS} +LDFLAGS = @LDFLAGS@ ${CROSSFLAGS} +DYEXT = @DYEXT@ +V_RPATH_OPT = @V_RPATH_OPT@ +DEPENDENCY_CFLAG = @DEPENDENCY_CFLAG@ + +# Standard CFLAGS for building test programs +FULL_CFLAGS = $(CCOPT) $(INCLS) $(DEFS) $(CFLAGS) + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# Explicitly define compilation rule since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +.c.o: + @rm -f $@ + $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c + +SRC = @VALGRINDTEST_SRC@ \ + can_set_rfmon_test.c \ + capturetest.c \ + filtertest.c \ + findalldevstest-perf.c \ + findalldevstest.c \ + opentest.c \ + nonblocktest.c \ + reactivatetest.c \ + selpolltest.c \ + threadsignaltest.c \ + writecaptest.c + +TESTS = $(SRC:.c=) + +TAGFILES = \ + $(SRC) $(HDR) + +CLEANFILES = $(OBJ) $(TESTS) + +all: $(TESTS) + +capturetest: $(srcdir)/capturetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o capturetest $(srcdir)/capturetest.c \ + ../libpcap.a $(LIBS) + +can_set_rfmon_test: $(srcdir)/can_set_rfmon_test.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o can_set_rfmon_test \ + $(srcdir)/can_set_rfmon_test.c \ + ../libpcap.a $(LIBS) + +filtertest: $(srcdir)/filtertest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o filtertest $(srcdir)/filtertest.c \ + ../libpcap.a $(LIBS) + +findalldevstest: $(srcdir)/findalldevstest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest \ + $(srcdir)/findalldevstest.c \ + ../libpcap.a $(LIBS) + +findalldevstest-perf: $(srcdir)/findalldevstest-perf.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o findalldevstest-perf \ + $(srcdir)/findalldevstest-perf.c \ + ../libpcap.a $(LIBS) + +opentest: $(srcdir)/opentest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o opentest $(srcdir)/opentest.c \ + ../libpcap.a $(LIBS) + +nonblocktest: $(srcdir)/nonblocktest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o nonblocktest $(srcdir)/nonblocktest.c \ + ../libpcap.a $(LIBS) + +reactivatetest: $(srcdir)/reactivatetest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o reactivatetest \ + $(srcdir)/reactivatetest.c ../libpcap.a $(LIBS) + +selpolltest: $(srcdir)/selpolltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o selpolltest $(srcdir)/selpolltest.c \ + ../libpcap.a $(LIBS) + +threadsignaltest: $(srcdir)/threadsignaltest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o threadsignaltest \ + $(srcdir)/threadsignaltest.c \ + ../libpcap.a $(LIBS) $(PTHREAD_LIBS) + +valgrindtest: $(srcdir)/valgrindtest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o valgrindtest $(srcdir)/valgrindtest.c \ + ../libpcap.a $(LIBS) + +writecaptest: $(srcdir)/writecaptest.c ../libpcap.a + $(CC) $(FULL_CFLAGS) -I. -L. -o writecaptest $(srcdir)/writecaptest.c \ + ../libpcap.a $(LIBS) + +clean: + rm -f $(CLEANFILES) + rm -rf *.dSYM + +distclean: clean + rm -f Makefile config.cache config.log config.status \ + config.h stamp-h stamp-h.in + rm -rf autom4te.cache + +install: + +uninstall: + +tags: $(TAGFILES) + ctags -wtd $(TAGFILES) + +depend: + $(MKDEP) -c $(CC) -m "$(DEPENDENCY_CFLAG)" -s "$(srcdir)" $(CFLAGS) $(DEFS) $(INCLS) $(SRC) diff --git a/src/libpcap-1.10.5/testprogs/can_set_rfmon_test.c b/src/libpcap-1.10.5/testprogs/can_set_rfmon_test.c new file mode 100644 index 0000000000..96816f9b97 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/can_set_rfmon_test.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include + +#include + +#include "pcap/funcattrs.h" + +static const char *program_name; + +/* Forwards */ +static void PCAP_NORETURN error(PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(1,2); + +int +main(int argc, char **argv) +{ + const char *cp; + pcap_t *pd; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", program_name); + return 2; + } + + pd = pcap_create(argv[1], ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_can_set_rfmon(pd); + if (status < 0) { + if (status == PCAP_ERROR) + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_geterr(pd)); + else + error("%s: pcap_can_set_rfmon failed: %s", argv[1], + pcap_statustostr(status)); + } + printf("%s: Monitor mode %s be set\n", argv[1], status ? "can" : "cannot"); + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/src/libpcap-1.10.5/testprogs/capturetest.c b/src/libpcap-1.10.5/testprogs/capturetest.c new file mode 100644 index 0000000000..4eadd33679 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/capturetest.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" +#else + #include +#endif +#include +#ifndef _WIN32 + #include +#endif +#include + +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; +#ifndef _WIN32 +static int breaksigint = 0; +#endif + +#ifndef _WIN32 +static void +sigint_handler(int signum _U_) +{ + if (breaksigint) + pcap_breakloop(pd); +} +#endif + +#ifdef _WIN32 +/* + * We don't have UN*X-style signals, so we don't have anything to test. + */ +#define B_OPTION "" +#define R_OPTION "" +#define S_OPTION "" +#else +/* + * We do have UN*X-style signals (we assume that "not Windows" means "UN*X"). + */ +#define B_OPTION "b" +#define R_OPTION "r" +#define S_OPTION "s" +#endif + +#define COMMAND_OPTIONS B_OPTION "i:mn" R_OPTION S_OPTION "t:" +#define USAGE_OPTIONS "-" B_OPTION "mn" R_OPTION S_OPTION + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + long longarg; + char *p; + int timeout = 1000; + int immediate = 0; + int nonblock = 0; +#ifndef _WIN32 + int sigrestart = 0; + int catchsigint = 0; +#endif + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + int packet_count; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) { + switch (op) { + +#ifndef _WIN32 + case 'b': + breaksigint = 1; + break; +#endif + + case 'i': + device = optarg; + break; + + case 'm': + immediate = 1; + break; + + case 'n': + nonblock = 1; + break; + +#ifndef _WIN32 + case 'r': + sigrestart = 1; + break; + + case 's': + catchsigint = 1; + break; +#endif + + case 't': + longarg = strtol(optarg, &p, 10); + if (p == optarg || *p != '\0') { + error("Timeout value \"%s\" is not a number", + optarg); + /* NOTREACHED */ + } + if (longarg < 0) { + error("Timeout value %ld is negative", longarg); + /* NOTREACHED */ + } + if (longarg > INT_MAX) { + error("Timeout value %ld is too large (> %d)", + longarg, INT_MAX); + /* NOTREACHED */ + } + timeout = (int)longarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + +#ifndef _WIN32 + /* + * If we were told to catch SIGINT, do so. + */ + if (catchsigint) { + struct sigaction action; + + action.sa_handler = sigint_handler; + sigemptyset(&action.sa_mask); + + /* + * Should SIGINT interrupt, or restart, system calls? + */ + action.sa_flags = sigrestart ? SA_RESTART : 0; + + if (sigaction(SIGINT, &action, NULL) == -1) + error("Can't catch SIGINT: %s\n", + strerror(errno)); + } +#endif + + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (immediate) { + status = pcap_set_immediate_mode(pd, 1); + if (status != 0) + error("%s: pcap_set_immediate_mode failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, timeout); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setnonblock(pd, nonblock, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + struct pcap_stat ps; + pcap_stats(pd, &ps); + printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n", + ps.ps_recv, ps.ps_drop, ps.ps_ifdrop); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + printf("Broken out of loop from SIGINT handler\n"); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_dispatch: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + pcap_freecode(&fcode); + free(cmdbuf); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ " USAGE_OPTIONS " ] [ -i interface ] [ -t timeout] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/src/libpcap-1.10.5/testprogs/filtertest.c b/src/libpcap-1.10.5/testprogs/filtertest.c new file mode 100644 index 0000000000..1729975564 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/filtertest.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include + +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" + #include "unix.h" +#else + #include +#endif +#include +#include +#ifdef _WIN32 + #include + #include +#else + #include + #include +#endif +#include +#include + +#include "pcap/funcattrs.h" + +#define MAXIMUM_SNAPLEN 262144 + +#ifdef BDEBUG +/* + * We have pcap_set_optimizer_debug() and pcap_set_print_dot_graph() in + * libpcap; declare them (they're not declared by any libpcap header, + * because they're special hacks, only available if libpcap was configured + * to include them, and only intended for use by libpcap developers trying + * to debug the optimizer for filter expressions). + */ +PCAP_API void pcap_set_optimizer_debug(int); +PCAP_API void pcap_set_print_dot_graph(int); +#endif + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + /* + * _read(), on Windows, has an unsigned int byte count and an + * int return value, so we can't handle a file bigger than + * INT_MAX - 1 bytes (and have no reason to do so; a filter *that* + * big will take forever to compile). (The -1 is for the '\0' at + * the end of the string.) + */ + if (buf.st_size > INT_MAX - 1) + error("%s is larger than %d bytes; that's too large", fname, + INT_MAX - 1); + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = (int)read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warn(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +int +main(int argc, char **argv) +{ + char *cp; + int op; + int dflag; +#ifdef BDEBUG + int gflag; +#endif + char *infile; + int Oflag; + int snaplen; + char *p; + int dlt; + bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN; + char *cmdbuf; + pcap_t *pd; + struct bpf_program fcode; + +#ifdef _WIN32 + if (pcap_wsockinit() != 0) + return 1; +#endif /* _WIN32 */ + + dflag = 1; +#ifdef BDEBUG + gflag = 0; +#endif + + infile = NULL; + Oflag = 1; + snaplen = MAXIMUM_SNAPLEN; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "dF:gm:Os:")) != -1) { + switch (op) { + + case 'd': + ++dflag; + break; + + case 'g': +#ifdef BDEBUG + ++gflag; + break; +#else + error("libpcap and filtertest not built with optimizer debugging enabled"); +#endif + + case 'F': + infile = optarg; + break; + + case 'O': + Oflag = 0; + break; + + case 'm': { + bpf_u_int32 addr; + + switch (inet_pton(AF_INET, optarg, &addr)) { + + case 0: + error("invalid netmask %s", optarg); + + case -1: + error("invalid netmask %s: %s", optarg, + pcap_strerror(errno)); + + case 1: + netmask = addr; + break; + } + break; + } + + case 's': { + char *end; + long long_snaplen; + + long_snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || long_snaplen < 0 + || long_snaplen > MAXIMUM_SNAPLEN) + error("invalid snaplen %s", optarg); + else { + if (snaplen == 0) + snaplen = MAXIMUM_SNAPLEN; + else + snaplen = (int)long_snaplen; + } + break; + } + + default: + usage(); + /* NOTREACHED */ + } + } + + if (optind >= argc) { + usage(); + /* NOTREACHED */ + } + + dlt = pcap_datalink_name_to_val(argv[optind]); + if (dlt < 0) { + dlt = (int)strtol(argv[optind], &p, 10); + if (p == argv[optind] || *p != '\0') + error("invalid data link type %s", argv[optind]); + } + + if (infile) + cmdbuf = read_infile(infile); + else + cmdbuf = copy_argv(&argv[optind+1]); + +#ifdef BDEBUG + pcap_set_optimizer_debug(dflag); + pcap_set_print_dot_graph(gflag); +#endif + + pd = pcap_open_dead(dlt, snaplen); + if (pd == NULL) + error("Can't open fake pcap_t"); + + if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (!bpf_validate(fcode.bf_insns, fcode.bf_len)) + warn("Filter doesn't pass validation"); + +#ifdef BDEBUG + if (cmdbuf != NULL) { + // replace line feed with space + for (cp = cmdbuf; *cp != '\0'; ++cp) { + if (*cp == '\r' || *cp == '\n') { + *cp = ' '; + } + } + // only show machine code if BDEBUG defined, since dflag > 3 + printf("machine codes for filter: %s\n", cmdbuf); + } else + printf("machine codes for empty filter:\n"); +#endif + + bpf_dump(&fcode, dflag); + free(cmdbuf); + pcap_freecode (&fcode); + pcap_close(pd); + exit(0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, +#ifdef BDEBUG + "Usage: %s [-dgO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", +#else + "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n", +#endif + program_name); + exit(1); +} diff --git a/src/libpcap-1.10.5/testprogs/findalldevstest-perf.c b/src/libpcap-1.10.5/testprogs/findalldevstest-perf.c new file mode 100644 index 0000000000..b56b44d111 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/findalldevstest-perf.c @@ -0,0 +1,95 @@ +#include + +#include +#include +#include +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include +#endif + +#include + +#include "varattrs.h" +#include "pcap/funcattrs.h" +#include "portability.h" + +int main(int argc _U_, char **argv _U_) +{ + pcap_if_t *alldevs; + int exit_status = 0; + char errbuf[PCAP_ERRBUF_SIZE+1]; +#ifdef _WIN32 + FILETIME start_ktime, start_utime, end_ktime, end_utime; + FILETIME dummy1, dummy2; + ULARGE_INTEGER start_kticks, end_kticks, start_uticks, end_uticks; + ULONGLONG ktime, utime, tottime; +#else + struct rusage start_rusage, end_rusage; + struct timeval ktime, utime, tottime; +#endif + +#ifdef _WIN32 + if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2, + &start_ktime, &start_utime)) + { + fprintf(stderr, "GetProcessTimes() fails at start\n"); + exit(1); + } + start_kticks.LowPart = start_ktime.dwLowDateTime; + start_kticks.HighPart = start_ktime.dwHighDateTime; + start_uticks.LowPart = start_utime.dwLowDateTime; + start_uticks.HighPart = start_utime.dwHighDateTime; +#else + if (getrusage(RUSAGE_SELF, &start_rusage) == -1) { + fprintf(stderr, "getrusage() fails at start\n"); + exit(1); + } +#endif + for (int i = 0; i < 500; i++) + { + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + pcap_freealldevs(alldevs); + } + +#ifdef _WIN32 + if (!GetProcessTimes(GetCurrentProcess(), &dummy1, &dummy2, + &end_ktime, &end_utime)) + { + fprintf(stderr, "GetProcessTimes() fails at end\n"); + exit(1); + } + end_kticks.LowPart = end_ktime.dwLowDateTime; + end_kticks.HighPart = end_ktime.dwHighDateTime; + end_uticks.LowPart = end_utime.dwLowDateTime; + end_uticks.HighPart = end_utime.dwHighDateTime; + ktime = end_kticks.QuadPart - start_kticks.QuadPart; + utime = end_uticks.QuadPart - start_uticks.QuadPart; + tottime = ktime + utime; + printf("Total CPU secs: kernel %g, user %g, total %g\n", + ((double)ktime) / 10000000.0, + ((double)utime) / 10000000.0, + ((double)tottime) / 10000000.0); +#else + if (getrusage(RUSAGE_SELF, &end_rusage) == -1) { + fprintf(stderr, "getrusage() fails at end\n"); + exit(1); + } + timersub(&end_rusage.ru_stime, &start_rusage.ru_stime, &ktime); + timersub(&end_rusage.ru_utime, &start_rusage.ru_utime, &utime); + timeradd(&ktime, &utime, &tottime); + printf("Total CPU secs: kernel %g, user %g, total %g\n", + (double)ktime.tv_sec + ((double)ktime.tv_usec / 1000000.0), + (double)utime.tv_sec + ((double)utime.tv_usec / 1000000.0), + (double)tottime.tv_sec + ((double)tottime.tv_usec / 1000000.0)); +#endif + exit(exit_status); +} diff --git a/src/libpcap-1.10.5/testprogs/findalldevstest.c b/src/libpcap-1.10.5/testprogs/findalldevstest.c new file mode 100644 index 0000000000..e4ec952984 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/findalldevstest.c @@ -0,0 +1,332 @@ +#include + +#include +#include +#include +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include + #include + #include + #include +#endif + +#include + +#include "varattrs.h" +#include "pcap/funcattrs.h" + +static int ifprint(pcap_if_t *d); +static char *iptos(bpf_u_int32 in); + +#ifdef _WIN32 +#include "portability.h" + +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} + +static char * +getpass(const char *prompt) +{ + HANDLE console_handle = GetStdHandle(STD_INPUT_HANDLE); + DWORD console_mode, save_console_mode; + static char password[128+1]; + char *p; + + fprintf(stderr, "%s", prompt); + + /* + * Turn off echoing. + */ + if (!GetConsoleMode(console_handle, &console_mode)) { + fprintf(stderr, "Can't get console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + save_console_mode = console_mode; + console_mode &= ~ENABLE_ECHO_INPUT; + if (!SetConsoleMode(console_handle, console_mode)) { + fprintf(stderr, "Can't set console mode: %s\n", + win32_strerror(GetLastError())); + exit(1); + } + if (fgets(password, sizeof password, stdin) == NULL) { + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + exit(1); + } + fprintf(stderr, "\n"); + SetConsoleMode(console_handle, save_console_mode); + p = strchr(password, '\n'); + if (p != NULL) + *p = '\0'; + return password; +} +#endif + +#ifdef ENABLE_REMOTE +int main(int argc, char **argv) +#else +int main(int argc _U_, char **argv _U_) +#endif +{ + pcap_if_t *alldevs; + pcap_if_t *d; + bpf_u_int32 net, mask; + int exit_status = 0; + char errbuf[PCAP_ERRBUF_SIZE+1]; +#ifdef ENABLE_REMOTE + struct pcap_rmtauth auth; + char username[128+1]; + char *p; + char *password; +#endif + +#ifdef ENABLE_REMOTE + if (argc >= 2) + { + if (pcap_findalldevs_ex(argv[1], NULL, &alldevs, errbuf) == -1) + { + /* + * OK, try it with a user name and password. + */ + fprintf(stderr, "User name: "); + if (fgets(username, sizeof username, stdin) == NULL) + exit(1); + p = strchr(username, '\n'); + if (p != NULL) + *p = '\0'; + password = getpass("Password: "); + auth.type = RPCAP_RMTAUTH_PWD; + auth.username = username; + auth.password = password; + if (pcap_findalldevs_ex(argv[1], &auth, &alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + } + else +#endif + { + if (pcap_findalldevs(&alldevs, errbuf) == -1) + { + fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf); + exit(1); + } + } + for(d=alldevs;d;d=d->next) + { + if (!ifprint(d)) + exit_status = 2; + } + + if (alldevs != NULL) + { + if (pcap_lookupnet(alldevs->name, &net, &mask, errbuf) < 0) + { + /* + * XXX - this doesn't distinguish between "a real error + * occurred" and "this interface doesn't *have* an IPv4 + * address". The latter shouldn't be treated as an error. + * + * We look for the interface name, followed by a colon and + * a space, and, if we find it,w e see if what follows it + * is "no IPv4 address assigned". + */ + size_t devnamelen = strlen(alldevs->name); + if (strncmp(errbuf, alldevs->name, devnamelen) == 0 && + strncmp(errbuf + devnamelen, ": ", 2) == 0 && + strcmp(errbuf + devnamelen + 2, "no IPv4 address assigned") == 0) + printf("Preferred device is not on an IPv4 network\n"); + else { + fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf); + exit_status = 2; + } + } + else + { + printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask)); + } + } + + pcap_freealldevs(alldevs); + exit(exit_status); +} + +static int ifprint(pcap_if_t *d) +{ + pcap_addr_t *a; + char ipv4_buf[INET_ADDRSTRLEN]; +#ifdef INET6 + char ipv6_buf[INET6_ADDRSTRLEN]; +#endif + const char *sep; + int status = 1; /* success */ + + printf("%s\n",d->name); + if (d->description) + printf("\tDescription: %s\n",d->description); + printf("\tFlags: "); + sep = ""; + if (d->flags & PCAP_IF_UP) { + printf("%sUP", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_RUNNING) { + printf("%sRUNNING", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_LOOPBACK) { + printf("%sLOOPBACK", sep); + sep = ", "; + } + if (d->flags & PCAP_IF_WIRELESS) { + printf("%sWIRELESS", sep); + switch (d->flags & PCAP_IF_CONNECTION_STATUS) { + + case PCAP_IF_CONNECTION_STATUS_UNKNOWN: + printf(" (association status unknown)"); + break; + + case PCAP_IF_CONNECTION_STATUS_CONNECTED: + printf(" (associated)"); + break; + + case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: + printf(" (not associated)"); + break; + + case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: + break; + } + } else { + switch (d->flags & PCAP_IF_CONNECTION_STATUS) { + + case PCAP_IF_CONNECTION_STATUS_UNKNOWN: + printf(" (connection status unknown)"); + break; + + case PCAP_IF_CONNECTION_STATUS_CONNECTED: + printf(" (connected)"); + break; + + case PCAP_IF_CONNECTION_STATUS_DISCONNECTED: + printf(" (disconnected)"); + break; + + case PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE: + break; + } + } + sep = ", "; + printf("\n"); + + for(a=d->addresses;a;a=a->next) { + if (a->addr != NULL) + switch(a->addr->sa_family) { + case AF_INET: + printf("\tAddress Family: AF_INET (%d)\n", a->addr->sa_family); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->addr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->netmask))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->broadaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET, + &((struct sockaddr_in *)(a->dstaddr))->sin_addr, + ipv4_buf, sizeof ipv4_buf)); + break; +#ifdef INET6 + case AF_INET6: + printf("\tAddress Family: AF_INET6 (%d)\n", a->addr->sa_family); + if (a->addr) + printf("\t\tAddress: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->addr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->netmask) + printf("\t\tNetmask: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->netmask))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->broadaddr) + printf("\t\tBroadcast Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->broadaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + if (a->dstaddr) + printf("\t\tDestination Address: %s\n", + inet_ntop(AF_INET6, + ((struct sockaddr_in6 *)(a->dstaddr))->sin6_addr.s6_addr, + ipv6_buf, sizeof ipv6_buf)); + break; +#endif + default: + printf("\tAddress Family: Unknown (%d)\n", a->addr->sa_family); + break; + } + else + { + fprintf(stderr, "\tWarning: a->addr is NULL, skipping this address.\n"); + status = 0; + } + } + printf("\n"); + return status; +} + +/* From tcptraceroute */ +#define IPTOSBUFFERS 12 +static char *iptos(bpf_u_int32 in) +{ + static char output[IPTOSBUFFERS][sizeof("255.255.255.255")]; + static short which; + u_char *p; + + p = (u_char *)∈ + which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1); + snprintf(output[which], sizeof(output[which]), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + return output[which]; +} diff --git a/src/libpcap-1.10.5/testprogs/fuzz/CMakeLists.txt b/src/libpcap-1.10.5/testprogs/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..67250cca43 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/CMakeLists.txt @@ -0,0 +1,43 @@ +add_executable(fuzz_pcap onefile.c fuzz_pcap.c) +target_link_libraries(fuzz_pcap ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(fuzz_pcap PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") +endif() + +add_executable(fuzz_filter onefile.c fuzz_filter.c) +target_link_libraries(fuzz_filter ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(fuzz_filter PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") +endif() + +add_executable(fuzz_both onefile.c fuzz_both.c) +target_link_libraries(fuzz_both ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(fuzz_both PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") +endif() + +if(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") +add_executable(fuzz_rclient onefile.c fuzz_rclient.c) +target_link_libraries(fuzz_rclient ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(fuzz_rclient PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") +endif() + +add_executable(fuzz_rserver onefile.c fuzz_rserver.c ../../rpcapd/daemon.c) +check_function_exists(crypt HAVE_CRYPT_IN_SYSTEM_LIBRARIES) +if(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + set(HAVE_CRYPT TRUE) +else(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) + set(PCAP_LINK_LIBRARIES ${PCAP_LINK_LIBRARIES} crypt) +endif(HAVE_CRYPT_IN_SYSTEM_LIBRARIES) +target_link_libraries(fuzz_rserver ${ARGN} ${LIBRARY_NAME}_static ${PCAP_LINK_LIBRARIES}) + +if(NOT "${SANITIZER_FLAGS}" STREQUAL "") + set_target_properties(fuzz_rserver PROPERTIES + LINK_FLAGS "${SANITIZER_FLAGS}") +endif() +endif(ENABLE_REMOTE AND "$ENV{CFLAGS}" MATCHES "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.c b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.c new file mode 100644 index 0000000000..59e3d40410 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include + +#include + +FILE * outfile = NULL; + +static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) { + FILE * fd; + if (remove(name) != 0) { + if (errno != ENOENT) { + printf("failed remove, errno=%d\n", errno); + return -1; + } + } + fd = fopen(name, "wb"); + if (fd == NULL) { + printf("failed open, errno=%d\n", errno); + return -2; + } + if (fwrite (Data, 1, Size, fd) != Size) { + fclose(fd); + return -3; + } + fclose(fd); + return 0; +} + +void fuzz_openFile(const char * name) { + if (outfile != NULL) { + fclose(outfile); + } + outfile = fopen(name, "w"); +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + pcap_t * pkts; + char errbuf[PCAP_ERRBUF_SIZE]; + const u_char *pkt; + struct pcap_pkthdr *header; + int r; + size_t filterSize; + char * filter; + struct bpf_program bpf; + + + //initialize output file + if (outfile == NULL) { + outfile = fopen("/dev/null", "w"); + if (outfile == NULL) { + return 0; + } + } + + if (Size < 1) { + return 0; + } + filterSize = Data[0]; + if (Size < 1+filterSize || filterSize == 0) { + return 0; + } + + //rewrite buffer to a file as libpcap does not have buffer inputs + if (bufferToFile("/tmp/fuzz.pcap", Data+1+filterSize, Size-(1+filterSize)) < 0) { + return 0; + } + + //initialize structure + pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf); + if (pkts == NULL) { + fprintf(outfile, "Couldn't open pcap file %s\n", errbuf); + return 0; + } + + filter = malloc(filterSize); + memcpy(filter, Data+1, filterSize); + //null terminate string + filter[filterSize-1] = 0; + + if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) { + //loop over packets + r = pcap_next_ex(pkts, &header, &pkt); + while (r > 0) { + //checks filter + fprintf(outfile, "packet length=%d/%d filter=%d\n",header->caplen, header->len, pcap_offline_filter(&bpf, header, pkt)); + r = pcap_next_ex(pkts, &header, &pkt); + } + //close structure + pcap_close(pkts); + pcap_freecode(&bpf); + } + else { + pcap_close(pkts); + } + free(filter); + + return 0; +} diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.options b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.options new file mode 100644 index 0000000000..0824b19fab --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_both.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 65535 diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.c b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.c new file mode 100644 index 0000000000..de35067279 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.c @@ -0,0 +1,43 @@ +#include +#include +#include + +#include + +void fuzz_openFile(const char * name){ + //do nothing +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + pcap_t * pkts; + struct bpf_program bpf; + char * filter; + + //we need at least 1 byte for linktype + if (Size < 1) { + return 0; + } + + //initialize structure snaplen = 65535 + pkts = pcap_open_dead(Data[Size-1], 0xFFFF); + if (pkts == NULL) { + printf("pcap_open_dead failed\n"); + return 0; + } + filter = malloc(Size); + memcpy(filter, Data, Size); + //null terminate string + filter[Size-1] = 0; + + if (pcap_compile(pkts, &bpf, filter, 1, PCAP_NETMASK_UNKNOWN) == 0) { + pcap_setfilter(pkts, &bpf); + pcap_close(pkts); + pcap_freecode(&bpf); + } + else { + pcap_close(pkts); + } + free(filter); + + return 0; +} diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.options b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.options new file mode 100644 index 0000000000..9fda93fcb3 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_filter.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 4096 diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.c b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.c new file mode 100644 index 0000000000..fba5312fca --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +#include + +FILE * outfile = NULL; + +static int bufferToFile(const char * name, const uint8_t *Data, size_t Size) { + FILE * fd; + if (remove(name) != 0) { + if (errno != ENOENT) { + printf("failed remove, errno=%d\n", errno); + return -1; + } + } + fd = fopen(name, "wb"); + if (fd == NULL) { + printf("failed open, errno=%d\n", errno); + return -2; + } + if (fwrite (Data, 1, Size, fd) != Size) { + fclose(fd); + return -3; + } + fclose(fd); + return 0; +} + +void fuzz_openFile(const char * name) { + if (outfile != NULL) { + fclose(outfile); + } + outfile = fopen(name, "w"); +} + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + pcap_t * pkts; + char errbuf[PCAP_ERRBUF_SIZE]; + const u_char *pkt; + struct pcap_pkthdr *header; + struct pcap_stat stats; + int r; + + //initialize output file + if (outfile == NULL) { + outfile = fopen("/dev/null", "w"); + if (outfile == NULL) { + return 0; + } + } + + //rewrite buffer to a file as libpcap does not have buffer inputs + if (bufferToFile("/tmp/fuzz.pcap", Data, Size) < 0) { + return 0; + } + + //initialize structure + pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf); + if (pkts == NULL) { + fprintf(outfile, "Couldn't open pcap file %s\n", errbuf); + return 0; + } + + //loop over packets + r = pcap_next_ex(pkts, &header, &pkt); + while (r > 0) { + //TODO pcap_offline_filter + fprintf(outfile, "packet length=%d/%d\n",header->caplen, header->len); + r = pcap_next_ex(pkts, &header, &pkt); + } + if (pcap_stats(pkts, &stats) == 0) { + fprintf(outfile, "number of packets=%d\n", stats.ps_recv); + } + //close structure + pcap_close(pkts); + + return 0; +} diff --git a/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.options b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.options new file mode 100644 index 0000000000..0824b19fab --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/fuzz_pcap.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 65535 diff --git a/src/libpcap-1.10.5/testprogs/fuzz/onefile.c b/src/libpcap-1.10.5/testprogs/fuzz/onefile.c new file mode 100644 index 0000000000..690a63bdc4 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/fuzz/onefile.c @@ -0,0 +1,54 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +void fuzz_openFile(const char * name); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t *Data; + size_t Size; + + if (argc == 3) { + fuzz_openFile(argv[2]); + } else if (argc != 2) { + return 1; + } + //opens the file, get its size, and reads it into a buffer + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + return 2; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + return 2; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + return 2; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + return 2; + } + Data = malloc(Size); + if (Data == NULL) { + fclose(fp); + return 2; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + free(Data); + return 2; + } + + //launch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + free(Data); + fclose(fp); + return 0; +} + diff --git a/src/libpcap-1.10.5/testprogs/nonblocktest.c b/src/libpcap-1.10.5/testprogs/nonblocktest.c new file mode 100644 index 0000000000..72700a3b64 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/nonblocktest.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +/* + * Tests for pcap_set_nonblock / pcap_get_nonblock: + * - idempotency + * - set/get are symmetric + * - get returns the same before/after activate + * - pcap_breakloop works after setting nonblock on and then off + * + * Really this is meant to + * be run manually under strace, to check for extra + * calls to eventfd or close. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static pcap_t *pd; +static char *program_name = "nonblocktest"; +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -i interface ]\n", + program_name); + exit(1); +} + +static void +breakme(u_char *user _U_, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + warning("using pcap_breakloop()"); + pcap_breakloop(pd); +} + +int +main(int argc, char **argv) +{ + int status, op, i, ret; + char *device; + pcap_if_t *devlist; + char ebuf[PCAP_ERRBUF_SIZE]; + + device = NULL; + while ((op = getopt(argc, argv, "i:sptnq")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + warning("listening on %s", device); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + /* set nonblock before activate */ + if (pcap_setnonblock(pd, 1, ebuf) < 0) + error("pcap_setnonblock failed: %s", ebuf); + /* getnonblock just returns "not activated yet" */ + ret = pcap_getnonblock(pd, ebuf); + if (ret != PCAP_ERROR_NOT_ACTIVATED) + error("pcap_getnonblock unexpectedly succeeded"); + if ((status = pcap_activate(pd)) < 0) + error("pcap_activate failed"); + ret = pcap_getnonblock(pd, ebuf); + if (ret != 1) + error( "pcap_getnonblock did not return nonblocking" ); + + /* Set nonblock multiple times, ensure with strace that it's a noop */ + for (i=0; i<10; i++) { + if (pcap_setnonblock(pd, 1, ebuf) < 0) + error("pcap_setnonblock failed: %s", ebuf); + ret = pcap_getnonblock(pd, ebuf); + if (ret != 1) + error( "pcap_getnonblock did not return nonblocking" ); + } + /* Set block multiple times, ensure with strace that it's a noop */ + for (i=0; i<10; i++) { + if (pcap_setnonblock(pd, 0, ebuf) < 0) + error("pcap_setnonblock failed: %s", ebuf); + ret = pcap_getnonblock(pd, ebuf); + if (ret != 0) + error( "pcap_getnonblock did not return blocking" ); + } + + /* Now pcap_loop forever, with a callback that + * uses pcap_breakloop to get out of forever */ + pcap_loop(pd, -1, breakme, NULL); + + /* Now test that pcap_setnonblock fails if we can't open the + * eventfd. */ + if (pcap_setnonblock(pd, 1, ebuf) < 0) + error("pcap_setnonblock failed: %s", ebuf); + while (1) { + ret = open("/dev/null", O_RDONLY); + if (ret < 0) + break; + } + ret = pcap_setnonblock(pd, 0, ebuf); + if (ret == 0) + error("pcap_setnonblock succeeded even though file table is full"); + else + warning("pcap_setnonblock failed as expected: %s", ebuf); +} diff --git a/src/libpcap-1.10.5/testprogs/opentest.c b/src/libpcap-1.10.5/testprogs/opentest.c new file mode 100644 index 0000000000..a441dda126 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/opentest.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" +#else + #include +#endif +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +#define MAXIMUM_SNAPLEN 262144 + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *device; + int dorfmon, dopromisc, snaplen, useactivate, bufsize; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist; + pcap_t *pd; + int status = 0; + + device = NULL; + dorfmon = 0; + dopromisc = 0; + snaplen = MAXIMUM_SNAPLEN; + bufsize = 0; + useactivate = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:Ips:aB:")) != -1) { + switch (op) { + + case 'i': + device = strdup(optarg); + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + case 'p': + dopromisc = 1; + break; + + case 's': { + char *end; + long long_snaplen; + + long_snaplen = strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' + || long_snaplen < 0 + || long_snaplen > MAXIMUM_SNAPLEN) + error("invalid snaplen %s", optarg); + else { + if (snaplen == 0) + snaplen = MAXIMUM_SNAPLEN; + else + snaplen = (int)long_snaplen; + } + break; + } + + case 'B': + bufsize = atoi(optarg)*1024; + if (bufsize <= 0) + error("invalid packet buffer size %s", optarg); + useactivate = 1; /* required for bufsize */ + break; + + case 'a': + useactivate = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, snaplen); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + if (dopromisc) { + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + } + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + if (bufsize != 0) { + status = pcap_set_buffer_size(pd, bufsize); + if (status != 0) + error("%s: pcap_set_buffer_size failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else + printf("%s opened successfully\n", device); + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + else + printf("%s opened successfully\n", device); + } + free(device); + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [ -Ipa ] [ -i interface ] [ -s snaplen ] [ -B bufsize ]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} diff --git a/src/libpcap-1.10.5/testprogs/reactivatetest.c b/src/libpcap-1.10.5/testprogs/reactivatetest.c new file mode 100644 index 0000000000..a9c987aa50 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/reactivatetest.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include + +#include "pcap/funcattrs.h" + +/* Forwards */ +static void PCAP_NORETURN error(PCAP_FORMAT_STRING(const char *), ...) PCAP_PRINTFLIKE(1,2); + +int +main(void) +{ + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_t *pd; + int status = 0; + + pd = pcap_open_live("lo0", 65535, 0, 1000, ebuf); + if (pd == NULL) { + pd = pcap_open_live("lo", 65535, 0, 1000, ebuf); + if (pd == NULL) { + error("Neither lo0 nor lo could be opened: %s", + ebuf); + } + } + status = pcap_activate(pd); + if (status != PCAP_ERROR_ACTIVATED) { + if (status == 0) + error("pcap_activate() of opened pcap_t succeeded"); + else if (status == PCAP_ERROR) + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_geterr(pd)); + else + error("pcap_activate() of opened pcap_t failed with %s, not PCAP_ERROR_ACTIVATED", + pcap_statustostr(status)); + } + return 0; +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "reactivatetest: "); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} diff --git a/src/libpcap-1.10.5/testprogs/selpolltest.c b/src/libpcap-1.10.5/testprogs/selpolltest.c new file mode 100644 index 0000000000..ab7f8f462a --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/selpolltest.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +/* + * Tests how select() and poll() behave on the selectable file descriptor + * for a pcap_t. + * + * This would be significantly different on Windows, as it'd test + * how WaitForMultipleObjects() would work on the event handle for a + * pcap_t. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#else +#include /* older UN*Xes */ +#endif +#include + +#include "pcap/funcattrs.h" + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +int +main(int argc, char **argv) +{ + register int op; + bpf_u_int32 localnet, netmask; + register char *cp, *cmdbuf, *device; + int doselect, dopoll, dotimeout, dononblock, quiet; + const char *mechanism; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist; + int selectable_fd = -1; + const struct timeval *required_timeout; + int status; + int packet_count; + + device = NULL; + doselect = 0; + dopoll = 0; + mechanism = NULL; + dotimeout = 0; + dononblock = 0; + quiet = 0; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:sptnq")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 's': + doselect = 1; + mechanism = "select() and pcap_dispatch()"; + break; + + case 'p': + dopoll = 1; + mechanism = "poll() and pcap_dispatch()"; + break; + + case 't': + dotimeout = 1; + break; + + case 'n': + dononblock = 1; + break; + + case 'q': + quiet = 1; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (doselect && dopoll) { + fprintf(stderr, "selpolltest: choose select (-s) or poll (-p), but not both\n"); + return 1; + } + if (dotimeout && !doselect && !dopoll) { + fprintf(stderr, "selpolltest: timeout (-t) requires select (-s) or poll (-p)\n"); + return 1; + } + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 0, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + + if (doselect || dopoll) { + /* + * We need either an FD on which to do select()/poll() + * or, if there isn't one, a timeout to use in select()/ + * poll(). + */ + selectable_fd = pcap_get_selectable_fd(pd); + if (selectable_fd == -1) { + printf("Listening on %s, using %s, with a timeout\n", + device, mechanism); + required_timeout = pcap_get_required_select_timeout(pd); + if (required_timeout == NULL) + error("select()/poll() isn't supported on %s, even with a timeout", + device); + + /* + * As we won't be notified by select() or poll() + * that a read can be done, we'll have to periodically + * try reading from the device every time the required + * timeout expires, and we don't want those attempts + * to block if nothing has arrived in that interval, + * so we want to force non-blocking mode. + */ + dononblock = 1; + } else { + printf("Listening on %s, using %s\n", device, + mechanism); + required_timeout = NULL; + } + } else + printf("Listening on %s, using pcap_dispatch()\n", device); + + if (dononblock) { + if (pcap_setnonblock(pd, 1, ebuf) == -1) + error("pcap_setnonblock failed: %s", ebuf); + } + if (doselect) { + for (;;) { + fd_set setread, setexcept; + struct timeval seltimeout; + struct timeval *timeoutp; + + FD_ZERO(&setread); + if (selectable_fd != -1) { + FD_SET(selectable_fd, &setread); + FD_ZERO(&setexcept); + FD_SET(selectable_fd, &setexcept); + } + required_timeout = pcap_get_required_select_timeout(pd); + if (dotimeout) { + seltimeout.tv_sec = 0; + if (required_timeout != NULL && + required_timeout->tv_usec < 1000) + seltimeout.tv_usec = required_timeout->tv_usec; + else + seltimeout.tv_usec = 1000; + timeoutp = &seltimeout; + } else if (required_timeout != NULL) { + seltimeout = *required_timeout; + timeoutp = &seltimeout; + } else { + timeoutp = NULL; + } + status = select((selectable_fd == -1) ? + 0 : selectable_fd + 1, &setread, NULL, &setexcept, + timeoutp); + if (status == -1) { + printf("Select returns error (%s)\n", + strerror(errno)); + } else { + if (!quiet) { + if (status == 0) + printf("Select timed out: "); + else{ + printf("Select returned a descriptor: "); + if (FD_ISSET(selectable_fd, &setread)) + printf("readable, "); + else + printf("not readable, "); + if (FD_ISSET(selectable_fd, &setexcept)) + printf("exceptional condition\n"); + else + printf("no exceptional condition\n"); + } + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + printf("%d packets seen, %d packets counted after select returns\n", + status, packet_count); + } + } + } + } else if (dopoll) { + for (;;) { + struct pollfd fd; + int polltimeout; + + fd.fd = selectable_fd; + fd.events = POLLIN; + required_timeout = pcap_get_required_select_timeout(pd); + if (dotimeout) + polltimeout = 1; + else if (required_timeout != NULL && + required_timeout->tv_usec >= 1000) + polltimeout = (int)(required_timeout->tv_usec/1000); + else + polltimeout = -1; + status = poll(&fd, (selectable_fd == -1) ? 0 : 1, polltimeout); + if (status == -1) { + printf("Poll returns error (%s)\n", + strerror(errno)); + } else { + if (!quiet) { + if (status == 0) + printf("Poll timed out\n"); + else { + printf("Poll returned a descriptor: "); + if (fd.revents & POLLIN) + printf("readable, "); + else + printf("not readable, "); + if (fd.revents & POLLERR) + printf("exceptional condition, "); + else + printf("no exceptional condition, "); + if (fd.revents & POLLHUP) + printf("disconnect, "); + else + printf("no disconnect, "); + if (fd.revents & POLLNVAL) + printf("invalid\n"); + else + printf("not invalid\n"); + } + } + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + /* + * Don't report this if we're using a + * required timeout and we got no packets, + * because that could be a very short timeout, + * and we don't want to spam the user with + * a ton of "no packets" reports. + */ + if (status != 0 || packet_count != 0 || + required_timeout != NULL) { + printf("%d packets seen, %d packets counted after poll returns\n", + status, packet_count); + } + } + } + } else { + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_dispatch: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -sptnq ] [ -i interface ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/src/libpcap-1.10.5/testprogs/threadsignaltest.c b/src/libpcap-1.10.5/testprogs/threadsignaltest.c new file mode 100644 index 0000000000..c9ade76fe5 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/threadsignaltest.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include + #include + + #define THREAD_HANDLE HANDLE + #define THREAD_FUNC_ARG_TYPE LPVOID + #define THREAD_FUNC_RETURN_TYPE DWORD __stdcall + + #include "getopt.h" +#else + #include + #include + #include + + #define THREAD_HANDLE pthread_t + #define THREAD_FUNC_ARG_TYPE void * + #define THREAD_FUNC_RETURN_TYPE void * +#endif +#include +#include + +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void countme(u_char *, const struct pcap_pkthdr *, const u_char *); +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +#ifdef _WIN32 +/* + * Generate a string for a Win32-specific error (i.e. an error generated when + * calling a Win32 API). + * For errors occurred during standard C calls, we still use pcap_strerror() + */ +#define ERRBUF_SIZE 1024 +static const char * +win32_strerror(DWORD error) +{ + static char errbuf[ERRBUF_SIZE+1]; + size_t errlen; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, + ERRBUF_SIZE, NULL); + + /* + * "FormatMessage()" "helpfully" sticks CR/LF at the end of the + * message. Get rid of it. + */ + errlen = strlen(errbuf); + if (errlen >= 2) { + errbuf[errlen - 1] = '\0'; + errbuf[errlen - 2] = '\0'; + errlen -= 2; + } + return errbuf; +} +#else +static void +catch_sigusr1(int sig _U_) +{ + printf("Got SIGUSR1\n"); +} +#endif + +static void +sleep_secs(int secs) +{ +#ifdef _WIN32 + Sleep(secs*1000); +#else + unsigned secs_remaining; + + if (secs <= 0) + return; + secs_remaining = secs; + while (secs_remaining != 0) + secs_remaining = sleep(secs_remaining); +#endif +} + +static THREAD_FUNC_RETURN_TYPE +capture_thread_func(THREAD_FUNC_ARG_TYPE arg) +{ + char *device = arg; + int packet_count; + int status; +#ifndef _WIN32 + struct sigaction action; + sigset_t mask; +#endif + +#ifndef _WIN32 + sigemptyset(&mask); + action.sa_handler = catch_sigusr1; + action.sa_mask = mask; + action.sa_flags = 0; + if (sigaction(SIGUSR1, &action, NULL) == -1) + error("Can't catch SIGUSR1: %s", strerror(errno)); +#endif + + printf("Listening on %s\n", device); + for (;;) { + packet_count = 0; + status = pcap_dispatch(pd, -1, countme, + (u_char *)&packet_count); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen, %d packets counted after pcap_dispatch returns\n", + status, packet_count); + } else + printf("No packets seen by pcap_dispatch\n"); + } + if (status == PCAP_ERROR_BREAK) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + printf("Loop got broken\n"); + } + (void)fflush(stdout); + if (status == PCAP_ERROR) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_dispatch: %s\n", + program_name, pcap_geterr(pd)); + } + return 0; +} + +int +main(int argc, char **argv) +{ + register int op; + register char *cp, *cmdbuf, *device; + int do_wakeup = 1; + pcap_if_t *devlist; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; + int status; + THREAD_HANDLE capture_thread; +#ifndef _WIN32 + void *retval; +#endif + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "i:n")) != -1) { + switch (op) { + + case 'i': + device = optarg; + break; + + case 'n': + do_wakeup = 0; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + *ebuf = '\0'; + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + status = pcap_set_timeout(pd, 5*60*1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + +#ifdef _WIN32 + capture_thread = CreateThread(NULL, 0, capture_thread_func, device, + 0, NULL); + if (capture_thread == NULL) + error("Can't create capture thread: %s", + win32_strerror(GetLastError())); +#else + status = pthread_create(&capture_thread, NULL, capture_thread_func, + device); + if (status != 0) + error("Can't create capture thread: %s", strerror(status)); +#endif + sleep_secs(60); + printf("Doing pcap_breakloop()\n"); + pcap_breakloop(pd); + if (do_wakeup) { + /* + * Force a wakeup in the capture thread. + * + * On some platforms, with some devices,, pcap_breakloop() + * can't do that itself. On Windows, poke the device's + * event handle; on UN*X, send a SIGUSR1 to the thread. + */ +#ifdef _WIN32 + printf("Setting event\n"); + if (!SetEvent(pcap_getevent(pd))) + error("Can't set event for pcap_t: %s", + win32_strerror(GetLastError())); +#else + printf("Sending SIGUSR1\n"); + status = pthread_kill(capture_thread, SIGUSR1); + if (status != 0) + warning("Can't interrupt capture thread: %s", + strerror(status)); +#endif + } + + /* + * Now wait for the capture thread to terminate. + */ +#ifdef _WIN32 + if (WaitForSingleObject(capture_thread, INFINITE) == WAIT_FAILED) + error("Wait for thread termination failed: %s", + win32_strerror(GetLastError())); + CloseHandle(capture_thread); +#else + status = pthread_join(capture_thread, &retval); + if (status != 0) + error("Wait for thread termination failed: %s", + strerror(status)); +#endif + + pcap_close(pd); + pcap_freecode(&fcode); + exit(status == -1 ? 1 : 0); +} + +static void +countme(u_char *user, const struct pcap_pkthdr *h _U_, const u_char *sp _U_) +{ + int *counterp = (int *)user; + + (*counterp)++; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [ -n ] [ -i interface ] [ expression ]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/src/libpcap-1.10.5/testprogs/unix.h b/src/libpcap-1.10.5/testprogs/unix.h new file mode 100644 index 0000000000..68ef4cb92a --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/unix.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef unix_h +#define unix_h + +/* + * Definitions to make MSVC C runtime library structures and functions + * look like the UNIX structures and functions they are intended to + * resemble. + */ +#ifdef _MSC_VER + #define stat _stat + #define fstat _fstat + + #define open _open + #define O_RDONLY _O_RDONLY + #define O_WRONLY _O_WRONLY + #define O_RDWR _O_RDWR + #define O_BINARY _O_BINARY + #define O_CREAT _O_CREAT + #define O_TRUNC _O_TRUNC + #define read _read + #define write _write + #define close _close +#endif + +#endif diff --git a/src/libpcap-1.10.5/testprogs/valgrindtest.c b/src/libpcap-1.10.5/testprogs/valgrindtest.c new file mode 100644 index 0000000000..22b75b0dbe --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/valgrindtest.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +/* + * This doesn't actually test libpcap itself; it tests whether + * valgrind properly handles the APIs libpcap uses. If it doesn't, + * we end up getting patches submitted to "fix" references that + * valgrind claims are being made to uninitialized data, when, in + * fact, the OS isn't making any such references - or we get + * valgrind *not* detecting *actual* incorrect references. + * + * Both BPF and Linux socket filters aren't handled correctly + * by some versions of valgrind. See valgrind bug 318203 for + * Linux: + * + * https://bugs.kde.org/show_bug.cgi?id=318203 + * + * and valgrind bug 312989 for macOS: + * + * https://bugs.kde.org/show_bug.cgi?id=312989 + * + * The fixes for both of those are checked into the official valgrind + * repository. + * + * The unofficial FreeBSD port has similar issues to the official macOS + * port, for similar reasons. + */ +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcap/funcattrs.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(_AIX) || defined(sun) +/* OS with BPF - use BPF */ +#define USE_BPF +#elif defined(__linux__) +/* Linux - use socket filters */ +#define USE_SOCKET_FILTERS +#else +#error "Unknown platform or platform that doesn't support Valgrind" +#endif + +#if defined(USE_BPF) + +#include +#include + +/* + * Make "pcap.h" not include "pcap/bpf.h"; we are going to include the + * native OS version, as we're going to be doing our own ioctls to + * make sure that, in the uninitialized-data tests, the filters aren't + * checked by libpcap before being handed to BPF. + */ +#define PCAP_DONT_INCLUDE_PCAP_BPF_H + +#elif defined(USE_SOCKET_FILTERS) + +#include +#include +#include + +#endif + +/* + * Squelch a warning. + * + * We include system headers to be able to directly set the filter to + * a program with uninitialized content, to make sure what we're testing + * is Valgrind's checking of the system call to set the filter, and we + * also include to open the device in the first place, and that + * means that we may get collisions between their definitions of + * BPF_STMT and BPF_JUMP - and do, in fact, get them on Linux (the + * definitions may be semantically the same, but that's not sufficient to + * avoid the warnings, as the preprocessor doesn't know that u_short is + * just unsigned short). + * + * So we undefine BPF_STMT and BPF_JUMP to avoid the warning. + */ +#undef BPF_STMT +#undef BPF_JUMP +#include + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); + +/* + * On Windows, we need to open the file in binary mode, so that + * we get all the bytes specified by the size we get from "fstat()". + * On UNIX, that's not necessary. O_BINARY is defined on Windows; + * we define it as 0 if it's not defined, so it does nothing. + */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static char * +read_infile(char *fname) +{ + register int i, fd, cc; + register char *cp; + struct stat buf; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd < 0) + error("can't open %s: %s", fname, pcap_strerror(errno)); + + if (fstat(fd, &buf) < 0) + error("can't stat %s: %s", fname, pcap_strerror(errno)); + + /* + * _read(), on Windows, has an unsigned int byte count and an + * int return value, so we can't handle a file bigger than + * INT_MAX - 1 bytes (and have no reason to do so; a filter *that* + * big will take forever to compile). (The -1 is for the '\0' at + * the end of the string.) + */ + if (buf.st_size > INT_MAX - 1) + error("%s is larger than %d bytes; that's too large", fname, + INT_MAX - 1); + cp = malloc((u_int)buf.st_size + 1); + if (cp == NULL) + error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, + fname, pcap_strerror(errno)); + cc = (int)read(fd, cp, (u_int)buf.st_size); + if (cc < 0) + error("read %s: %s", fname, pcap_strerror(errno)); + if (cc != buf.st_size) + error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); + + close(fd); + /* replace "# comment" with spaces */ + for (i = 0; i < cc; i++) { + if (cp[i] == '#') + while (i < cc && cp[i] != '\n') + cp[i++] = ' '; + } + cp[cc] = '\0'; + return (cp); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} + +#define INSN_COUNT 17 + +int +main(int argc, char **argv) +{ + char *cp, *device; + int op; + int dorfmon, useactivate; + char ebuf[PCAP_ERRBUF_SIZE]; + char *infile; + const char *cmdbuf; + pcap_if_t *devlist; + pcap_t *pd; + int status = 0; + int pcap_fd; +#if defined(USE_BPF) + struct bpf_program bad_fcode; + struct bpf_insn uninitialized[INSN_COUNT]; +#elif defined(USE_SOCKET_FILTERS) + struct sock_fprog bad_fcode; + struct sock_filter uninitialized[INSN_COUNT]; +#endif + struct bpf_program fcode; + + device = NULL; + dorfmon = 0; + useactivate = 0; + infile = NULL; + + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, "aF:i:I")) != -1) { + switch (op) { + + case 'a': + useactivate = 1; + break; + + case 'F': + infile = optarg; + break; + + case 'i': + device = optarg; + break; + + case 'I': + dorfmon = 1; + useactivate = 1; /* required for rfmon */ + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (device == NULL) { + /* + * No interface specified; get whatever pcap_lookupdev() + * finds. + */ + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + + if (infile != NULL) { + /* + * Filter specified with "-F" and a file containing + * a filter. + */ + cmdbuf = read_infile(infile); + } else { + if (optind < argc) { + /* + * Filter specified with arguments on the + * command line. + */ + cmdbuf = copy_argv(&argv[optind+1]); + } else { + /* + * No filter specified; use an empty string, which + * compiles to an "accept all" filter. + */ + cmdbuf = ""; + } + } + + if (useactivate) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s: pcap_create() failed: %s", device, ebuf); + status = pcap_set_snaplen(pd, 65535); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + status = pcap_set_promisc(pd, 1); + if (status != 0) + error("%s: pcap_set_promisc failed: %s", + device, pcap_statustostr(status)); + if (dorfmon) { + status = pcap_set_rfmon(pd, 1); + if (status != 0) + error("%s: pcap_set_rfmon failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pd, 1000); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + } else { + *ebuf = '\0'; + pd = pcap_open_live(device, 65535, 1, 1000, ebuf); + if (pd == NULL) + error("%s", ebuf); + else if (*ebuf) + warning("%s", ebuf); + } + + pcap_fd = pcap_fileno(pd); + + /* + * Try setting a filter with an uninitialized bpf_program + * structure. This should cause valgrind to report a + * problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Try setting a filter with an initialized bpf_program + * structure that points to an uninitialized program. + * That should also cause valgrind to report a problem. + * + * We don't check for errors, because it could get an + * error due to a bad pointer or count. + */ +#if defined(USE_BPF) + bad_fcode.bf_len = INSN_COUNT; + bad_fcode.bf_insns = uninitialized; + ioctl(pcap_fd, BIOCSETF, &bad_fcode); +#elif defined(USE_SOCKET_FILTERS) + bad_fcode.len = INSN_COUNT; + bad_fcode.filter = uninitialized; + setsockopt(pcap_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bad_fcode, + sizeof(bad_fcode)); +#endif + + /* + * Now compile a filter and set the filter with that. + * That should *not* cause valgrind to report a + * problem. + */ + if (pcap_compile(pd, &fcode, cmdbuf, 1, 0) < 0) + error("can't compile filter: %s", pcap_geterr(pd)); + if (pcap_setfilter(pd, &fcode) < 0) + error("can't set filter: %s", pcap_geterr(pd)); + + pcap_close(pd); + exit(status < 0 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "%s, with %s\n", program_name, + pcap_lib_version()); + (void)fprintf(stderr, + "Usage: %s [-aI] [ -F file ] [ -i interface ] [ expression ]\n", + program_name); + exit(1); +} diff --git a/src/libpcap-1.10.5/testprogs/visopts.py b/src/libpcap-1.10.5/testprogs/visopts.py new file mode 100755 index 0000000000..97eafffff4 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/visopts.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python + +""" +This program parses the output from pcap_compile() to visualize the CFG after +each optimize phase. + +Usage guide: +1. Enable optimizer debugging code when configure libpcap, + and build libpcap & the test programs + ./configure --enable-optimizer-dbg + make + make testprogs +2. Run filtertest to compile BPF expression and produce the CFG as a + DOT graph, save to output a.txt + testprogs/filtertest -g EN10MB host 192.168.1.1 > a.txt +3. Send a.txt to this program's standard input + cat a.txt | testprogs/visopts.py + (Graphviz must be installed) +4. Step 2&3 can be merged: + testprogs/filtertest -g EN10MB host 192.168.1.1 | testprogs/visopts.py +5. The standard output is something like this: + generated files under directory: /tmp/visopts-W9ekBw + the directory will be removed when this programs finished. + open this link: http://localhost:39062/expr1.html +6. Open the URL at the 3rd line in a browser. + +Note: +1. The CFG is translated to SVG images, expr1.html embeds them as external + documents. If you open expr1.html as local file using file:// protocol, some + browsers will deny such requests so the web page will not work properly. + For Chrome, you can run it using the following command to avoid this: + chromium --disable-web-security + That's why this program starts a localhost HTTP server. +2. expr1.html uses jQuery from https://ajax.googleapis.com, so it needs Internet + access to work. +""" + +import sys, os +import string +import subprocess +import json + +html_template = string.Template(""" + + + BPF compiler optimization phases for $expr + + + + + + + +
+

$expr

+
+ +          + +
+
+
+
+
+
+
+
+
+ + +""") + +def write_html(expr, gcount, logs): + logs = map(lambda s: s.strip().replace("\n", "
"), logs) + + global html_template + html = html_template.safe_substitute(expr=expr.encode("string-escape"), gcount=gcount, logs=json.dumps(logs).encode("string-escape")) + with file("expr1.html", "wt") as f: + f.write(html) + +def render_on_html(infile): + expr = None + gid = 1 + log = "" + dot = "" + indot = 0 + logs = [] + + for line in infile: + if line.startswith("machine codes for filter:"): + expr = line[len("machine codes for filter:"):].strip() + break + elif line.startswith("digraph BPF {"): + indot = 1 + dot = line + elif indot: + dot += line + if line.startswith("}"): + indot = 2 + else: + log += line + + if indot == 2: + try: + p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + except OSError as ose: + print "Failed to run 'dot':", ose + print "(Is Graphviz installed?)" + exit(1) + + svg = p.communicate(dot)[0] + with file("expr1_g%03d.svg" % (gid), "wt") as f: + f.write(svg) + + logs.append(log) + gid += 1 + log = "" + dot = "" + indot = 0 + + if indot != 0: + #unterminated dot graph for expression + return False + if expr is None: + # BPF parser encounter error(s) + return False + write_html(expr, gid - 1, logs) + return True + +def run_httpd(): + import SimpleHTTPServer + import SocketServer + + class MySocketServer(SocketServer.TCPServer): + allow_reuse_address = True + Handler = SimpleHTTPServer.SimpleHTTPRequestHandler + httpd = MySocketServer(("localhost", 0), Handler) + print "open this link: http://localhost:%d/expr1.html" % (httpd.server_address[1]) + try: + httpd.serve_forever() + except KeyboardInterrupt as e: + pass + +def main(): + import tempfile + import atexit + import shutil + os.chdir(tempfile.mkdtemp(prefix="visopts-")) + atexit.register(shutil.rmtree, os.getcwd()) + print "generated files under directory: %s" % os.getcwd() + print " the directory will be removed when this program has finished." + + if not render_on_html(sys.stdin): + return 1 + run_httpd() + return 0 + +if __name__ == "__main__": + if '-h' in sys.argv or '--help' in sys.argv: + print __doc__ + exit(0) + exit(main()) diff --git a/src/libpcap-1.10.5/testprogs/writecaptest.c b/src/libpcap-1.10.5/testprogs/writecaptest.c new file mode 100644 index 0000000000..4db532c6e6 --- /dev/null +++ b/src/libpcap-1.10.5/testprogs/writecaptest.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "varattrs.h" + +#ifndef lint +static const char copyright[] _U_ = + "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\ +The Regents of the University of California. All rights reserved.\n"; +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 + #include "getopt.h" +#else + #include +#endif +#include +#ifndef _WIN32 + #include +#endif +#include + +#include + +#include "pcap/funcattrs.h" + +#ifdef _WIN32 + #include "portability.h" +#endif + +static char *program_name; + +/* Forwards */ +static void PCAP_NORETURN usage(void); +static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2); +static char *copy_argv(char **); + +static pcap_t *pd; + +#ifdef _WIN32 +static BOOL WINAPI +stop_capture(DWORD ctrltype _U_) +{ + pcap_breakloop(pd); + return TRUE; +} +#else +static void +stop_capture(int signum _U_) +{ + pcap_breakloop(pd); +} +#endif + +static long +parse_interface_number(const char *device) +{ + const char *p; + long devnum; + char *end; + + /* + * Search for a colon, terminating any scheme at the beginning + * of the device. + */ + p = strchr(device, ':'); + if (p != NULL) { + /* + * We found it. Is it followed by "//"? + */ + p++; /* skip the : */ + if (strncmp(p, "//", 2) == 0) { + /* + * Yes. Search for the next /, at the end of the + * authority part of the URL. + */ + p += 2; /* skip the // */ + p = strchr(p, '/'); + if (p != NULL) { + /* + * OK, past the / is the path. + */ + device = p + 1; + } + } + } + devnum = strtol(device, &end, 10); + if (device != end && *end == '\0') { + /* + * It's all-numeric, but is it a valid number? + */ + if (devnum <= 0) { + /* + * No, it's not an ordinal. + */ + error("Invalid adapter index"); + } + return (devnum); + } else { + /* + * It's not all-numeric; return -1, so our caller + * knows that. + */ + return (-1); + } +} + +static char * +find_interface_by_number(long devnum) +{ + pcap_if_t *dev, *devlist; + long i; + char ebuf[PCAP_ERRBUF_SIZE]; + char *device; + int status; + + status = pcap_findalldevs(&devlist, ebuf); + if (status < 0) + error("%s", ebuf); + /* + * Look for the devnum-th entry in the list of devices (1-based). + */ + for (i = 0, dev = devlist; i < devnum-1 && dev != NULL; + i++, dev = dev->next) + ; + if (dev == NULL) + error("Invalid adapter index"); + device = strdup(dev->name); + pcap_freealldevs(devlist); + return (device); +} + +static pcap_t * +open_interface(const char *device, int snaplen_set, int snaplen, char *ebuf) +{ + pcap_t *pc; + int status; + char *cp; + + pc = pcap_create(device, ebuf); + if (pc == NULL) { + /* + * If this failed with "No such device", that means + * the interface doesn't exist; return NULL, so that + * the caller can see whether the device name is + * actually an interface index. + */ + if (strstr(ebuf, "No such device") != NULL) + return (NULL); + error("%s", ebuf); + } + if (snaplen_set) { + status = pcap_set_snaplen(pc, snaplen); + if (status != 0) + error("%s: pcap_set_snaplen failed: %s", + device, pcap_statustostr(status)); + } + status = pcap_set_timeout(pc, 100); + if (status != 0) + error("%s: pcap_set_timeout failed: %s", + device, pcap_statustostr(status)); + status = pcap_activate(pc); + if (status < 0) { + /* + * pcap_activate() failed. + */ + cp = pcap_geterr(pc); + if (status == PCAP_ERROR) + error("%s", cp); + else if (status == PCAP_ERROR_NO_SUCH_DEVICE) { + /* + * Return an error for our caller to handle. + */ + snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)", + device, pcap_statustostr(status), cp); + } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0') + error("%s: %s\n(%s)", device, + pcap_statustostr(status), cp); + else + error("%s: %s", device, + pcap_statustostr(status)); + pcap_close(pc); + return (NULL); + } else if (status > 0) { + /* + * pcap_activate() succeeded, but it's warning us + * of a problem it had. + */ + cp = pcap_geterr(pc); + if (status == PCAP_WARNING) + warning("%s", cp); + else if (status == PCAP_WARNING_PROMISC_NOTSUP && + *cp != '\0') + warning("%s: %s\n(%s)", device, + pcap_statustostr(status), cp); + else + warning("%s: %s", device, + pcap_statustostr(status)); + } + return (pc); +} + +#define COMMAND_OPTIONS "DLi:s:w:y:" + +int +main(int argc, char **argv) +{ + int op; + char *cp, *cmdbuf = NULL, *device, *end, *savefile = NULL; + int snaplen = 0; + int snaplen_set = 0; + pcap_if_t *devlist; + long devnum; + int show_interfaces = 0; + int show_dlt_types = 0; + int ndlts; + int *dlts; + bpf_u_int32 localnet, netmask; + struct bpf_program fcode; + char ebuf[PCAP_ERRBUF_SIZE]; +#ifndef _WIN32 + struct sigaction action; +#endif + int dlt; + const char *dlt_name = NULL; + int status; + pcap_dumper_t *pdd; + + device = NULL; + if ((cp = strrchr(argv[0], '/')) != NULL) + program_name = cp + 1; + else + program_name = argv[0]; + + opterr = 0; + while ((op = getopt(argc, argv, COMMAND_OPTIONS)) != -1) { + switch (op) { + + case 'D': + show_interfaces = 1; + break; + + case 'L': + show_dlt_types = 1; + break; + + case 'i': + device = optarg; + break; + + case 's': + snaplen = (int)strtol(optarg, &end, 0); + if (optarg == end || *end != '\0' || snaplen < 0) + error("invalid snaplen %s (must be >= 0)", + optarg); + snaplen_set = 1; + break; + + case 'w': + savefile = optarg; + break; + + case 'y': + dlt_name = optarg; + break; + + default: + usage(); + /* NOTREACHED */ + } + } + + if (show_interfaces) { + pcap_if_t *dev; + int i; + + if (pcap_findalldevs(&devlist, ebuf) < 0) + error("%s", ebuf); + for (i = 0, dev = devlist; dev != NULL; i++, dev = dev->next) { + printf("%d.%s", i+1, dev->name); + if (dev->description != NULL) + printf(" (%s)", dev->description); + printf("\n"); + } + pcap_freealldevs(devlist); + return (0); + } + + if (device == NULL) { + if (pcap_findalldevs(&devlist, ebuf) == -1) + error("%s", ebuf); + if (devlist == NULL) + error("no interfaces available for capture"); + device = strdup(devlist->name); + pcap_freealldevs(devlist); + } + if (show_dlt_types) { + pd = pcap_create(device, ebuf); + if (pd == NULL) + error("%s", ebuf); + status = pcap_activate(pd); + if (status < 0) { + /* + * pcap_activate() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + ndlts = pcap_list_datalinks(pd, &dlts); + if (ndlts < 0) { + /* + * pcap_list_datalinks() failed. + */ + error("%s: %s\n(%s)", device, + pcap_statustostr(status), pcap_geterr(pd)); + } + for (int i = 0; i < ndlts; i++) { + dlt_name = pcap_datalink_val_to_name(dlts[i]); + if (dlt_name == NULL) + printf("DLT %d", dlts[i]); + else + printf("%s", dlt_name); + printf("\n"); + } + pcap_free_datalinks(dlts); + pcap_close(pd); + return 0; + } + + if (savefile == NULL) + error("no savefile specified"); + + *ebuf = '\0'; + + pd = open_interface(device, snaplen_set, snaplen, ebuf); + if (pd == NULL) { + /* + * That failed because the interface couldn't be found. + * + * If we can get a list of interfaces, and the interface name + * is purely numeric, try to use it as a 1-based index + * in the list of interfaces. + */ + devnum = parse_interface_number(device); + if (devnum == -1) { + /* + * It's not a number; just report + * the open error and fail. + */ + error("%s", ebuf); + } + + /* + * OK, it's a number; try to find the + * interface with that index, and try + * to open it. + * + * find_interface_by_number() exits if it + * couldn't be found. + */ + device = find_interface_by_number(devnum); + pd = open_interface(device, snaplen_set, snaplen, ebuf); + if (pd == NULL) + error("%s", ebuf); + } + + if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) { + localnet = 0; + netmask = 0; + warning("%s", ebuf); + } + + if (dlt_name != NULL) { + dlt = pcap_datalink_name_to_val(dlt_name); + if (dlt == PCAP_ERROR) + error("%s isn't a valid DLT name", dlt_name); + if (pcap_set_datalink(pd, dlt) == PCAP_ERROR) + error("%s: %s", device, pcap_geterr(pd)); + } + + /* + * Don't set a filter unless we were given one on the + * command line; if capturing doesn't work, or doesn't + * use the snapshot length, without a filter, that's + * a bug. + */ + if (optind < argc) { + cmdbuf = copy_argv(&argv[optind]); + + if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0) + error("%s", pcap_geterr(pd)); + + if (pcap_setfilter(pd, &fcode) < 0) + error("%s", pcap_geterr(pd)); + } + + pdd = pcap_dump_open(pd, savefile); + if (pdd == NULL) + error("%s", pcap_geterr(pd)); + +#ifdef _WIN32 + SetConsoleCtrlHandler(stop_capture, TRUE); +#else + action.sa_handler = stop_capture; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + if (sigaction(SIGINT, &action, NULL) == -1) + error("Can't catch SIGINT: %s\n", strerror(errno)); +#endif + + printf("Listening on %s, link-type ", device); + dlt = pcap_datalink(pd); + dlt_name = pcap_datalink_val_to_name(dlt); + if (dlt_name == NULL) + printf("DLT %d", dlt); + else + printf("%s", dlt_name); + printf("\n"); + for (;;) { + status = pcap_dispatch(pd, -1, pcap_dump, (u_char *)pdd); + if (status < 0) + break; + if (status != 0) { + printf("%d packets seen\n", status); + struct pcap_stat ps; + pcap_stats(pd, &ps); + printf("%d ps_recv, %d ps_drop, %d ps_ifdrop\n", + ps.ps_recv, ps.ps_drop, ps.ps_ifdrop); + } + } + if (status == -2) { + /* + * We got interrupted, so perhaps we didn't + * manage to finish a line we were printing. + * Print an extra newline, just in case. + */ + putchar('\n'); + printf("Broken out of loop from SIGINT handler\n"); + } + (void)fflush(stdout); + if (status == -1) { + /* + * Error. Report it. + */ + (void)fprintf(stderr, "%s: pcap_dispatch: %s\n", + program_name, pcap_geterr(pd)); + } + pcap_close(pd); + if (cmdbuf != NULL) { + pcap_freecode(&fcode); + free(cmdbuf); + } + exit(status == -1 ? 1 : 0); +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s -D -L [ -i interface ] [ -s snaplen ] [ -w file ] [ -y dlt ] [expression]\n", + program_name); + exit(1); +} + +/* VARARGS */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } + exit(1); + /* NOTREACHED */ +} + +/* VARARGS */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + (void)fprintf(stderr, "%s: WARNING: ", program_name); + va_start(ap, fmt); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + if (*fmt) { + fmt += strlen(fmt); + if (fmt[-1] != '\n') + (void)fputc('\n', stderr); + } +} + +/* + * Copy arg vector into a new buffer, concatenating arguments with spaces. + */ +static char * +copy_argv(register char **argv) +{ + register char **p; + register size_t len = 0; + char *buf; + char *src, *dst; + + p = argv; + if (*p == 0) + return 0; + + while (*p) + len += strlen(*p++) + 1; + + buf = (char *)malloc(len); + if (buf == NULL) + error("copy_argv: malloc"); + + p = argv; + dst = buf; + while ((src = *p++) != NULL) { + while ((*dst++ = *src++) != '\0') + ; + dst[-1] = ' '; + } + dst[-1] = '\0'; + + return buf; +} diff --git a/src/libpcap-1.10.5/tests/pcap-invalid-version-1.pcap b/src/libpcap-1.10.5/tests/pcap-invalid-version-1.pcap new file mode 100644 index 0000000000..9dd0429d22 Binary files /dev/null and b/src/libpcap-1.10.5/tests/pcap-invalid-version-1.pcap differ diff --git a/src/libpcap-1.10.5/tests/pcap-invalid-version-2.pcap b/src/libpcap-1.10.5/tests/pcap-invalid-version-2.pcap new file mode 100644 index 0000000000..4217d1e7a9 Binary files /dev/null and b/src/libpcap-1.10.5/tests/pcap-invalid-version-2.pcap differ diff --git a/src/libpcap-1.10.5/tests/pcapng-invalid-vers-1.pcapng b/src/libpcap-1.10.5/tests/pcapng-invalid-vers-1.pcapng new file mode 100644 index 0000000000..7bbb7ab0cd Binary files /dev/null and b/src/libpcap-1.10.5/tests/pcapng-invalid-vers-1.pcapng differ diff --git a/src/libpcap-1.10.5/tests/pcapng-invalid-vers-2.pcapng b/src/libpcap-1.10.5/tests/pcapng-invalid-vers-2.pcapng new file mode 100644 index 0000000000..77595f4bda Binary files /dev/null and b/src/libpcap-1.10.5/tests/pcapng-invalid-vers-2.pcapng differ diff --git a/src/libpcap-1.10.5/tests/shb-option-too-long.pcapng b/src/libpcap-1.10.5/tests/shb-option-too-long.pcapng new file mode 100644 index 0000000000..f77397476f Binary files /dev/null and b/src/libpcap-1.10.5/tests/shb-option-too-long.pcapng differ diff --git a/src/libpcap-1.10.5/thread-local.h b/src/libpcap-1.10.5/thread-local.h new file mode 100644 index 0000000000..c9cbda2cbf --- /dev/null +++ b/src/libpcap-1.10.5/thread-local.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1994, 1995, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef thread_local_h +#define thread_local_h + +/* + * This defines thread_local to specify thread-local storage, if it + * is not already defined. + * + * C11, if __STDC_NO_THREADS__ is not defined to be 1, defines + * _Thread_local to indicate thread-local storage. (You can also + * include to so define it, but we don't use any of + * the other stuff there.) + * + * Otherwise, we define it ourselves, based on the compiler. + * + * This is taken from https://stackoverflow.com/a/18298965/16139739. + */ +#ifndef thread_local + #if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__ + #define thread_local _Thread_local + #elif defined __TINYC__ + #define thread_local + #warning "Some libpcap calls will not be thread-safe." + #elif defined _WIN32 && ( \ + defined _MSC_VER || \ + defined __ICL || \ + defined __DMC__ || \ + defined __BORLANDC__ ) + #define thread_local __declspec(thread) + /* note that ICC (linux) and Clang are covered by __GNUC__ */ + #elif defined __GNUC__ || \ + defined __SUNPRO_C || \ + defined __xlC__ + #define thread_local __thread + #else + #error "Cannot define thread_local" + #endif +#endif + +#endif diff --git a/src/libpcap-1.10.5/varattrs.h b/src/libpcap-1.10.5/varattrs.h new file mode 100644 index 0000000000..05bfe8cd4a --- /dev/null +++ b/src/libpcap-1.10.5/varattrs.h @@ -0,0 +1,59 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef varattrs_h +#define varattrs_h + +#include + +/* + * Attributes to apply to variables, using various compiler-specific + * extensions. + */ + +#if __has_attribute(unused) \ + || PCAP_IS_AT_LEAST_GNUC_VERSION(2,0) + /* + * Compiler with support for __attribute__((unused)), or GCC 2.0 and + * later, so it supports __attribute__((unused)). + */ + #define _U_ __attribute__((unused)) +#else + /* + * We don't know of any way to mark a variable as unused. + */ + #define _U_ +#endif + +#endif