Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the principle of tcpdump grabbing packets in Linux

2025-04-10 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces "what is the principle of tcpdump bag grab in Linux". In daily operation, I believe that many people have doubts about the principle of tcpdump bag grab in Linux. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful for you to answer the question of "what is the principle of tcpdump bag grab in Linux?" Next, please follow the editor to study!

Tcpdump is a tool for intercepting network packets and outputting packet contents. With its powerful function and flexible interception strategy, it has become the preferred tool for network analysis and problem checking in UNIX-like systems.

1.1.1.1 how to implement

Let's take a look at the process of passing the package, as shown in the following figure. The package goes from the network card to the memory, to the kernel state, and finally to the user program. We know that tcpdump programs run in user mode, so how to capture packets from kernel mode?

This is achieved through the libpcap library. Tcpdump calls the api function of libpcap, and the libpcap enters the kernel state to the link layer to grab the packet, as shown in the following figure. The BPF in the figure is a filter that can improve performance by reducing the number of packets and bytes of packets in the application based on user settings for packet filtering. A BufferQ is a packet that is cached for an application to read. We can say that the underlying principle of tcpdump is actually the implementation principle of libpcap.

However, libpcap grabs packets in the link layer of linux system through PF_PACKET sockets (the implementation mechanism of different systems is different). When creating this method, the second parameter can be specified as SOCK_DGRAM or SOCK_RAW, which affects whether to deduct the head of the link layer.

Libpcap takes skb_clone () away at the interface of the kernel transceiver packet.

The process of how to register network protocols and hook functions in the kernel will not be expanded here and will be specifically explained later. Let's take a look at some of the implementations of libpcap and their api.

1.1.1.2 libpcap

When you enter tcpdump-version in the system, you actually output libpcap, which shows its position in tcpdump.

In fact, the earliest compilation system and filtering engine was in the tcpdump project, and later it was isolated in order to compile other package-grabbing applications. Libpcap now provides platform-independent libraries and API to perform network sniffing.

Tcpdump.c officially uses the functions in libpcap to complete the two most critical actions: getting the interface to capture the message, and capturing the message and giving the message to callback.

Libpcap supports the Berkeley packet filtering (BPF) syntax. BPF can filter traffic by comparing the values of individual data fields in layer 2, 3, and 4 protocols. The logic of using Libpcap is shown below:

If you like, you can also develop a package grabbing tool similar to tcpdump based on libpcap. It is important to note that if a packet capture device is used, incoming packets can only be received on a single interface.

1.1.1.3 Core function

Let's first take a look at some core functions in libpcap, which can be divided into the following categories according to their functions:

L router opens the handle for reading the packet

L router selects the link layer for grabbing packets

L / R / R / L / L /

L / R / R filter

L ≤ choose the direction to grab the packet (in or out)

L / R / R / L / L

L the package will be written to the file to open the handle

L / R / R / L / R / R / L / L / R / L

L router injection package

L router reported an error

L: get the library version information.

For the official introduction, see http://www.tcpdump.org/manpages/pcap.3pcap.html.

Some commonly used functions are as follows:

Pcap_lookupdev, which selects a device if the packet capture device is not specified (the-I command line option).

Pcap_open_offine opens a saved file.

Pcap_setfilter setting filter

Pcap_open_live opens the selected device.

Pcap_next receives a packet

Pcap_dump writes the package to the pcap_dump_t structure

Pcap_loopupnet returns the network address and subnet mask of the packet capture device, which must then be specified when calling pcap_compile.

Pcap_compile compiles the filter string constructed in the cmd character array into a filter program, which is stored in fcode.

Pcap_setfilter loads the compiled filter program into the packet capture device and triggers the capture of the packets selected with the filter.

Pcap_datalink returns the data link type of the packet capture device.

Wait, so how to use the libpcap library? let's take a look.

1.1.1.4 preparation for use

First install the pcap-dev package (apt-get install pcap-dev) on the system, and then create an test.c file as follows:

# include

# include

Int

Main (int argc, char * argv [])

{undefined

Char * dev, errbuf [PCAP _ ERRBUF_SIZE]

Dev = pcap_lookupdev (errbuf)

If (dev = = NULL)

{undefined

Fprintf (stderr, "Couldn't find default device:% s\ n", errbuf)

Return (2)

}

Printf ("Device:% s\ n", dev)

Return (0)

}

Then compile as follows:

Gcc test.c-lpcap-lpthread

It can be executed, looking for an interface in the system that can grab packets.

With the interface device, you can continue to create a sniffing session, using the function

Pcap_t * pcap_open_live (char * device, int snaplen, int promisc, int to_ms, char * ebuf)

Where snaplen is the number of bytes captured by pcap, and whether promisc enables promiscuous mode (if it is not promiscuous mode, it will only be grabbed to the local packet. ), whether to_ms timed out, and ebuf stores error messages.

After you create a sniffing session, you need a filter. We can extract only the data we want. The filter must be compiled before it is applied. The calling function is as follows:

Int pcap_compile (pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask)

The first parameter is the value returned by pcap_open_live, the version of the filter stored by fp, optimize indicates whether optimization is needed, and finally netmask is the subnet mask used by the filter.

Once you have the filter, you need to use the compiler to call the function:

Int pcap_setfilter (pcap_t * p, struct bpf_program * fp)

At this point, the entire code flow is referred to the following code snippet:

# include

...

Pcap_t handle; / Session handle * /

Char dev [] = "rl0"; / * Device to sniff on * /

Char errbuf [PCAP _ ERRBUF_SIZE]; / * Error string * /

Struct bpf_program fp; / * The compiled filter expression * /

Char filter_exp [] = "port 23"; / * The filter expression * /

Bpf_u_int32 mask; / * The netmask of our sniffing device * /

Bpf_u_int32 net; / * The IP of our sniffing device * /

If (pcap_lookupnet (dev, & net, & mask, errbuf) = =-1) {undefined

Fprintf (stderr, "Can't get netmask for device% s\ n", dev)

Net = 0

Mask = 0

}

Handle = pcap_open_live (dev, BUFSIZ, 1, 1000, errbuf)

If (handle = = NULL) {undefined

Fprintf (stderr, "Couldn't open device% s:% s\ n", dev, errbuf)

Return (2)

}

If (pcap_compile (handle, & fp, filter_exp, 0, net) =-1) {undefined

Fprintf (stderr, "Couldn't parse filter% s:% s\ n", filter_exp, pcap_geterr (handle))

Return (2)

}

If (pcap_setfilter (handle, & fp) =-1) {undefined

Fprintf (stderr, "Couldn't install filter% s:% s\ n", filter_exp, pcap_geterr (handle))

Return (2)

}

1.1.1.5 start to grab the bag

Now that you are ready to monitor the grab package and set the filter, the following is the start of the capture package.

There are two kinds of bag grabbing techniques, one is to grab one bag at a time, and the other is to grab it together when there are n bags.

Let's take a look at grabbing one bag at a time. The function is as follows:

U_char * pcap_next (pcap_t * p, struct pcap_pkthdr * h)

The first parameter is the created session handle, and the second parameter holds the package information.

This function is rarely used. Nowadays, most package grabbing tools use the second technology to grab packages, and the functions used are:

Int pcap_loop (pcap_t * p, int cnt, pcap_handler callback, u_char * user)

The first parameter is the created session handle, and the second parameter is the number (grab several packets), that is, this parameter determines how many packets to grab, and then the capture ends. The third function is to catch a sufficient number of callback functions, which are called every time they are caught. The fourth parameter is often set to NULL, which is useful in some applications.

Similar to the pcap_loop function is pcap_dispatch, the usage of the two is basically the same, the main difference is that pcap_dispatch will only execute the callback function once, while pcap_loop will always call the callback function processing package.

Its callback function is defined as follows:

Void got_packet (u_char * args, const struct pcap_pkthdr * header, const u_char * packet)

The first parameter, args, is the last parameter of the pcap_loop function, the second is the header of the pcap, which contains the information about the captured package, and the third is the package itself.

Struct pcap_pkthdr {undefined

Struct timeval ts; / * time stamp * /

Bpf_u_int32 caplen; / * length of portion present * /

Bpf_u_int32 len; / * length this packet (off wire) * /

}

About the package itself is actually a string pointer, how to find my ip header, tcp header, and the contents of the header? This requires the use of exceptionally powerful pointers in the C language. Define a macro as follows:

/ * Ethernet addresses are 6 bytes * /

# define ETHER_ADDR_LEN 6

/ * Ethernet header * /

Struct sniff_ethernet {undefined

U_char ether_ dhost [Eter _ ADDR_LEN]; / * Destination host address * /

U_char ether_ shot [Eter _ ADDR_LEN]; / * Source host address * /

U_short ether_type; / * IP? ARP? RARP? Etc * /

}

/ * IP header * /

Struct sniff_ip {undefined

U_char ip_vhl; / * version > 2 * /

U_char ip_tos; / * type of service * /

U_short ip_len; / * total length * /

U_short ip_id; / * identification * /

U_short ip_off; / * fragment offset field * /

# define IP_RF 0x8000 / * reserved fragment flag * /

# define IP_DF 0x4000 / * dont fragment flag * /

# define IP_MF 0x2000 / * more fragments flag * /

# define IP_OFFMASK 0x1fff / * mask for fragmenting bits * /

U_char ip_ttl; / * time to live * /

U_char ip_p; / * protocol * /

U_short ip_sum; / * checksum * /

Struct in_addr ip_src,ip_dst; / * source and dest address * /

}

# define IP_HL (ip) (ip)-> ip_vhl) & 0x0f)

# define IP_V (ip) (ip)-> ip_vhl) > > 4)

/ * TCP header * /

Typedef u_int tcp_seq

Struct sniff_tcp {undefined

U_short th_sport; / * source port * /

U_short th_dport; / * destination port * /

Tcp_seq th_seq; / * sequence number * /

Tcp_seq th_ack; / * acknowledgement number * /

U_char th_offx2; / * data offset, rsvd * /

# define TH_OFF (th) (th)-> th_offx2 & 0xf0) > > 4)

U_char th_flags

# define TH_FIN 0x01

# define TH_SYN 0x02

# define TH_RST 0x04

# define TH_PUSH 0x08

# define TH_ACK 0x10

# define TH_URG 0x20

# define TH_ECE 0x40

# define TH_CWR 0x80

# define TH_FLAGS (TH_FIN | TH_SYN | TH_RST | TH_ACK | TH_URG | TH_ECE | TH_CWR)

U_short th_win; / * window * /

U_short th_sum; / * checksum * /

U_short th_urp; / * urgent pointer * /

}

/ * ethernet headers are always exactly 14 bytes * /

# define SIZE_ETHERNET 14

Const struct sniff_ethernet ethernet; / The ethernet header * /

Const struct sniff_ip ip; / The IP header * /

Const struct sniff_tcp tcp; / The TCP header * /

Const char payload; / Packet payload * /

U_int size_ip

U_int size_tcp

Through the above structure definition, we can find the link frame header, IP frame header, TCP frame header and data load one by one from the packet pointer address of the callback function.

At this point, the study on "what is the principle of tcpdump grab package in Linux" is over. I hope to be able to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report