The quick intro to libipq

The quick intro to libipq

By: Chris, Christy and Frank
We are going to begin with looking at some of the sample code provided in the man page of libipq. Its not completely obvious whats going on here with the direction and flow of packets, so I'll try and explain as we go.
Before you try running the code, you need to do a couple things:
  • modprobe iptable_filter
  • modprobe ip_queue
  • iptables rule to direct packets to QUEUE
      The ones we will be using are:
    • iptables -A OUTPUT -p icmp -j QUEUE
    • iptables -A INPUT -p tcp -j QUEUE
    • iptables -A INPUT -p udp -j QUEUE
The code begins... We have some includes, one of which is for libipq, and the other is netfilter. We use the libipq one for all of the functions prefixed with ipq_ and the netfilter header is for some of the constants we use through out. Other useful headers include the ip header, tcp header, and any other packet type that you might want to be able to map into a structure.
    
    
    
    
#include  < linux / netfilter.h >
#include 
< libipq.h >
#include 
< stdio.h >

#define  BUFSIZE 2048 

static   void  die( struct  ipq_handle  * h)
{
        ipq_perror(
" passer " );
        ipq_destroy_handle(h);
        exit(
1 );
}

int  main( int  argc,  char   ** argv)
{
        
int  status;
        unsigned 
char  buf[BUFSIZE];
Here we need a ipq_handle in order to use later when we want to do things, such as read packets and do any other libipq operations. Note we also have a buf[BUFSIZE] above this, which is a static sized buffer for packet data. We create the handle, and move or die trying.
    
    
    
    
         struct  ipq_handle  * h;
        
        h 
=  ipq_create_handle( 0 , PF_INET);
        
if  ( ! h)
                die(h);
Now we determine the mode that we want to use to get packets. The different modes are IPQ_COPY_META and IPQ_COPY_PACKET. Basically we need to know if we want payloads as well as meta-data. This also initiates the transfer of packets from the QUEUE to user-space. If we specify IPQ_COPY_PACKET, then the 3rd argument is the size of the payload we are going to want. If this fails we die.
        
    
    
    
    
status  =  ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
        
if  (status  <   0 )
                die(h);
                
        
do {
Next we read the contents of a packet, with ipq_read. This says to read into buf, for a maximum size of BUFSIZE (we don't want to overflow the buffer right...). The last arg, in this case 0, is the timeout for the read operation. This is the same as a select() function timeout.
                
    
    
    
    
status  =  ipq_read(h, buf, BUFSIZE,  0 );
                
if  (status  <   0 )
                        die(h);
                        
                
switch  (ipq_message_type(buf)) {
                        
case  NLMSG_ERROR:
                                fprintf(stderr, 
" Received error message %d " ,
                                        ipq_get_msgerr(buf));
                                
break ;
Based on the message type, we can determine an error (NLMSG_ERROR) or if we got a packet (IPQM_PACKET). Then we use the packet_msg_t to access the packet, and then set the verdict (ACCEPT or DROP). ACCEPT allows the packet through the netfilter hooks, and into the appropriate service. DROP makes the packet disappear.
Also in the IPQM_PACKET block we have some additional code which is not in the man page. This is just an example of how to access parts of the packets, such as the IP layer header and the TCP header. To point the headers at the right places you basically just need the size of each previous header. Then by offsetting from the m->payload pointer we can access the different portions of the packet. Once we have this, you can get any of the data contained in the header, such as the port in this example.
 
                       case  IPQM_PACKET: {
                                ipq_packet_msg_t 
* =  ipq_get_packet(buf);

                                
struct  iphdr  * ip  =  ( struct  iphdr * ) m -> payload;

                                
struct  tcphdr  * tcp  =  ( struct  tcphdr * ) (m -> payload  +  ( 4   *  ip -> ihl));
                                  
                                
int  port  =  htons(tcp -> dest);        
                               
                                status 
=  ipq_set_verdict(h, m -> packet_id,
                                                         NF_ACCEPT, 
0 , NULL);
                                
if  (status  <   0 )
                                        die(h);
                                
break ;
                        }
                        
                        
default :
                                fprintf(stderr, 
" Unknown message type! " );
                                
break ;
                }
        } 
while  ( 1 );
After we are done, we cleanup and exit. Need to remove the hook to cleanly end all of the ipq stuff.
    
    
    
    
        ipq_destroy_handle(h);
        
return   0 ;
}

 注:

libipq提供了以下函数:
 
//建立ipq的handle:
struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol);
 
// 释放ipq handle
int ipq_destroy_handle(struct ipq_handle *h);
 
// 读取数据到buf中
ssize_t ipq_read(const struct ipq_handle *h,
                unsigned char *buf, size_t len, int timeout);
 
// 设置ipq拷贝模式
int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len);
 
// 从buf中解析数据包结构
ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf);
 
// 返回包的类型
int ipq_message_type(const unsigned char *buf);
 
// 设置对数据包的裁决
int ipq_set_verdict(const struct ipq_handle *h,
                    ipq_id_t id,
                    unsigned int verdict,
                    size_t data_len,
                    unsigned char *buf);

你可能感兴趣的:(The quick intro to libipq)