"Linux Driver" Netfilter/iptables (vi) kernel protocol stack programming (send SKB)

Source: Internet
Author: User
Tags goto iptables htons

kernel State based on NetFilter constructs SKB data packet
The previous fourth article introduces the NetFilter hook mechanism, we know that packets in the protocol stack pass through different hook points, and each hook point is NetFilter pre-registration a series of hook callback function, Each packet passes through the processing of these hook functions.

In the hook callback function, you can do anything that you can customize and then load in as a module.

Here we give an example: each received 5 TCP packets to the specified IP address to send a UDP packet, this feature development involves the kernel protocol stack programming , rather than the user space we learned before the Socket network programming.

See Code implementation:

Linux kernel 3.13.0-43 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> # Include <linux/ip.h>//for IP header #include <linux/types.h> #include <linux/skbuff.h> #include < linux/if_ether.h> #include <linux/if_packet.h> #include <net/tcp.h> #include <net/udp.h> #

Include <net/icmp.h> #include <linux/inet.h> module_license ("Dual BSD/GPL"); #define ETH "Wlan0"//native wireless network card device #define SIP "192.168.1.27"//Free #define DIP "118.6.24.132"//#define SPORT 39804 #define DP ORT 6980 #define NIPQUAD (addr) \ (unsigned char *) &addr) [0],\ ((unsigned char *) &addr) [1],\ (Unsigne D char *) (&AMP;ADDR) [2],\ (unsigned char *) &addr) [3] unsigned char Smac[eth_alen] = {0x1c, 0x4b, 0xd6, 0x7a, 0x55 , 0x96};//native wireless card hardware address unsigned char Dmac[eth_alen] = {0xe0, 0XCB, 0x4e, 0xb0, 0xed,0xd8};//native network card hardware address static struct Nf_hook_ops nfho; Constructs a UDP message and sends a static int build_and_xmit_udp (char *eth, U_char *smac, U_char *dmac, U_char *pkt, int pkt_len, U_lo
    Ng sip, U_long dip, U_short Sport, u_short dport) {struct Sk_buff *skb = NULL;
    struct Net_device *dev = NULL;
    struct UDPHDR *UDPH = NULL;
    struct IPHDR *iph = NULL;
    struct ETHHDR *ethdr = NULL;
    U_char *pdata = NULL;

    int nret = 1; if (NULL = = SMAC | |

    NULL = = Dmac) goto out; Get device pointer by device name//The high version of the function called here has been modified with a parameter struct net* if (NULL = = (Dev = dev_get_by_name (&init_net, ETH)) go

    to out; 
    Create a SKB SKB = ALLOC_SKB (pkt_len + sizeof (struct UDPHDR) + sizeof (struct IPHDR) + sizeof (struct ETHHDR), gfp_atomic);

    if (NULL = = SKB) goto out; Reserved space for the SKB to facilitate the back Skb_buff protocol encapsulation Skb_reserve (SKB, Pkt_len + sizeof (struct UDPHDR) + sizeof (struct IPHDR) + sizeof (struct ET

    HHDR));
    SKB byte padding skb->dev = dev; Skb->pkt_type = packet_Otherhost;
    Skb->protocol = __constant_htons (ETH_P_IP);
    skb->ip_summed = Checksum_none;

    skb->priority = 0;
    Packet encapsulation//separate pressure into the application layer, Transport layer, network layer, link layer stack frame//skb_push from behind to the front, and skb_put different pdata = Skb_push (SKB, Pkt_len);
    UDPH = (struct udphdr*) skb_push (SKB, sizeof (struct UDPHDR));
    Iph = (struct iphdr*) skb_push (SKB, sizeof (struct IPHDR));

    ETHDR = (struct ethhdr*) skb_push (SKB, sizeof (struct ETHHDR));

    Application layer data is populated memcpy (pdata, PKT, Pkt_len);
    The transport layer UDP data is populated memset (UDPH, 0, sizeof (struct UDPHDR));
    Udph->source = sport;
    Udph->dest = Dport;

    Udph->len = htons (sizeof (struct UDPHDR) + Pkt_len);/host byte order to network byte order Udph->check = 0;//skb_checksum must be placed before 0. Agreement provisions
    Network layer data padding iph->version = 4;
    IPH-&GT;IHL = sizeof (struct IPHDR) >> 2;
    Iph->frag_off = 0;
    Iph->protocol = IPPROTO_UDP;
    Iph->tos = 0;
    IPH-&GT;DADDR = dip;
    iph->saddr = SIP;
    Iph->ttl = 0x40; Iph->tot_len = __constant_htoNS (Skb->len);
    Iph->check = 0; Iph->check = Ip_fast_csum ((unsigned char*) iph, IPH-&GT;IHL);//COMPUTE checksum skb->csum = skb_checksum (SKB, iph->ihl*4  , skb->len-iph->ihl*4, 0);//SKB checksum calculation Udph->check = csum_tcpudp_magic (SIP, dip, skb->len-iph->ihl*4,
    IPPROTO_UDP, skb->csum);//dup and TCP pseudo-header checksum//Link layer Data fill memcpy (Ethdr->h_dest, Dmac, Eth_alen);
    memcpy (Ethdr->h_source, SMAC, Eth_alen);

    Ethdr->h_proto = __constant_htons (ETH_P_IP);
        Call the kernel protocol stack function to send the packet if (Dev_queue_xmit (SKB) < 0) {PRINTK ("Dev_queue_xmit error\n");
    Goto out;
    } nret = 0;//Here is the necessary printk ("Dev_queue_xmit correct\n");
Error handling out:/* The following 0!=nret is required, even if the previous goto out, the following statement program will also execute, if not add 0!=nret statement, then the front dev_queue_xmit return (already KFREE_SKB once), Then enter the following statement the second execution of the KFREE_SKB, will cause the system to panic///The key is to know dev_queue_xmit internal call success, will KFREE_SKB, and goto statement function if (0!= nret && NULL!)
       = SKB)//Here the front of the nret judge is necessary, otherwise it must be frozen {dev_put (dev);//reduce the reference count of the device KFREE_SKB (SKB)//Destroy packet} return nret;//f_accept; atomic_t pktcnt = atomic_init (0)///hook function, note parameter format is consistent with the development environment source tree static unsigned int hook_func (const struct NF_HOOK_
        Ops *ops, struct sk_buff *skb, const struct net_device, const *in struct, Net_device,
    Int (*OKFN) (struct Sk_buff *)) {struct IPHDR *iph = IP_HDR (SKB); 
    int ret = nf_accept;

    unsigned char *pdata = "Hello kernel";

    PRINTK ("hook function processing\n");
        if (Iph->protocol = = ipproto_tcp) {atomic_inc (&pktcnt); if (Atomic_read (&pktcnt)% 5 = 0) {PRINTK (kern_info "Sending the%d UDP packet\n", Atomic_read (&A
            MP;PKTCNT)/5);
        ret = BUILD_AND_XMIT_UDP (ETH, SMAC, DMAC, pdata, strlen (pdata), In_aton (SIP), In_aton (DIP), htons (Sport), htons (Dport));
} return ret; The static int __init hook_init (void) {Nfho.hook = hook_func;//Associated handler function Nfho.hooknum = Nf_inet_local_out;//ipv4 Local ExportPlace nfho.pf = Pf_inet;//ipv4, so use this nfho.priority = nf_ip_pri_first;//priority, first CIS nf_register_hook (&AMP;NFHO);
return 0;
static void __exit hook_exit (void) {Nf_unregister_hook (&AMP;NFHO);//Logoff} module_init (Hook_init); Module_exit (Hook_exit);

The comments have been broadly explained. Note that you write the kernel program interface and data structure, and so must be with your development source tree has been, 3.13 version compared to the 2.6 version has a big change, here mainly reflected in the Sk_buff.

Here is to create a SKB in the hook function, and then manually populate the data of each protocol stack, and finally call the kernel protocol stack function Dev_queue_xmit function sent, this function is the physical layer, a driving function, so we constructed SKB data packets need to fill the application layer, Transport layer, network layer, And the data for the link layer.

At the outset of this procedure, as long as the operation (loading module), will immediately panic, for this reason do not know how many times the forced shutdown restart, and finally through debugging and access to data, found to be kfree_skb this link error, and then commented out this line of code, the program runs correctly, test also no problem, but there are always bugs Is that the data package that was created is not destroyed at last.

Later check that, because there are two times KFREE_SKB, after the success of the Dev_queue_xmit call, has been kfree_skb once, after the return, the following out: The statement will continue to execute, do not add 0!=nret judgment statement, will be called again Kree_ SKB, causing the crash.
This is less than the goto statement (almost not), not clear the role of the Goto statement, now should be so understanding goto out; Is the statement to out: The statement between the skip, the rest still how ...

Test: Make (the Make file for this series of code is the same), Insmod Wqlkp.ko
Here we use Wireshark to grab the bag (Root permission)
1. Open a video site and then DMESG

[3523.489826] sending the 237 UDP packet
[3523.489850] dev_queue_xmit correct
[3523.489922] hook function proce Ssing
[3523.602361] hook function processing
[3523.602532] hook function processing
[3523.606425] Hook Fun ction processing
[3523.688857] hook function processing
[3523.688864] sending of the 238 UDP packet
[3523.6888 ] dev_queue_xmit correct
[3523.691320] hook function processing
Using Wireshark to grab bags

As you can see, we sent a UDP message with a data content of "Hello kernel".

On the protocol stack programming and the SKB package above, we have time to follow up later.
This door is also a rookie, flaws and the wrong place also hope to correct.

Resources:
Sk_buff encapsulation and the process of encapsulating network packets

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.