aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/ip4defrag/defrag.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/ip4defrag/defrag.go')
-rw-r--r--vendor/github.com/google/gopacket/ip4defrag/defrag.go350
1 files changed, 0 insertions, 350 deletions
diff --git a/vendor/github.com/google/gopacket/ip4defrag/defrag.go b/vendor/github.com/google/gopacket/ip4defrag/defrag.go
deleted file mode 100644
index 9d3862f..0000000
--- a/vendor/github.com/google/gopacket/ip4defrag/defrag.go
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2013 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 ip4defrag implements a IPv4 defragmenter
-package ip4defrag
-
-import (
- "container/list"
- "errors"
- "fmt"
- "log"
- "sync"
- "time"
-
- "github.com/google/gopacket"
- "github.com/google/gopacket/layers"
-)
-
-// Quick and Easy to use debug code to trace
-// how defrag works.
-var debug debugging = false // or flip to true
-type debugging bool
-
-func (d debugging) Printf(format string, args ...interface{}) {
- if d {
- log.Printf(format, args...)
- }
-}
-
-// Constants determining how to handle fragments.
-const (
- IPv4MinimumFragmentSize = 576 // Minimum size of a single fragment
- IPv4MaximumSize = 65535 // Maximum size of a fragment (2^16)
- IPv4MaximumFragmentOffset = 8189 // Maximum offset of a fragment
- IPv4MaximumFragmentListLen = 8 // Back out if we get more than this many fragments
-)
-
-// DefragIPv4 takes in an IPv4 packet with a fragment payload.
-//
-// It do not modify the IPv4 layer in place, 'in' remains untouched
-// It returns a ready-to be used IPv4 layer.
-//
-// If the passed-in IPv4 layer is NOT fragmented, it will
-// immediately return it without modifying the layer.
-//
-// If the IPv4 layer is a fragment and we don't have all
-// fragments, it will return nil and store whatever internal
-// information it needs to eventually defrag the packet.
-//
-// If the IPv4 layer is the last fragment needed to reconstruct
-// the packet, a new IPv4 layer will be returned, and will be set to
-// the entire defragmented packet,
-//
-// It use a map of all the running flows
-//
-// Usage example:
-//
-// func HandlePacket(in *layers.IPv4) err {
-// defragger := ip4defrag.NewIPv4Defragmenter()
-// in, err := defragger.DefragIPv4(in)
-// if err != nil {
-// return err
-// } else if in == nil {
-// return nil // packet fragment, we don't have whole packet yet.
-// }
-// // At this point, we know that 'in' is defragmented.
-// //It may be the same 'in' passed to
-// // HandlePacket, or it may not, but we don't really care :)
-// ... do stuff to 'in' ...
-//}
-//
-func (d *IPv4Defragmenter) DefragIPv4(in *layers.IPv4) (*layers.IPv4, error) {
- return d.DefragIPv4WithTimestamp(in, time.Now())
-}
-
-// DefragIPv4WithTimestamp provides functionality of DefragIPv4 with
-// an additional timestamp parameter which is used for discarding
-// old fragments instead of time.Now()
-//
-// This is useful when operating on pcap files instead of live captured data
-//
-func (d *IPv4Defragmenter) DefragIPv4WithTimestamp(in *layers.IPv4, t time.Time) (*layers.IPv4, error) {
- // check if we need to defrag
- if st := d.dontDefrag(in); st == true {
- debug.Printf("defrag: do nothing, do not need anything")
- return in, nil
- }
- // perfom security checks
- st, err := d.securityChecks(in)
- if err != nil || st == false {
- debug.Printf("defrag: alert security check")
- return nil, err
- }
-
- // ok, got a fragment
- debug.Printf("defrag: got a new fragment in.Id=%d in.FragOffset=%d in.Flags=%d\n",
- in.Id, in.FragOffset*8, in.Flags)
-
- // have we already seen a flow between src/dst with that Id?
- ipf := newIPv4(in)
- var fl *fragmentList
- var exist bool
- d.Lock()
- fl, exist = d.ipFlows[ipf]
- if !exist {
- debug.Printf("defrag: unknown flow, creating a new one\n")
- fl = new(fragmentList)
- d.ipFlows[ipf] = fl
- }
- d.Unlock()
- // insert, and if final build it
- out, err2 := fl.insert(in, t)
-
- // at last, if we hit the maximum frag list len
- // without any defrag success, we just drop everything and
- // raise an error
- if out == nil && fl.List.Len()+1 > IPv4MaximumFragmentListLen {
- d.flush(ipf)
- return nil, fmt.Errorf("defrag: Fragment List hits its maximum"+
- "size(%d), without success. Flushing the list",
- IPv4MaximumFragmentListLen)
- }
-
- // if we got a packet, it's a new one, and he is defragmented
- if out != nil {
- // when defrag is done for a flow between two ip
- // clean the list
- d.flush(ipf)
- return out, nil
- }
- return nil, err2
-}
-
-// DiscardOlderThan forgets all packets without any activity since
-// time t. It returns the number of FragmentList aka number of
-// fragment packets it has discarded.
-func (d *IPv4Defragmenter) DiscardOlderThan(t time.Time) int {
- var nb int
- d.Lock()
- for k, v := range d.ipFlows {
- if v.LastSeen.Before(t) {
- nb = nb + 1
- delete(d.ipFlows, k)
- }
- }
- d.Unlock()
- return nb
-}
-
-// flush the fragment list for a particular flow
-func (d *IPv4Defragmenter) flush(ipf ipv4) {
- d.Lock()
- fl := new(fragmentList)
- d.ipFlows[ipf] = fl
- d.Unlock()
-}
-
-// dontDefrag returns true if the IPv4 packet do not need
-// any defragmentation
-func (d *IPv4Defragmenter) dontDefrag(ip *layers.IPv4) bool {
- // don't defrag packet with DF flag
- if ip.Flags&layers.IPv4DontFragment != 0 {
- return true
- }
- // don't defrag not fragmented ones
- if ip.Flags&layers.IPv4MoreFragments == 0 && ip.FragOffset == 0 {
- return true
- }
- return false
-}
-
-// securityChecks performs the needed security checks
-func (d *IPv4Defragmenter) securityChecks(ip *layers.IPv4) (bool, error) {
- // don't allow too big fragment offset
- if ip.FragOffset > IPv4MaximumFragmentOffset {
- return false, fmt.Errorf("defrag: fragment offset too big "+
- "(handcrafted? %d > %d)", ip.FragOffset, IPv4MaximumFragmentOffset)
- }
- fragOffset := ip.FragOffset * 8
-
- // don't allow fragment that would oversize an IP packet
- if fragOffset+ip.Length > IPv4MaximumSize {
- return false, fmt.Errorf("defrag: fragment will overrun "+
- "(handcrafted? %d > %d)", ip.FragOffset*8+ip.Length, IPv4MaximumSize)
- }
-
- return true, nil
-}
-
-// fragmentList holds a container/list used to contains IP
-// packets/fragments. It stores internal counters to track the
-// maximum total of byte, and the current length it has received.
-// It also stores a flag to know if he has seen the last packet.
-type fragmentList struct {
- List list.List
- Highest uint16
- Current uint16
- FinalReceived bool
- LastSeen time.Time
-}
-
-// insert insert an IPv4 fragment/packet into the Fragment List
-// It use the following strategy : we are inserting fragment based
-// on their offset, latest first. This is sometimes called BSD-Right.
-// See: http://www.sans.org/reading-room/whitepapers/detection/ip-fragment-reassembly-scapy-33969
-func (f *fragmentList) insert(in *layers.IPv4, t time.Time) (*layers.IPv4, error) {
- // TODO: should keep a copy of *in in the list
- // or not (ie the packet source is reliable) ? -> depends on Lazy / last packet
- fragOffset := in.FragOffset * 8
- if fragOffset >= f.Highest {
- f.List.PushBack(in)
- } else {
- for e := f.List.Front(); e != nil; e = e.Next() {
- frag, _ := e.Value.(*layers.IPv4)
- if in.FragOffset == frag.FragOffset {
- // TODO: what if we receive a fragment
- // that begins with duplicate data but
- // *also* has new data? For example:
- //
- // AAAA
- // BB
- // BBCC
- // DDDD
- //
- // In this situation we completely
- // ignore CC and the complete packet can
- // never be reassembled.
- debug.Printf("defrag: ignoring frag %d as we already have it (duplicate?)\n",
- fragOffset)
- return nil, nil
- }
- if in.FragOffset < frag.FragOffset {
- debug.Printf("defrag: inserting frag %d before existing frag %d\n",
- fragOffset, frag.FragOffset*8)
- f.List.InsertBefore(in, e)
- break
- }
- }
- }
-
- f.LastSeen = t
-
- fragLength := in.Length - 20
- // After inserting the Fragment, we update the counters
- if f.Highest < fragOffset+fragLength {
- f.Highest = fragOffset + fragLength
- }
- f.Current = f.Current + fragLength
-
- debug.Printf("defrag: insert ListLen: %d Highest:%d Current:%d\n",
- f.List.Len(),
- f.Highest, f.Current)
-
- // Final Fragment ?
- if in.Flags&layers.IPv4MoreFragments == 0 {
- f.FinalReceived = true
- }
- // Ready to try defrag ?
- if f.FinalReceived && f.Highest == f.Current {
- return f.build(in)
- }
- return nil, nil
-}
-
-// Build builds the final datagram, modifying ip in place.
-// It puts priority to packet in the early position of the list.
-// See Insert for more details.
-func (f *fragmentList) build(in *layers.IPv4) (*layers.IPv4, error) {
- var final []byte
- var currentOffset uint16
-
- debug.Printf("defrag: building the datagram \n")
- for e := f.List.Front(); e != nil; e = e.Next() {
- frag, _ := e.Value.(*layers.IPv4)
- if frag.FragOffset*8 == currentOffset {
- debug.Printf("defrag: building - adding %d\n", frag.FragOffset*8)
- final = append(final, frag.Payload...)
- currentOffset = currentOffset + frag.Length - 20
- } else if frag.FragOffset*8 < currentOffset {
- // overlapping fragment - let's take only what we need
- startAt := currentOffset - frag.FragOffset*8
- debug.Printf("defrag: building - overlapping, starting at %d\n",
- startAt)
- if startAt > frag.Length-20 {
- return nil, errors.New("defrag: building - invalid fragment")
- }
- final = append(final, frag.Payload[startAt:]...)
- currentOffset = currentOffset + frag.FragOffset*8
- } else {
- // Houston - we have an hole !
- debug.Printf("defrag: hole found while building, " +
- "stopping the defrag process\n")
- return nil, errors.New("defrag: building - hole found")
- }
- debug.Printf("defrag: building - next is %d\n", currentOffset)
- }
-
- // TODO recompute IP Checksum
- out := &layers.IPv4{
- Version: in.Version,
- IHL: in.IHL,
- TOS: in.TOS,
- Length: f.Highest,
- Id: 0,
- Flags: 0,
- FragOffset: 0,
- TTL: in.TTL,
- Protocol: in.Protocol,
- Checksum: 0,
- SrcIP: in.SrcIP,
- DstIP: in.DstIP,
- Options: in.Options,
- Padding: in.Padding,
- }
- out.Payload = final
-
- return out, nil
-}
-
-// ipv4 is a struct to be used as a key.
-type ipv4 struct {
- ip4 gopacket.Flow
- id uint16
-}
-
-// newIPv4 returns a new initialized IPv4 Flow
-func newIPv4(ip *layers.IPv4) ipv4 {
- return ipv4{
- ip4: ip.NetworkFlow(),
- id: ip.Id,
- }
-}
-
-// IPv4Defragmenter is a struct which embedded a map of
-// all fragment/packet.
-type IPv4Defragmenter struct {
- sync.RWMutex
- ipFlows map[ipv4]*fragmentList
-}
-
-// NewIPv4Defragmenter returns a new IPv4Defragmenter
-// with an initialized map.
-func NewIPv4Defragmenter() *IPv4Defragmenter {
- return &IPv4Defragmenter{
- ipFlows: make(map[ipv4]*fragmentList),
- }
-}