1 // Copyright 2013 Google, Inc. All rights reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
7 // Package ip4defrag implements a IPv4 defragmenter
18 "github.com/google/gopacket"
19 "github.com/google/gopacket/layers"
22 // Quick and Easy to use debug code to trace
24 var debug debugging = false // or flip to true
27 func (d debugging) Printf(format string, args ...interface{}) {
29 log.Printf(format, args...)
33 // Constants determining how to handle fragments.
35 IPv4MinimumFragmentSize = 576 // Minimum size of a single fragment
36 IPv4MaximumSize = 65535 // Maximum size of a fragment (2^16)
37 IPv4MaximumFragmentOffset = 8189 // Maximum offset of a fragment
38 IPv4MaximumFragmentListLen = 8 // Back out if we get more than this many fragments
41 // DefragIPv4 takes in an IPv4 packet with a fragment payload.
43 // It do not modify the IPv4 layer in place, 'in' remains untouched
44 // It returns a ready-to be used IPv4 layer.
46 // If the passed-in IPv4 layer is NOT fragmented, it will
47 // immediately return it without modifying the layer.
49 // If the IPv4 layer is a fragment and we don't have all
50 // fragments, it will return nil and store whatever internal
51 // information it needs to eventually defrag the packet.
53 // If the IPv4 layer is the last fragment needed to reconstruct
54 // the packet, a new IPv4 layer will be returned, and will be set to
55 // the entire defragmented packet,
57 // It use a map of all the running flows
61 // func HandlePacket(in *layers.IPv4) err {
62 // defragger := ip4defrag.NewIPv4Defragmenter()
63 // in, err := defragger.DefragIPv4(in)
66 // } else if in == nil {
67 // return nil // packet fragment, we don't have whole packet yet.
69 // // At this point, we know that 'in' is defragmented.
70 // //It may be the same 'in' passed to
71 // // HandlePacket, or it may not, but we don't really care :)
72 // ... do stuff to 'in' ...
75 func (d *IPv4Defragmenter) DefragIPv4(in *layers.IPv4) (*layers.IPv4, error) {
76 return d.DefragIPv4WithTimestamp(in, time.Now())
79 // DefragIPv4WithTimestamp provides functionality of DefragIPv4 with
80 // an additional timestamp parameter which is used for discarding
81 // old fragments instead of time.Now()
83 // This is useful when operating on pcap files instead of live captured data
85 func (d *IPv4Defragmenter) DefragIPv4WithTimestamp(in *layers.IPv4, t time.Time) (*layers.IPv4, error) {
86 // check if we need to defrag
87 if st := d.dontDefrag(in); st == true {
88 debug.Printf("defrag: do nothing, do not need anything")
91 // perfom security checks
92 st, err := d.securityChecks(in)
93 if err != nil || st == false {
94 debug.Printf("defrag: alert security check")
99 debug.Printf("defrag: got a new fragment in.Id=%d in.FragOffset=%d in.Flags=%d\n",
100 in.Id, in.FragOffset*8, in.Flags)
102 // have we already seen a flow between src/dst with that Id?
107 fl, exist = d.ipFlows[ipf]
109 debug.Printf("defrag: unknown flow, creating a new one\n")
110 fl = new(fragmentList)
114 // insert, and if final build it
115 out, err2 := fl.insert(in, t)
117 // at last, if we hit the maximum frag list len
118 // without any defrag success, we just drop everything and
120 if out == nil && fl.List.Len()+1 > IPv4MaximumFragmentListLen {
122 return nil, fmt.Errorf("defrag: Fragment List hits its maximum"+
123 "size(%d), without success. Flushing the list",
124 IPv4MaximumFragmentListLen)
127 // if we got a packet, it's a new one, and he is defragmented
129 // when defrag is done for a flow between two ip
137 // DiscardOlderThan forgets all packets without any activity since
138 // time t. It returns the number of FragmentList aka number of
139 // fragment packets it has discarded.
140 func (d *IPv4Defragmenter) DiscardOlderThan(t time.Time) int {
143 for k, v := range d.ipFlows {
144 if v.LastSeen.Before(t) {
153 // flush the fragment list for a particular flow
154 func (d *IPv4Defragmenter) flush(ipf ipv4) {
156 fl := new(fragmentList)
161 // dontDefrag returns true if the IPv4 packet do not need
162 // any defragmentation
163 func (d *IPv4Defragmenter) dontDefrag(ip *layers.IPv4) bool {
164 // don't defrag packet with DF flag
165 if ip.Flags&layers.IPv4DontFragment != 0 {
168 // don't defrag not fragmented ones
169 if ip.Flags&layers.IPv4MoreFragments == 0 && ip.FragOffset == 0 {
175 // securityChecks performs the needed security checks
176 func (d *IPv4Defragmenter) securityChecks(ip *layers.IPv4) (bool, error) {
177 // don't allow too big fragment offset
178 if ip.FragOffset > IPv4MaximumFragmentOffset {
179 return false, fmt.Errorf("defrag: fragment offset too big "+
180 "(handcrafted? %d > %d)", ip.FragOffset, IPv4MaximumFragmentOffset)
182 fragOffset := ip.FragOffset * 8
184 // don't allow fragment that would oversize an IP packet
185 if fragOffset+ip.Length > IPv4MaximumSize {
186 return false, fmt.Errorf("defrag: fragment will overrun "+
187 "(handcrafted? %d > %d)", ip.FragOffset*8+ip.Length, IPv4MaximumSize)
193 // fragmentList holds a container/list used to contains IP
194 // packets/fragments. It stores internal counters to track the
195 // maximum total of byte, and the current length it has received.
196 // It also stores a flag to know if he has seen the last packet.
197 type fragmentList struct {
205 // insert insert an IPv4 fragment/packet into the Fragment List
206 // It use the following strategy : we are inserting fragment based
207 // on their offset, latest first. This is sometimes called BSD-Right.
208 // See: http://www.sans.org/reading-room/whitepapers/detection/ip-fragment-reassembly-scapy-33969
209 func (f *fragmentList) insert(in *layers.IPv4, t time.Time) (*layers.IPv4, error) {
210 // TODO: should keep a copy of *in in the list
211 // or not (ie the packet source is reliable) ? -> depends on Lazy / last packet
212 fragOffset := in.FragOffset * 8
213 if fragOffset >= f.Highest {
216 for e := f.List.Front(); e != nil; e = e.Next() {
217 frag, _ := e.Value.(*layers.IPv4)
218 if in.FragOffset == frag.FragOffset {
219 // TODO: what if we receive a fragment
220 // that begins with duplicate data but
221 // *also* has new data? For example:
228 // In this situation we completely
229 // ignore CC and the complete packet can
230 // never be reassembled.
231 debug.Printf("defrag: ignoring frag %d as we already have it (duplicate?)\n",
235 if in.FragOffset < frag.FragOffset {
236 debug.Printf("defrag: inserting frag %d before existing frag %d\n",
237 fragOffset, frag.FragOffset*8)
238 f.List.InsertBefore(in, e)
246 fragLength := in.Length - 20
247 // After inserting the Fragment, we update the counters
248 if f.Highest < fragOffset+fragLength {
249 f.Highest = fragOffset + fragLength
251 f.Current = f.Current + fragLength
253 debug.Printf("defrag: insert ListLen: %d Highest:%d Current:%d\n",
255 f.Highest, f.Current)
258 if in.Flags&layers.IPv4MoreFragments == 0 {
259 f.FinalReceived = true
261 // Ready to try defrag ?
262 if f.FinalReceived && f.Highest == f.Current {
268 // Build builds the final datagram, modifying ip in place.
269 // It puts priority to packet in the early position of the list.
270 // See Insert for more details.
271 func (f *fragmentList) build(in *layers.IPv4) (*layers.IPv4, error) {
273 var currentOffset uint16
275 debug.Printf("defrag: building the datagram \n")
276 for e := f.List.Front(); e != nil; e = e.Next() {
277 frag, _ := e.Value.(*layers.IPv4)
278 if frag.FragOffset*8 == currentOffset {
279 debug.Printf("defrag: building - adding %d\n", frag.FragOffset*8)
280 final = append(final, frag.Payload...)
281 currentOffset = currentOffset + frag.Length - 20
282 } else if frag.FragOffset*8 < currentOffset {
283 // overlapping fragment - let's take only what we need
284 startAt := currentOffset - frag.FragOffset*8
285 debug.Printf("defrag: building - overlapping, starting at %d\n",
287 if startAt > frag.Length-20 {
288 return nil, errors.New("defrag: building - invalid fragment")
290 final = append(final, frag.Payload[startAt:]...)
291 currentOffset = currentOffset + frag.FragOffset*8
293 // Houston - we have an hole !
294 debug.Printf("defrag: hole found while building, " +
295 "stopping the defrag process\n")
296 return nil, errors.New("defrag: building - hole found")
298 debug.Printf("defrag: building - next is %d\n", currentOffset)
301 // TODO recompute IP Checksum
311 Protocol: in.Protocol,
323 // ipv4 is a struct to be used as a key.
329 // newIPv4 returns a new initialized IPv4 Flow
330 func newIPv4(ip *layers.IPv4) ipv4 {
332 ip4: ip.NetworkFlow(),
337 // IPv4Defragmenter is a struct which embedded a map of
338 // all fragment/packet.
339 type IPv4Defragmenter struct {
341 ipFlows map[ipv4]*fragmentList
344 // NewIPv4Defragmenter returns a new IPv4Defragmenter
345 // with an initialized map.
346 func NewIPv4Defragmenter() *IPv4Defragmenter {
347 return &IPv4Defragmenter{
348 ipFlows: make(map[ipv4]*fragmentList),