diff options
Diffstat (limited to 'doc/README.capture-module')
-rw-r--r-- | doc/README.capture-module | 354 |
1 files changed, 1 insertions, 353 deletions
diff --git a/doc/README.capture-module b/doc/README.capture-module index e13eaf31..b2bf2c09 100644 --- a/doc/README.capture-module +++ b/doc/README.capture-module @@ -1,353 +1 @@ - How to write a libpcap module - -WARNING: this document describes an unstable interface; future releases -of libpcap may, and some probably will, change the interface in an -incompatible fashion. If you submit your module to the libpcap -developers for inclusion in libpcap, not only does that make it more -likely that it will be available in the libpcap provided by operating -system vendors (such as Linux distributions), but it also means that we -will attempt to update it to handle future changes to this interface. -If we add new capabilities, we may have to ask you how to provide those -additional capabilities if you're using an underlying mechanism for -which we have neither the source code nor the documentation. - -NOTE: this document assumes familiarity with the entire libpcap API. - -TODO: more routines, more stuff that the activate routine has to do -(such as setting the list of DLT_s), convert to Markdown? - -On Linux, *BSD, macOS, Solaris, AIX, HP-UX, IRIX, and Tru64 UNIX, -Libpcap supports capturing on network interfaces as supported by the -operating system networking stack, using the native packet capture -mechanism provided by the OS. On Windows, it supports it with the help -of the driver and library supplied by WinPcap and Npcap. - -In addition, it also supports capturing on other types of devices, such -as: - - specialized capture cards, such as Endace DAG cards; - - network adapters that provide special high-performance code - paths, such as CSPI Myricom adapters; - - buses such as USB; - - software communication channels such as D-Bus and Linux netlink; - - etc.. - -Support for those devices is provided by modules compiled into libpcap. - -If you want to add such a module, you would first have to check the list -of link-layer header types supported by libpcap, to see if one of those -would be sufficient for your device. The current version of the list -can be found at - - https://www.tcpdump.org/linktypes.html - -If none of those would work for your device, please read -doc/DLT_ALLOCATE_HOWTO.md and the introductory paragraphs on the Web -page mentioned above, and then send a request for the new link-layer -header type to tcpdump-workers@lists.tcpdump.org. - -Once you have a link-layer header type value or values that you can use, -you can add new module. - -The module should be a C source file, with a name of the form -pcap-{MOD}.c, where {MOD} is a name appropriate for your device; for -example, the support for DAG cards is in pcap-dag.c, and the support for -capturing USB traffic on Linux is pcap-usb-linux.c. - -Your module is assumed to support one or more named devices. The names -should be relatively short names, containing only lower-case -alphanumeric characters, consisting of a prefix that ends with an -alphabetic character and, if there can be more than one device instance, -possibly followed by a numerical device ID, such as "mydevice" or -"mydevice0"/"mydevice1"/.... If you have more than one type of device -that you can support, you can have more than one prefix, each of which -can be followed by a numerical device ID. - -The two exported functions that your module must provide are routines to -provide a list of device instances and a program to initialize a -created-but-not-activated pcap_t for an instance of one of your devices. - -The "list of device instances" routine takes, as arguments: - - a pointer to a pcap_if_list_t; - - a pointer to an error message buffer. - -The error message buffer may be assumed to be PCAP_ERRBUF_SIZE bytes -large, but must not be assumed to be larger. By convention, the routine -typically has a name containing "findalldevs". - -The routine should attempt to determine what device instances are -available and add them to the list pointed to by the first argument; -this may be impossible for some modules, but, for those modules, it may -be difficult to capture on the devices using Wirehshark (although it -should be possible to capture on them using tcpdump, TShark, or other -programs that take a device name on the command line), so we recommend -that your routine provide the list of devices if possible. If it -cannot, it should just immediately return 0. - -The routine should add devices to the list by calling the add_dev() -routine in libpcap, declared in the pcap-int.h header. It takes, as -arguments: - - the pointer to the pcap_if_list_t passed as an argument to the - routine; - - the device name, as described above; - - a 32-bit word of flags, as provided by pcap_findalldevs(); - - a text description of the device, or NULL if there is no - description; - - the error message buffer pointer provided to the routine. - -add_dev() will, if it succeeds, return a pointer to a pcap_if_t that was -added to the list of devices. If it fails, it will return NULL; in this -case, the error message buffer has been filled in with an error string, -and your routine must return -1 to indicate the error. - -If your routine succeeds, it must return 0. If it fails, it must fill -in the error message buffer with an error string and return -1. - -The "initialize the pcap_t" routine takes, as arguments: - - a pointer to a device name; - - a pointer to an error message buffer; - - a pointer to an int. - -It returns a pointer to a pcap_t. - -Your module will probably need, for each pcap_t for an opened device, a -private data structure to maintain its own information about the opened -device. These should be allocated per opened instance, not per device; -if, for example, mydevice0 can be captured on by more than one program -at the same time, there will be more than one pcap_t opened for -mydevice0, and so there will be separate private data structures for -each pcap_t. If you need to maintain per-device, rather than per-opened -instance information, you will have to maintain that yourself. - -The routine should first check the device to see whether it looks like a -device that this module would handle; for example, it should begin with -one of the device name prefixes for your module and, if your devices -have instance numbers, be followed by a number. If it is not one of -those devices, you must set the integer pointed to by the third -argument to 0, to indicate that this is *not* one of the devices for -your module, and return NULL. - -If it *is* one of those devices, it should call pcap_create_common, -passing to it the error message buffer as the first argument and the -size of the per-opened instance data structure as the second argument. -If it fails, it will return NULL; you must return NULL in this case. - -If it succeeds, the pcap_t pointed to by the return value has been -partially initialized, but you will need to complete the process. It -has a "priv" member, which is a void * that points to the private data -structure attached to it; that structure has been initialized to zeroes. - -What you need to set are some function pointers to your routines to -handle certain operations: - - activate_op - the routine called when pcap_activate() is done on the - pcap_t - - can_set_rfmon_op - the routine called when pcap_can_set_rfmon() is done on - the pcap_t - if your device doesn't support 802.11 - monitor mode, you can leave this as initialized by - pcap_create_common(), as that routine will return "no, - monitor mode isn't supported". - -Once you've set the activate_op and, if necessary, the can_set_rfmon_op, -you must return the pcap_t * that was returned to you. - -Your activate routine takes, as an argument, a pointer to the pcap_t -being activated, and returns an int. - -The perameters set for the device in the pcap_create() call, and after -that call(), are mostly in the opt member of the pcap_t: - - device - the name of the device - - timeout - the buffering timeout, in milliseconds - - buffer_size - the buffer size to use - - promisc - 1 if promiscuous mode is to be used, 0 otherwise - - rfmon - 1 if monitor mode is to be used, 0 otherwise - - immediate - 1 if the device should be in immediate mode, 0 otherwise - - nonblock - 1 if the device should be in non-blocking mode, 0 - otherwise - - tstamp_type - the type of time stamp to supply - - tstamp_precision - the time stamp precision to supply - -The snapshot member of the pcap_t structure will contain the snapshot -length to be used. - -Your routine should attempt to set up the device for capturing. If it -fails, it must return an error indication which is one of the PCAP_ERROR -values. For PCAP_ERROR, it must also set the errbuf member of the -pcap_t to an error string. For PCAP_ERROR_NO_SUCH_DEVICE and -PCAP_ERROR_PERM_DENIED, it may set it to an error string providing -additional information that may be useful for debugging, or may just -leave it as a null string. - -If it succeeds, it must set certain function pointers in the pcap_t -structure: - - read_op - called whenever packets are to be read - - inject_op - called whenever packets are to be injected - - setfilter_op - called whenever pcap_setfilter() is called - - setdirection_op - called whenever pcap_setdirection() is called - - set_datalink_op - called whnever pcap_set_datalink() is called - - getnonblock_op - called whenever pcap_getnonblock() is called - - setnonblock_op - called whenever pcap_setnonblock() is called - - stats_op - called whenever pcap_stats() is called - - cleanup_op - called if the activate routine fails or pcap_close() is - called - -and must also set the linktype member to the DLT_ value for the device. - -On UN*Xes, if the device supports waiting for packets to arrive with -select()/poll()/epoll()/kqueues etc., it should set the selectable_fd -member of the structure to the descriptor you would use with those -calls. If it does not, then, if that's because the device polls for -packets rather than receiving interrupts or other signals when packets -arrive, it should have a struct timeval in the private data structure, -set the value of that struct timeval to the poll timeout, and set the -required_select_timeout member of the pcap_t to point to the struct -timeval. - -The read_op routine is called when pcap_dispatch(), pcap_loop(), -pcap_next(), or pcap_next_ex() is called. It is passed the same -arguments as pcap_dispatch() is called. - -The routine should first check if the break_loop member of the pcap_t is -non-zero and, if so, set that member to zero and return -PCAP_ERROR_BREAK. - -Then, if the pcap_t is in blocking mode (as opposed to non-blocking -mode), and there are no packets immediately available to be passed to -the callback, it should block waiting for packets to arrive, using the -buffering timeout, first, and read packets from the device if necessary. - -Then it should loop through the available packets, calling the callback -routine for each packet: - - If the PACKET_COUNT_IS_UNLIMITED() macro evaluates to true when - passed the packet count argument, the loop should continue until - there are no more packets immediately available or the - break_loop member of the pcap_t is non-zero. If the break_loop - member is fount to be non-zero, it should set that member to - zero and return PCAP_ERROR_BREAK. - - If it doesn't evaluat to true, then the loop should also - terminate if the specified number of packets have been delivered - to the callback. - -Note that there is *NO* requirement that the packet header or data -provided to the callback remain available, or valid, after the callback -routine returns; if the callback needs to save the data for other code -to use, it must make a copy of that data. This means that the module is -free to, for example, overwrite the buffer into which it read the -packet, or release back to the kernel a packet in a memory-mapped -buffer shared between the kernel and userland, after the callback -returns. - -If an error occurs when reading packets from the device, it must set the -errbuf member of the pcap_t to an error string and return PCAP_ERROR. - -If no error occurs, it must return the number of packets that were -supplied to the callback routine. - -The inject routine is passed a pointer to the pcap_t, a buffer -containing the contents of the packet to inject, and the number of bytes -in the packet. If the device doesn't support packet injection, the -routine must set the errbuf member of the pcap_t to a message indicating -that packet injection isn't supported and return PCAP_ERROR. Otherwise, -it should attempt to inject the packet; if the attempt fails, it must -set the errbuf member of the pcap_t to an error message and return -PCAP_ERROR. Otherwise, it should return the number of bytes injected. - -The setfilter routine is passed a pointer to the pcap_t and a pointer -to a struct bpf_program containing a BPF program to be used as a filter. -If the mechanism used by your module can perform filtering with a BPF -program, it would attempt to set that filter to the specified program. - -If that failed because the program was too large, or used BPF features -not supported by that mechanism, the module should fall back on -filtering in userland by saving a copy of the filter with a call to -install_bpf_program(), setting a flag in the private data instructure -indicating that filtering is being done by the module and, in the read -routine's main loop, checking the flag and, if it's set, calling -pcap_filter(), passing it the fcode.bf_insns member of the pcap_t, the -raw packet data, the on-the-wire length of the packet, and the captured -length of the packet, and only passing the packet to the callback -routine, and counting it, if pcap_filter() returns a non-zero value. -(If the flag is not set, all packets should be passed to the callback -routine and counted, as the filtering is being done by the mechanism -used by the module.) If install_bpf_program() returns a negative value, -the routine should return PCAP_ERROR. - -If the attempt to set the filter failed for any other reason, the -routine must set the errbuf member of the pcap_t to an error message and -return PCAP_ERROR. - -If the attempt to set the filter succeeded, or it failed because the -mechanism used by the module rejected it and the call to -install_bpf_program() succeeded, the routine should return 0. - -If the mechanism the module uses doesn't support filtering, the pointer -to the setfilter routine can just be set to point to -install_bpf_program; the module does not need a routine of its own to -handle that. - -The setdirection routine is passed a pointer to the pcap_t and a -pcap_direction_t indicating which packet directions should be accepted. -If the module can't arrange to handle only incoming packets or only -outgoing packets, it can set the pointer to the setdirection routine to -NULL, and calls to pcap_setdirection() will fail with an error message -indicating that setting the direction isn't supported. - -XXX describe set_datalink, including what the activate routine has to do -XXX - -XXX describe the rest of the routines XXX +This document has moved to https://www.tcpdump.org/libpcap-module-HOWTO.html |