This file is indexed.

/usr/include/tins/sniffer.h is in libtins-dev 1.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/*
 * Copyright (c) 2012, Matias Fontanini
 * 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 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 TINS_SNIFFER_H
#define TINS_SNIFFER_H


#include <pcap.h>
#include <string>
#include <memory>
#include <stdexcept>
#include "pdu.h"
#include "ethernetII.h"
#include "radiotap.h"
#include "packet.h"
#include "loopback.h"
#include "dot11/dot11_base.h"
#include "dot3.h"
#include "sll.h"
#include "cxxstd.h"
#include "exceptions.h"

namespace Tins {
    /**
     * \class BaseSniffer
     * \brief Base class for sniffers.
     * 
     * This class implements the basic sniffing operations. Subclasses
     * should only initialize this object using a pcap_t pointer, which
     * will be used to extract packets.
     * 
     * Initialization must be done using the BaseSniffer::init method.
     */
    class BaseSniffer {
    public:
        #if TINS_IS_CXX11
            /**
             * \brief Move constructor.
             * This constructor is available only in C++11.
             */
            BaseSniffer(BaseSniffer &&rhs) noexcept 
            {
                *this = std::move(rhs);
            }
            
            /**
             * \brief Move assignment operator.
             * This opeartor is available only in C++11.
             */
            BaseSniffer& operator=(BaseSniffer &&rhs) noexcept 
            {
                handle = 0;
                mask = rhs.mask;
                iface_type = rhs.iface_type;
                actual_filter.bf_insns = 0;
                std::swap(handle, rhs.handle);
                std::swap(actual_filter, rhs.actual_filter);
                return *this;
            }
        #endif
    
        /**
         * \brief Sniffer destructor.
         * This frees all memory used by the pcap handle.
         */
        virtual ~BaseSniffer();
        
        /**
         * \brief Compiles a filter and uses it to capture one packet.
         * 
         * This method returns the first sniffed packet that matches the 
         * sniffer's filter, or the first sniffed packet if no filter has
         * been set.
         * 
         * The return type is a thin wrapper over a PDU* and a Timestamp
         * object. This wrapper can be both implicitly converted to a 
         * PDU* and a Packet object. So doing this:
         * 
         * \code
         * Sniffer s(...);
         * std::unique_ptr<PDU> pdu(s.next_packet());
         * // Packet takes care of the PDU*. 
         * Packet packet(s.next_packet());
         * \endcode
         * 
         * Is fine, but this:
         * 
         * \code
         * // bad!!
         * PtrPacket p = s.next_packet();
         * 
         * \endcode
         * 
         * Is not, since PtrPacket can't be copy constructed. 
         * 
         * \sa Packet::release_pdu
         * 
         * \return The captured packet, matching the given filter.
         * If an error occured(probably compiling the filter), PtrPacket::pdu
         * will return 0. Caller takes ownership of the PDU * stored in
         * the PtrPacket.
         */
        PtrPacket next_packet();
        
        /**
         * \brief Starts a sniffing loop, using a callback object for every
         * sniffed packet.
         * 
         * The callback object must implement an operator with some of
         * the following(or compatible) signatures:
         * 
         * \code
         * bool operator()(PDU&);
         * bool operator()(RefPacket&);
         * \endcode
         * 
         * This operator will be called using the sniffed packets 
         * as arguments. You can modify the parameter argument as you wish. 
         * Calling PDU methods like PDU::release_inner_pdu is perfectly 
         * valid.
         * 
         * The callback taking a RefPacket will contain a timestamp
         * indicating the moment in which the packet was taken out of 
         * the wire/pcap file. 
         * 
         * Note that the Functor object will be copied using its copy
         * constructor, so that object should be some kind of proxy to
         * another object which will process the packets(e.g. std::bind).
         * 
         * \sa RefPacket
         * 
         * \param cback_handler The callback handler object which should process packets.
         * \param max_packets The maximum amount of packets to sniff. 0 == infinite.
         */
        template<class Functor>
        void sniff_loop(Functor function, uint32_t max_packets = 0);
        
        /**
         * \brief Sets a filter on this sniffer.
         * \param filter The filter to be set.
         * \return True iif it was possible to apply the filter.
         */
        bool set_filter(const std::string &filter);
        
        /**
         * \brief Stops sniffing loops.
         */
        void stop_sniff();

        /**
         * \brief Gets the file descriptor associated with the sniffer.
         */
        int get_fd();
    protected:
        /**
         * Default constructor.
         */
        BaseSniffer();
    
        /**
         * \brief Initialices this BaseSniffer.
         * 
         * \param phandle The pcap handle to be used for sniffing.
         * \param filter The pcap filter which will be applied to the
         * stream.
         * \param if_mask The interface's subnet mask. If 0 is provided,
         * then some IP broadcast tests won't work correctly.
         */
        void init(pcap_t *phandle, const std::string &filter, bpf_u_int32 if_mask);
    private:
        template<class Functor>
        struct LoopData {
            pcap_t *handle;
            Functor c_handler;
            int iface_type;
            
            LoopData(pcap_t *_handle, const Functor _handler, 
              int if_type) 
            : handle(_handle), c_handler(_handler), iface_type(if_type)
            { }
        };
        
        struct PCapLoopBreaker {
            bool &went_well;
            pcap_t *handle;
            
            PCapLoopBreaker(bool &went_well, pcap_t *handle)
            : went_well(went_well), handle(handle) { }
            
            ~PCapLoopBreaker() {
                if(!went_well)
                    pcap_breakloop(handle);
            }
        };
    
        BaseSniffer(const BaseSniffer&);
        BaseSniffer &operator=(const BaseSniffer&);
        static bool is_dot3(const uint8_t *ptr, size_t sz) {
            return (sz >= 13 && ptr[12] < 8);
        }
        
        template<class ConcretePDU, class Functor>
        static bool call_functor(LoopData<Functor> *data, const u_char *packet, const struct pcap_pkthdr *header);
        
        bool compile_set_filter(const std::string &filter, bpf_program &prog);
        
        template<class Functor>
        static void callback_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
        
        pcap_t *handle;
        bpf_u_int32 mask;
        bpf_program actual_filter;
        int iface_type;
    };
    
    /** 
     * \class Sniffer
     * \brief Sniffs packets using pcap filters.
     * 
     * This class uses a given filter to sniff packets and allow the user
     * to handle them. Each time a filter is set, it's used until a new one
     * is set. Both Sniffer::next_packet and Sniffer::sniff_loop have an
     * optional filter parameter. If a filter is set using those parameter,
     * the previously set filter is freed and the new one is used.
     */
    class Sniffer : public BaseSniffer {
    public:
        /**
         * \brief Constructs an instance of Sniffer.
         * \param device The device which will be sniffed.
         * \param max_packet_size The maximum packet size to be read.
         * \param promisc bool indicating wether to put the interface in promiscuous mode.(optional)
         * \param filter A capture filter to be used on the sniffing session.(optional);
         */
        Sniffer(const std::string &device, unsigned max_packet_size,
          bool promisc = false, const std::string &filter = "");
    };
    
    /**
     * \class FileSniffer
     * \brief Parses pcap files and interprets the packets in it.
     * 
     * This class acts exactly in the same way that Sniffer, but reads
     * packets from a pcap file instead of an interface.
     */
    class FileSniffer : public BaseSniffer {
    public:
        /**
         * \brief Constructs an instance of FileSniffer.
         * \param file_name The pcap file which will be parsed.
         * \param filter A capture filter to be used on the file.(optional);
         */
        FileSniffer(const std::string &file_name, const std::string &filter = "");
    };
        
    template<class Functor>
    void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
        LoopData<Functor> data(handle, function, iface_type);
        pcap_loop(handle, max_packets, &BaseSniffer::callback_handler<Functor>, (u_char*)&data);
    }
    
    template<class ConcretePDU, class Functor>
    bool Tins::BaseSniffer::call_functor(LoopData<Functor> *data, const u_char *packet, 
      const struct pcap_pkthdr *header) 
    {
        ConcretePDU some_pdu((const uint8_t*)packet, header->caplen);
        Timestamp ts(header->ts);
        RefPacket pck(some_pdu, ts);
        return data->c_handler(pck);
    }
    
    template<class Functor>
    void Tins::BaseSniffer::callback_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
        bool ret_val(true);
        LoopData<Functor> *data = reinterpret_cast<LoopData<Functor>*>(args);
        PCapLoopBreaker _(ret_val, data->handle);
        try {
            Internals::smart_ptr<PDU>::type pdu;
            if(data->iface_type == DLT_EN10MB) {
                ret_val = is_dot3((const uint8_t*)packet, header->caplen) ?
                        call_functor<Tins::Dot3>(data, packet, header) :
                        call_functor<Tins::EthernetII>(data, packet, header);
            }
            else if(data->iface_type == DLT_IEEE802_11_RADIO)
                ret_val = call_functor<Tins::RadioTap>(data, packet, header);
            else if(data->iface_type == DLT_IEEE802_11) {
                Internals::smart_ptr<PDU>::type pdu(
                    Tins::Dot11::from_bytes((const uint8_t*)packet, header->caplen)
                );
                if(pdu.get()) {
                    RefPacket pck(*pdu, header->ts);
                    ret_val = data->c_handler(pck);
                }
            }
            else if(data->iface_type == DLT_NULL) 
                ret_val = call_functor<Tins::Loopback>(data, packet, header);
            else if(data->iface_type == DLT_LINUX_SLL)
                ret_val = call_functor<Tins::SLL>(data, packet, header);
        }
        catch(malformed_packet&) { 
            ret_val = true;
        }
        catch(pdu_not_found&) { 
            ret_val = true;
        }
    }
    
    template<class T>
    class HandlerProxy {
    public:
        typedef T* ptr_type;
        typedef bool (T::*fun_type)(PDU&) ;
    
        HandlerProxy(ptr_type ptr, fun_type function) 
        : object(ptr), fun(function) {}
        
        bool operator()(PDU &pdu) {
            return (object->*fun)(pdu);
        }
    private:
        ptr_type object;
        fun_type fun;
    };
    
    template<class T>
    HandlerProxy<T> make_sniffer_handler(T *ptr, typename HandlerProxy<T>::fun_type function) 
    {
        return HandlerProxy<T>(ptr, function);
    }
}
    
#endif // TINS_SNIFFER_H