packet handlers in different threads in pcap - c

I'm trying to work with pcap and want it to work in a way wherein once I receive a packet, I want that packet to be processed independently while my pcap_loop() stills sniffs on other incoming packets.
This way I have my packet being processed and wait for an ACK for a specified time. If I don't receive an ACK, I take some other action.
What I don't understand is how to create a thread for a packet after it is sniffed..so that each packet is processed independently of the other.
So it would be something of this sort,
pcap_loop(handle, -1, got_packet, NULL)
When creating a pthread where should I have my have my code for
pthread_create(pthread_t, NULL, &got_packet, NULL)
Thanks for your help!
The following code below just captures one packet and then exits.
EDited to include code frags:
struct parameter {
u_char *param1;
const struct pcap_pkthdr *param2;
u_char *param3;
};
pcap_loop(handle, -1, create_thread, NULL);
void create_thread(u_char *args, const struct pcap_pkthdr *header, u_char *packet)
{
struct parameter thrd_args;
thrd_args.param1 = args;
thrd_args.param2 = header;
thrd_args.param3 = packet;
pthread_t packet_handler;
pthread_create(&packet_handler, NULL, &got_packet, (void *)&thrd_args);
error handling....
pthread_exit(NULL);
}
void *got_packet(void *thrd_args)
{
struct parameters *thread_args;
thread_args = thrd_args;
u_char *args = &thread_args->param1;
const struct pcap_pkthdr *header = &thread_args->param2;
u_char *packet = &thread_args->param3;
}

Is there a real good reason for you to handle the packet processing in a different thread? The pcap driver stores packets for you in a queue so you will not miss them if they arrive while you process previous packets (depending of course on the size of the buffer you stated when you created the sniffer). Be that as it may, you should probably create the thread in your got_packet function (which will be called by the pcap driver every time a packet is sniffed) and give it the address of a different processing function like so: pthread_create(pthread_t, NULL, &process_packet, NULL) . Of course you need to somehow pass the packet to your new processing thread, but I'll leave that for you to figure out.

I did it bit differently, maybe this will help anyone. Once pcap_loop receives a packet, call appropriate function, where you create new thread and do pthread_detach() along with return 0. The new thread will handle the packet and pcap will the same way process another packet in another thread.
You will then have as many threads as you will receive packets.

Related

How to extract entire packet from skb including ethernet header, ip, and tcp plus pay load in poll method of device driver

in r8169 driver from realtek it does
rx_buf = page_address(tp->Rx_databuff[entry]);
dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
prefetch(rx_buf);
skb_copy_to_linear_data(skb, rx_buf, pkt_size);<----//Do I get packet at this????
skb->tail += pkt_size;
skb->len = pkt_size;
dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
//csum...
skb->protocol = eth_type_trans(skb, dev);
napi_gro_receive(&tp->napi, skb);
this is inside rtl_rx function called from poll of driver. I like to know in above code how can I extract the entire packet from skb at which line afterwards.
I assume at this line
skb_copy_to_linear_data(skb, rx_buf, pkt_size);
I should have a packet, but like to know the correct way I can create a kmalloc obect like
void *packet= kmalloc(....sizeof(struct ethhdr)+sizeof(struct iphdr)+sizeof(tcphdr))
and read ethernet ip and tcp headers from void *packet
How to achieve it
Or should I simple do skb_netword_header, skb_tcp_header, etc... to extract the headers and payload from skb after it get populated in above lines,
or can I simply cast as
rx_buf = page_address(tp->Rx_databuff[entry]);
struct ether_header ethhdr_of_packet=(struct eher_header *) rx_buf;
Should it work?
The highlighted line (the one with skb_copy_to_linear_data()) indeed copies entire packet data from the buffer in the driver-internal Rx ring (rx_buf) to the data buffer of the skb.
static inline void skb_copy_to_linear_data(struct sk_buff *skb,
const void *from,
const unsigned int len)
{
memcpy(skb->data, from, len);
}
Casting the rx_buf pointer to Ethernet header should be OK, too. However, the purpose of accessing the packet header like this is rather vague in the question of yours. Are you trying to just print ("dump") the packet or do you intend to copy the packet data to a completely different buffer to be consumed elsewhere?

How to get next TCP segment in linux kernel module?

I know I can get the pointer of TCP packet data like this:
char *data = (char *)tcphdr + 4 * tcph->doff;
But once data was segmented I cannot get full data such way. So how to get next sk_buff of next segment?
My simple code:
#include ...
static struct nf_hook_ops nfho;
unsigned int hook_funcion(void *priv, struct sk_buff *skb, const struct
nf_hook_state *state)
{
// check if it is TCP packet
char *data = (char *)tcphdr + 4 * tcph->doff;
// do something here
return NF_ACCEPT;
}
static int __init hook_init(void)
{
int ret;
nfho.hook = hook_funcion;
nfho.pf = NFPROTO_IPV4;
nfho.hooknum = NF_INET_POST_ROUTING;
nfho.priority = NF_IP_PRI_LAST;
ret = nf_register_hook(&nfho);
printk("xmurp-test start\n");
printk("nf_register_hook returnd %d\n", ret);
return 0;
}
static void __exit hook_exit(void)
{
nf_unregister_hook(&nfho);
printk("xmurp-test stop\n");
}
module_init(hook_init);
module_exit(hook_exit);
Your question is a bit complicated as there is no such thing in TCP as "full data", as TCP is a stream protocol and not a datagram protocol (in contrast of UDP). This means that there is no specific end to the data (unless the connection is closed / reset).
If you're handling an application-layer protocol which segments the TCP stream into sized messages (for example: HTTP), you should act in the following steps:
Parse the TCP payload and figure out how large this current message is.
Only then you can handle the following packets / segments as they arrive in the network stack as the continuation of the same message.
Finally, after all the data you expect have arrived, you can reassemble them and only then use their data on the application layer.
Do remember that the network works in datagrams and TCP is a stream protocol. So it might be very much possible that at the time of your first segment's handling, the rest of the data has yet to arrive. Therefore you must manage a desegmentation (defragmentation) over this and future packets over this specific stream and only then parse upper layer protocols.

netfilter - how to specify queue number in kernel module?

I am writing a kernel module which needs to do some packet filtering work at the IP layer. What I need to do is intercept all IP packets, and on some outgoing packets, I need to withhold them for a small amount of time (like a few dozen milliseconds) for analysis before sending them on their way.
I've got the kernel module up and running, at the moment it accepts all incoming packets and returns NF_QUEUE on all outgoing packets. I can then pick up those packets using libnetfilter in userspace (like with a Python script and NetfilterQueue) but the problem is that the Python library takes a queue number, and my kernel module queues up the packets in queue #0. How do I configure that?!
This is what my kernel module's outgoing packet hook looks like (cobbled up from various sources):
static struct nf_hook_ops nfho_send;
unsigned int hook_send_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
return NF_QUEUE;
}
/* in init_module() */
nfho_send.hook = hook_send_func;
nfho_send.hooknum = NF_INET_POST_ROUTING;
nfho_send.pf = NFPROTO_IPV4;
nfho_send.priority = NF_IP_PRI_LAST;
nf_register_hook(&nfho_send);
Where do I specify which queue the packets will end up on? What is the significance of queue numbers? I can't be processing random stray packets queued by another hook than mine, is that already done by default?
Thanks! Also, I am using Linux 3.x.
Use the NF_QUEUE_NR(x) macro. You pass it a single argument (the queue number), and it will build your return value for you. Specifically, it will left-shift the queue number by 16 bits and then AND it with NF_QUEUE.
If you're interested, the implementation is in include/uapi/linux/netfilter.h

Caching packets captured from pcap

This is a follow-up question to this:
Rebuilding a packet to inject via pcap
What I want to accomplish:
functionA: Capture packets with pcap. Modify source/destination addresses. Recalculate checksums. Inject with pcap.
functionB: Create two threads. Thread 1 sends a magic packet to wake sleeping client. Thread 2 captures packets with pcap and caches the packets into an array of u_char *'s, since pcap puts the packet data serially into "u_char * packet". When both threads terminate, I then change the headers then inject each of the cached packets.
What I need help with:
functionA: I can do everything but calculate checksums. I tried to verify the original checksum by calculating it myself with a function but they never match. However, this issue is not as important because I don't need it to demo my final project. I understand that if IP checksums are incorrect, the receiving computer will discard the packet. But when I demo, so long as my client computer can be shown to have received this incorrect packet, I have proven my overall concept and will not fail. :)
functionB: I guess this is the more important problem. I don't know of an easy way to cache my captured packets. What I'm working on right now is as follows:
functionB creates a pointer to an array that stores u_char * called cachedPackets. So cachedPackets basically points to an array that stores "strings".
It'll be something like this? u_char ** cachedPackets[100], enough array elements for 100 packets.
After this, I start two threads. Thread1 to wake my sleeping client. Thread2 to open another pcap session so no data is lost while client is waking. Thread1 is easy, I've already tested my send magic packet function independently. Thread2 is where I'm screwing up.
Thread2 eventually calls int pcap_loop(pcap_t *p, int cut, pcap_handler callback, u_char *user).
callback is the function that will be run after each packet is captured. It is where I will be caching the packet into the array.
callback takes parameters ( u_char* user,
const struct pcap_pkthdr* packet_header,
const u_char* packet_data )
user is the same string in the 4th argument of pcap_loop.
So I was thinking, I could sneakily give my callback function the pointer to the array of string by type casting it.
pcap_loop(asdf, asdf, callback, (u_char *)cachedPackets);
Since I don't know how big the incoming packets will be, I'll dynamically allocate enough space in the callback function. I will also keep track of my position in the array with a static int.
this is what the callback looks like:
void cacheCall(u_char * user, const struct pcap_pkthdr * header, const u_char * packet)
static int cacheindex = 0;
u_char ** cachethis = (u_char **)user;
//u_char * cachething = *cachethis;
(*cachethis)[cacheindex] = (u_char *) malloc(header->len); <--- 497
int i = 0;
for(i = 0; i < header->len; i++)
{
(*cachethis)[cacheindex][i] = packet[i]; <-------------------503
}
//memcpy(cachething[cacheindex], packet, header->len);
cacheindex++;
but when I compile, i get
497: warning: assignment makes integer from pointer without a cast
503: error: subscripted value is neither array nor pointer
That was pretty longwinded, hopefully my knowledge of what I'm doing isn't completely misinformed. Any help would be awesome! :)
u_char ** cachethis;
cachethis is a pointer-to-pointer-to-u_char.
So:
*cachethis
is a pointer-to-u_char, and:
(*cachethis)[i]
is a plain u_char.
So line 497 tries to store a pointer into an u_char, and line 503 tries to subscript a u_char, both of which are invalid.
Looks like what you want is simply:
cachethis[i]
and
cachethis[i][j]

In Linux's net/ipv4/udp.c, why does a UDP packet need to be processed by xfrm4_policy_check()?

int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) {
struct udp_sock *up = udp_sk(sk);
int rc;
int is_udplite = IS_UDPLITE(sk);
/*
* Charge it to the socket, dropping if the queue is full.
*/
if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
goto drop;
nf_reset(skb);
I'm reading the code in Linux net/ipv4/udp.c. Can anyone explain to me why an UDP packet need to run through xfrm_policy_check()?
As far as I know the function return:
true: non-IPsec packet / valid IPsec packet
false: invalid IPsec packet
I might have misunderstood the function return value, as do not entirely understand the source code.
xfrm4_policy_check function checks the packet against IPsec policies. The return value of this function is 1 if the packet is allowed to be processed, and zero if it is not. For example, IPsec might decide to drop the packet if skb->ip_summed is not set to CHECKSUM_UNNECESSASRY and packet fails a checksum.

Resources