Linux how to achieve mirror port

In all the high-end models, most end type and switch / router some low-end models, can be configured with one or a plurality of mirror port, it is the tool for flow analysis. However, Linux is not off the shelf technology can realize the port mirroring, of course, I wasn't referring to Linux 3.x (x is few, forget) above the kernel, the kernel has been supporting the mirror, but not good enough. At least, the kernel of 2.6.35 is not supported, then the Linux soft switch which belongs to the class? The key is, many high-end network products is realized based on Linux, no mirror how I can do it, even without the use of Linux bridge, also hope to be able to realize the port mirroring a technology.
I believe, and sure, many products have implemented this technology, it is in fact very simple, many years ago, my own time in learning Huawei network technology, the kernel module in Linux wrote a mirror, although that is implemented in the Internet to find other half film code change. Now, I can not very modest to say that they are proficient in Netfilter and Linux IP routing, Decided to give an implementation based on Netfilter, Netfilter in the, It almost can be extended to any protocol stack, Even rewriting the entire stack... Over the years, Discussion on how to realize the Linux port mirroring many, Also gave birth to try and fix many Evergo people, For me personally, The first set foot in this topic is in 2009, Although the time to learn Cisco technology got, But after all, is not a task, I only said that the Cisco technique is to learn and do not take too expensive, So you can have a lot of this should be used for test preparation time for learning Linux, Especially the characteristics of the Cisco implementation in Linux, As an aside, I was on Cisco and Linux network technology can also master, And learn and do not have great relations, But for the job, That is another matter...
Given the code before, I first give a only depends on the configuration can be completed, and then talk about its shortcomings. In fact, only rely on the brctl command or sysfs, echo can achieve a mirror port, the concrete procedure is:
1 make sure your mirror port, such as eth5,
The actual data through 2 ports, such as eth0 and mirror port tied into a bridge,
3 calls to the brctl setageing command will be aging time is set to 0, which is the simulation of a hub 2 Port,
4 of all eth0 port data sent the package will be sent to eth5
...

But! But each physical interface can only belong to a bridge, it means that you can only capture a direction by the way of data, have to use a mirror image of another export use the same way to capture another direction of the data, and then the two mirror port connected to a switch, this switch the two into one, this way, or, is too hard!
So, The software have some practice?, I realize that many years ago, General idea is to register a ETH_P_ALL type of packet_type, Similar to tcpdump as capture data packet capture, Then call the in kernel modules dev_queue_xmit sends it to your definition of mirror port, The specific definition of need through the character device IOCTL, PROCFS to define. This way is relatively routine, work better, and can be from the virtual network such as tap will flow to mirror process rather than the audit equipment cable. However, Or is it too hard, You pass in the BPF syntax to filter the packets before, Flow has been ETH_P_ALL interception... In fact, Not all traffic needs to be mirrored! BPF powerful, But relying on the middle layer of interpretation of translation, The threshold is too high, I believe, A iptables rule and an equivalent BPF rules on the, Can read the former accounted for the vast majority of, Cannot read the latter accounted for the vast majority of, Too flexible or inflexible, Give you a Xinhua Dictionary, All the words are in there, You read it ten times as read "Guwenguanzhi"... This is from Shannon's information theory to prove.

The implementation of xt_TEE

In xtables-addons, has been the realization of a xt_TEE, in manual, there is a stick out a mile configuration:
-t mangle -A PREROUTING -i eth0 -j TEE --gateway 2001:db8::1
The cloning of a packet, and then sent to an IP address, the IP address can be configured. Why do I feel bad about it first?, I think the dependent IP instead of port to mirror the data packet may need additional too much configuration based on, For example, you have to have a clear IP receiver address; second I think it is not very good, It hinders the rapid adoption of the original data packet, While I tend to use the "lower" thought to solve the problem of cloning packets, The first will be discharged into a queue, And then let the system scheduling the sending, Rather than forcing call in code sending code. In addition to these two points, the realization of TEE is really good. After looking at the implementation of TEE, I wonder, why:
-j TEE --dev ethX,ethY,ethZ
This setting will not? Of course, certainly not, because the TEE target no --dev parameter, but why no one realized?... don't just kernel lacks automatically by the dev package head interface Ethernet? Perhaps, after all, all dev_queue_xmit calls are from the road down by the layer of a road...
Now this is my latest realized. This implementation is very simple, like TEE, write a new iptables target, or CLONE. Cloning of a data packet and tagged, then how to process the packet? Apparently according to the label to find the policy routing table, you can in the routing table of all clones data packet to any one card, this is not the mirror port meaning?
That is, although you can clone data by way of reroute labeled packets will be sent to a network adapter card, but the need to target or to the next hop ARP in the former, it may lead to the failure of the ARP did not respond and, fortunately, the ifconfig command can disable the network card ARP it is not, for port mirroring??

Episode

At first, Write the module's goal is not to do mirror port, But to be two copies of a packet, That's all, In fact, packet capture module is designed to achieve a Netfilter, Compared with using pcap capture, Its advantage is that can remove the interference of many irrelevant data packets, It can only crawl is sent to the data packet, Although this may violate the capture of the meaning of the original, But that is just a word! I and many people in most cases capture is not to out of other people's data, But in order to solve and their related problems, This needs to filter out the accidentally come because the switch MAC mapping due to send all data port, But the need to write a lot of tcpdump rules.
The use of Netfilter with iptables to do this thing, Advantage is not need to put all the rules in writing a command, You can drop those you are not interested in the package with the mark filter in the PREROUTING mangle table, And then in the FORWARD filter interested in Bao Shishi Bao Kelong, And then cloned into data packets through the strategic route to any place you want it to arrive. You can write a module, is used to decide whether to package record completely, or only record protocol metadata - just like LOG target. This is very important, most of the time, we don't care about load content, unless you do in depth analysis.
In a word, I didn't like that do all the procedures, so is the capture, a ETH_P_ALL will all data without forethought all interception, it is not appropriate, of course it is more consistent with the original meaning of capture, but who cares? Perhaps the UNIX philosophy in worship, but also just maybe. Positivism is effective not anywhere.
In our implementation, and the realization of TEE different, I just cloning data packets, and then to play the last label, as to what to do next, subsequent HOOK to decide, you even can use my CLONE target and TEE target together, to form a packet fork.
Given below, note, the implementation ofCan't doBao Xiutan!

Realization

This is achieved by the 4 part, which contains a kernel module file, a user mode iptables library file, a structure to define a header, a set of Makefile. The code is fully in accordance with xtables-addons standard production.
The structure definition header files: xt_CLONE.h

#ifndef _LINUX_NETFILTER_XT_CLONEMARK_H
#define _LINUX_NETFILTER_XT_CLONEMARK_H 1

struct xt_clonemark_tginfo {
        __u32 mark;
};

#endif /* _LINUX_NETFILTER_XT_CLONEMARK_H */



The kernel module: xt_CLONE.c
/*
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License; either
 *      version 2 of the License, or any later version, as published by the
 *      Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h>
#include <net/ip6_route.h>
#include "xt_CLONE.h"
#include <net/ip.h>
#include "compat_xtables.h"

struct sk_buff_head clq;
static struct tasklet_struct clone_xmit_tasklet;


static void clone_xmit_work(unsigned long data)
{
        struct sk_buff_head *pclq = (struct sk_buff_head *)data;
        struct net_device *old_dev = NULL;
        struct net_device *new_dev = NULL;
        do {
                struct sk_buff * skb = skb_dequeue_tail(pclq);
                old_dev = skb_dst(skb)->dev;
                if (ip_route_me_harder(&skb, RTN_UNSPEC)) {
                        kfree_skb(skb);
                }
                new_dev = skb_dst(skb)->dev;
                if (old_dev != new_dev) {
                        ip_local_out(skb);
                } else {
                        kfree_skb(skb);
                }
        } while (!skb_queue_empty(pclq));
}


static unsigned int
clone_tg6(struct sk_buff **poldskb, const struct xt_action_param *par)
{
        // TODO
        return XT_CONTINUE;;
}

static unsigned int
clone_tg4(struct sk_buff **poldskb, const struct xt_action_param *par)
{
        const struct xt_clonemark_tginfo *markinfo = par->targinfo;
        struct sk_buff *newskb;
        __u32 mark;
        __u32 qlen;

        qlen = skb_queue_len (&clq);
        // Total amount control!
        if (qlen > 1000/*The sysctl parameter control*/) {
                return XT_CONTINUE;
        }
        mark = markinfo->mark;
        newskb = pskb_copy(*poldskb, GFP_ATOMIC);
        if (newskb == NULL)
                return XT_CONTINUE;

        // In the FORWARD chain was done to can rest assured that reroute, the key in the re prefix
//      skb_dst_drop(newskb);

        // Discard the connection tracking, but pseudo tracking connection to initialize a notrack
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#include <net/netfilter/nf_conntrack.h>
        nf_conntrack_put(newskb->nfct);
        newskb->nfct = &nf_conntrack_untracked.ct_general;
        newskb->nfctinfo = IP_CT_NEW;
        nf_conntrack_get(newskb->nfct);
#endif
        newskb->mark = mark;
        skb_queue_head(&clq, newskb);
        tasklet_schedule(&clone_xmit_tasklet);

        return XT_CONTINUE;
}

static struct xt_target clone_tg_reg[] __read_mostly = {
        {
                .name       = "CLONE",
                .revision   = 0,
                .family     = NFPROTO_IPV6,
                .table      = "filter",
                .target     = clone_tg6,
                .targetsize = sizeof(struct xt_clonemark_tginfo),
                .me         = THIS_MODULE,
        },
        {
                .name       = "CLONE",
                .revision   = 0,
                .family     = NFPROTO_IPV4,
                .table      = "filter",
                .target     = clone_tg4,
                .targetsize = sizeof(struct xt_clonemark_tginfo),
                .me         = THIS_MODULE,
        },
};

static int __init clone_tg_init(void)
{
        skb_queue_head_init(&clq);
        tasklet_init(&clone_xmit_tasklet, clone_xmit_work, (unsigned long)&clq);
        return xt_register_targets(clone_tg_reg, ARRAY_SIZE(clone_tg_reg));
}

static void __exit clone_tg_exit(void)
{
        tasklet_kill(&clone_xmit_tasklet);
        return xt_unregister_targets(clone_tg_reg, ARRAY_SIZE(clone_tg_reg));
}

module_init(clone_tg_init);
module_exit(clone_tg_exit);
MODULE_AUTHOR("Wangran <>");
MODULE_DESCRIPTION("Xtables: CLONE packet target");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip6t_CLONE");
MODULE_ALIAS("ipt_CLONE");



The iptables module: libxt_CLONE.c

/*
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License; either
 *      version 2 of the License, or any later version, as published by the
 *      Free Software Foundation.
 */
#include <stdio.h>
#include <getopt.h>
#include <xtables.h>
#include "xt_CLONE.h"
#include "compat_user.h"

enum {
        FL_MARK_USED     = 1 <<0,
};

static const struct option clonemark_tg_opts[] = {
        {.name = "mark",     .has_arg = true, .val = '1'},
        {NULL},
};

static void clonemark_tg_init(struct xt_entry_target *t)
{
        struct xt_clonemark_tginfo *info = (void *)t->data;
        info->mark = ~0U;
}

static void clone_tg_help(void)
{
        printf("CLONE --mark mark\n\n");
}

static int clone_tg_parse(int c, char **argv, int invert, unsigned int *flags,
                         const void *entry, struct xt_entry_target **target)
{
        struct xt_clonemark_tginfo *info = (void *)(*target)->data;
        unsigned int n;
        switch (c) {
        case '1':
                xtables_param_act(XTF_ONLY_ONCE, "CLONE", "--mark", *flags & FL_MARK_USED);
                xtables_param_act(XTF_NO_INVERT, "CLONE", "--mark", invert);
                if (!xtables_strtoui(optarg, NULL, &n, 0, ~0U))
                        xtables_param_act(XTF_BAD_VALUE, "CLONE", "--mark", optarg);
                info->mark = n;
                *flags |= FL_MARK_USED;
                return true;
        }
        return false;
}

static void clone_tg_check(unsigned int flags)
{
        //TODO
}

static void
clonemark_tg_save(const void *entry, const struct xt_entry_target *target)
{
        const struct xt_clonemark_tginfo *info = (const void *)target->data;
        printf(" --mark 0x%x ", (__u32)info->mark);
}

static struct xtables_target clone_tg_reg = {
        .version       = XTABLES_VERSION,
        .name          = "CLONE",
        .family        = NFPROTO_UNSPEC,
        .size          = XT_ALIGN(sizeof(struct xt_clonemark_tginfo)),
        .userspacesize = XT_ALIGN(sizeof(struct xt_clonemark_tginfo)),
        .init          = clonemark_tg_init,
        .save          = clonemark_tg_save,
        .help          = clone_tg_help,
        .parse         = clone_tg_parse,
        .final_check   = clone_tg_check,
        .extra_opts    = clonemark_tg_opts,
};

static __attribute__((constructor)) void clone_tg_ldr(void)
{
        xtables_register_target(&clone_tg_reg);
}


Compile:
Advice when compiling C code into the xtables-addons extensions directory, and then modify the directory of the Kbuild file, add the following line:
obj-${build_CLONE} += xt_CLONE.o
Modify the directory of the Mbuild file, add the following line:
obj-${build_CLONE} += libxt_CLONE.so
Modify the directory the directory of the mconfig file, add the following line:
build_CLONE=m
In the extensions directorymake && make installYou can,

Explain

Why the table doing in filter? Because the filter table in the route after the execution of, this is in order to call reroute interface function of ip_route_me_harder is convenient, the function is derived as a kernel interface, you can directly call. Before you do, I tried to call the ip_queue_xmit function, However, found that only starting in the machine package will pass through the path, Therefore, the need for SKB to bind a socket can, And this is the increase in workload; later, I thought of directly calls the ip_rcv_finish function, Can the function does not export, In the loading module before you go to PROCFS check the function's address, Then the incoming module, This practice is not standard; later, Come very naturally is called ip_route_me_harder interface function, However, the function of SKB has been a dst_entry (this is very normal, The re prefix in reroute show that the SKB has been routed once), Therefore must call in after the route, So obviously the processing position fell to the middle position of saddle surface Netfilter HOOK and routing structure, Only in the filter table to do, After the re routing, Call ip_local_out directly from the third layer can be issued.
Then there is the problem, since it has been re routing, in order not to directly from the results of the second layer routing issues in dev, is calling the dev_queue_xmit function. It is completely possible, but also can increase the workload, for example you need to add their own MAC header encapsulation etc.. In the realization of a molding, all packages must be made byThe stack itselfTo finish, namely the function call stack, because the stack itself is doing, never achieve in their own code, if you think you can achieve a better, then just get rid of the protocol stack.

Limited

This implementation still have certain limitations, after all the way too high, it will change the MAC header data packets, but the depth resolution for application layer content, no matter. Also of note, need to do three things in this machine, the first is to set up the CLONE rules and to determine the mark, second is set based on mark and policy routing, third is the policy routing to export equipment ARP disable. In addition to the machine to do work, but also receives the interface at the receiving image data machine open promiscuous mode.
After all, this is just a test, the solution is not formed, can achieve this point I have been very satisfied.

Posted by Louisa at October 24, 2014 - 1:10 AM