I'm trying to implement my version of clustering in Contiki-ng. I took some inspiration from this code: Clustring example
What I did basically was that I created two connection:
static struct simple_udp_connection broad_conn;
static struct simple_udp_connection uni_conn;
However, though the code compiles and starts running in cooja, it stops showing me an error in the stack. I traced the error message and it looked like it came from this part of the code in stack-check.c:
if(p >= (uint8_t*)GET_STACK_ORIGIN()) {
/* This means the stack is screwed. */
return -1;
}
actual = stack_check_get_usage();
allowed = stack_check_get_reserved_size();
if(actual < 0 || allowed < 0) {
LOG_ERR("Check in inconsistent state: %" PRId32 " vs. %" PRId32 "\n", actual, allowed);
There is no memory overflow, and besides the callback functions, there is nothing in the code. The only thing that I think off is that it's because of the connections, but I just don't see why.
This is the code of nodes.c:
#include "contiki.h"
#include "simple-udp.h"
#include "sys/log.h"
#define LOG_MODULE "SensorNode"
#define LOG_LEVEL LOG_LEVEL_INFO
#define UDP_PORT_BROADCAST 1234
#define UDP_PORT_UNICAST 4321
static struct simple_udp_connection broadcast_conn;
static struct simple_udp_connection unicast_conn;
static uip_ipaddr_t CH_address;
PROCESS(nodes_process, "Nodes");
AUTOSTART_PROCESSES(&nodes_process);
/*---------------------------------Not Me------------------------------------------*/
static void
broadcast_receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
LOG_INFO("Received broadcast '%.*s' from ", datalen, (char *) data);
LOG_INFO_6ADDR(sender_addr);
LOG_INFO_("\n");
uip_ipaddr_copy(&CH_address, sender_addr);
}
/*---------------------------------------------------------------------------*/
static void
unicast_receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
LOG_INFO("Received reply '%.*s' from ", datalen, (char *) data);
LOG_INFO_6ADDR(sender_addr);
LOG_INFO_("\n");
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(nodes_process, ev, data)
{
static struct etimer periodic_timer;
static unsigned count;
static char str[32];
PROCESS_BEGIN();
/* Not me also */
/* Initialize UDP broadcast connection */
simple_udp_register(&broadcast_conn, UDP_PORT_BROADCAST, NULL,
UDP_PORT_BROADCAST, broadcast_receiver);
/* Initialize UDP unicast connection */
simple_udp_register(&unicast_conn, UDP_PORT_UNICAST, NULL,
UDP_PORT_UNICAST, unicast_receiver);
/* Send messages to the clusterhead every 60 seconds */
etimer_set(&periodic_timer, 60*CLOCK_SECOND);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
LOG_INFO("Sending message %u to ", count);
LOG_INFO_6ADDR(&CH_address);
LOG_INFO_("\n");
snprintf(str, sizeof(str), "hello %d", count);
simple_udp_sendto(&unicast_conn, str, strlen(str), &CH_address);
count++;
etimer_reset(&periodic_timer);
}
PROCESS_END();
}
Any help in explaining this would be great.
Thank you.
Related
sctp uses crc32c to calculate the checksum,but I don't know how to implement incremental updates。
code is in /include/net/sctp/checksum.h:
static inline __wsum sctp_csum_update(const void *buff, int len, __wsum sum)
{
/* This uses the crypto implementation of crc32c, which is either
* implemented w/ hardware support or resolves to __crc32c_le().
*/
return (__force __wsum)crc32c((__force __u32)sum, buff, len);
}
crc32c code is: (/lib/libcrc32c.c)
u32 crc32c(u32 crc, const void *address, unsigned int length)
{
SHASH_DESC_ON_STACK(shash, tfm);
u32 ret, *ctx = (u32 *)shash_desc_ctx(shash);
int err;
shash->tfm = tfm;
*ctx = crc;
err = crypto_shash_update(shash, address, length);
BUG_ON(err);
ret = *ctx;
barrier_data(ctx);
return ret;
}
Using libevent 2.1.11, reading the input evbuffer is limited to 4096 bytes. Due to EVBUFFER_MAX_READ 4096 in buffer.c
Given this information, the next read callback should be called after the first read callback with the remaining data.
Running this program, when the read callback is first called, there is only 4096 bytes which is normal given the EVBUFFER_MAX_READ 4096. Then the callback is called again but the length is only 1 bytes.
Ouptut when sending data over 4096 bytes.
Received data is: 4096 bytes
received: {string of 4096 bytes}
Received data is: 1 bytes
received:
How to retrieve all the data sent to the server.
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
static const int PORT = 2048;
static void conn_readcb(struct bufferevent *bev, void *arg) {
struct evbuffer *buffer = bufferevent_get_input(bev);
const size_t len = evbuffer_get_length(buffer);
printf("Received data is: %ld bytes\n", len);
if(len < 1)
return;
char *data = malloc(len);
evbuffer_remove(buffer, data, len);
printf("received: %s\n", data);
free(data);
}
static void conn_writecb(struct bufferevent *bev, void *arg) {}
static void conn_eventcb(struct bufferevent *bev, short events, void *arg) {
bufferevent_free(bev);
}
static void signal_cb(evutil_socket_t sig, short events, void *evb) {
struct event_base *base = evb;
struct timeval delay = {2, 0};
event_base_loopexit(base, &delay);
}
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *evb) {
struct event_base *base = evb;
struct bufferevent *bev;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if(!bev) {
fprintf(stderr, "Error constructing bufferevent");
event_base_loopbreak(base);
return;
}
bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_WRITE|EV_READ);
}
int main(int argc, char* argv[]) {
struct event_base *base;
struct evconnlistener *listener;
struct event *signal_event;
struct sockaddr_in sin = {0};
base = event_base_new();
if(!base) {
fprintf(stderr, "Could not get new event base");
return -1;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin,
sizeof(sin));
if(!listener) {
fprintf(stderr, "Could not create a listener");
return -1;
}
signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
if(!signal_event || event_add(signal_event, NULL) < 0) {
fprintf(stderr, "Could not create or add a singal event");
return -1;
}
event_base_dispatch(base);
evconnlistener_free(listener);
event_free(signal_event);
event_base_free(base);
return 0;
}
I have a code in contiki cooja. I have 2 sending nodes and 2 receiving nodes as you can see in the picture1. the broadcast senders and receivers are as follows.
#include "contiki.h"
#include "lib/random.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ip/uip-debug.h"
#include "simple-udp.h"
#include <stdio.h>
#include <string.h>
#define SEND_INTERVAL (20 * CLOCK_SECOND)
#define SEND_TIME (random_rand() % (SEND_INTERVAL))
static struct simple_udp_connection broadcast_connection;
/*---------------------------------------------------------------------------*/
PROCESS(broadcast_example_process, "UDP broadcast example process");
AUTOSTART_PROCESSES(&broadcast_example_process);
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received from ");
uip_debug_ipaddr_print(sender_addr);
printf(" on port %d from port %d with length %d: %s \n",
receiver_port, sender_port, datalen, data);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
static struct etimer periodic_timer;
static struct etimer send_timer;
uip_ipaddr_t addr;
char message[20];
sprintf(message," hello ");
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, 1234,
NULL, 1900,
receiver);
etimer_set(&periodic_timer, SEND_INTERVAL);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
etimer_reset(&periodic_timer);
etimer_set(&send_timer, SEND_TIME);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer));
printf("Sending broadcast\n");
uip_create_linklocal_allnodes_mcast(&addr);
simple_udp_sendto(&broadcast_connection, message , strlen(message) , &addr);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
and receivers:
#include "contiki.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "simple-udp.h"
#include "net/ip/uip-debug.h"
#include <stdio.h>
#include <string.h>
#define UDP_PORT 1900
static struct simple_udp_connection broadcast_connection;
/*---------------------------------------------------------------------------*/
PROCESS(broadcast_example_process, "UDP broadcast example process");
AUTOSTART_PROCESSES(&broadcast_example_process);
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received from ");
uip_debug_ipaddr_print(sender_addr);
printf(" on port %d from port %d with length %d: %s \n",
receiver_port, sender_port, datalen, data);
/* this line should work,right?*/
simple_udp_sendto(&broadcast_connection, "hello",5, sender_addr);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, 1900,
NULL, 1234,
receiver);
while(1) {
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
Now the problem is replying to the sender. I want each receiver node reply to the sender which has sent that message to it.
I don't know how to do that?
simple_udp_sendto() does not work.Can I use this function for this job? How should I use that?
You normally have an RDC function : packet_received. When an IT trigger, packet_received is called with the data in ptr. You just have to send again by reading the address of the sender.
Edit : you probably have a packet_received on the network layer, with same function. If you don't, you should implements one.
In following kernel module, I hooked syscall sys_open, and now trying to send filename to process in userspace using Netlink socket, in response process will return a msg, and then according to msg, the kernel module will proceed further.
source code: foo.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <linux/syscalls.h>
#include <linux/delay.h> // loops_per_jiffy
//===============netlink=================
#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#define NETLINK_USER 31
struct sock *nl_sk = NULL;
//===============netlink=================
#define CR0_WP 0x00010000 // Write Protect Bit (CR0:16)
/* Just so we do not taint the kernel */
MODULE_LICENSE("GPL");
void **syscall_table;
unsigned long **find_sys_call_table(void);
long (*orig_sys_open)(const char __user *filename, int flags, int mode);
//===============netlink=================
static void hello_nl_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int pid;
struct sk_buff *skb_out;
int msg_size;
char *msg = "Hello from kernel";
int res;
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
msg_size = strlen(msg);
nlh = (struct nlmsghdr *)skb->data;
printk(KERN_INFO "Netlink received msg payload: %s\n", (char *)nlmsg_data(nlh));
pid = nlh->nlmsg_pid; /*pid of sending process */
skb_out = nlmsg_new(msg_size, 0);
if (!skb_out)
{
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
strncpy(nlmsg_data(nlh), msg, msg_size);
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res < 0)
printk(KERN_INFO "Error while sending bak to user\n");
}
//===============netlink=================
unsigned long **find_sys_call_table()
{
unsigned long ptr;
unsigned long *p;
for (ptr = (unsigned long)sys_close;
ptr < (unsigned long)&loops_per_jiffy;
ptr += sizeof(void *))
{
p = (unsigned long *)ptr;
if (p[__NR_close] == (unsigned long)sys_close)
{
printk(KERN_DEBUG "Found the sys_call_table!!!\n");
return (unsigned long **)p;
}
}
return NULL;
}
long my_sys_open(const char __user *filename, int flags, int mode)
{
long ret;
//Send filename & get response from user space app
if(/*user_space_response ==*/ 0)
{
/*Other processing*/
}
ret = orig_sys_open(filename, flags, mode);
printk(KERN_DEBUG "file %s has been opened with mode %d\n", filename, mode);
return ret;
}
static int __init syscall_init(void)
{
int ret;
unsigned long addr;
unsigned long cr0;
syscall_table = (void **)find_sys_call_table();
if (!syscall_table)
{
printk(KERN_DEBUG "Cannot find the system call address\n");
return -1;
}
//===============netlink=================
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
if (!nl_sk)
{
printk(KERN_DEBUG "Error creating socket.\n");
return -1;
}
//===============netlink=================
cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);
addr = (unsigned long)syscall_table;
ret = set_memory_rw(PAGE_ALIGN(addr) - PAGE_SIZE, 3);
if(ret)
{
printk(KERN_DEBUG "Cannot set the memory to rw (%d) at addr %16lX\n", ret, PAGE_ALIGN(addr) - PAGE_SIZE);
}
else
{
printk(KERN_DEBUG "3 pages set to rw");
}
orig_sys_open = syscall_table[__NR_open];
syscall_table[__NR_open] = my_sys_open;
write_cr0(cr0);
return 0;
}
static void __exit syscall_release(void)
{
unsigned long cr0;
cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);
syscall_table[__NR_open] = orig_sys_open;
write_cr0(cr0);
netlink_kernel_release(nl_sk);
}
module_init(syscall_init);
module_exit(syscall_release);
The function 'hello_nl_recv_msg' which is a callback function sends and receives msgs to the process but How can I send msg (i.e. filename) from function 'my_sys_open' to process in user space? and how to wait for response?
Makefile :
obj-m += foo.o
all:
make -C /usr/src/linux-headers-3.2.0-23-generic/ M=$(PWD) modules
clean:
make -C /usr/src/linux-headers-3.2.0-23-generic/ M=$(PWD) clean
Thanks for your time ;)
How can I send msg (i.e. filename) from function 'my_sys_open' to process in user space?
User-space program should create socket AF_NETLINK, address of this socket will be used to send message to it. For detailed info read man netlink.
and how to wait for response?
You can use any standard mechanism for make my_sys_open waiting responce event in hello_nl_recv_msg, e.g. wait_event. Simplified code:
/*
* Whether responce is recieved.
*
* For process concurrent open's this should be map,
* e.g., struct task_struct -> bool.
*/
int have_responce = 0;
DECLARE_WAIT_QUEUE_HEAD(responce_waitqueue); // Waitqueue for wait responce.
static void hello_nl_recv_msg(struct sk_buff *skb)
{
...
if(<detect responce from user program>)
{
have_responce = 1;
wake_up_all(responce_waitqueue);
}
...
}
long my_sys_open(const char __user *filename, int flags, int mode)
{
struct sk_buff *skb_out;
...
have_responce = 0; // clear responce flag
nlmsg_unicast(nl_sk, skb_out, <stored_user_pid>);// send message
wait_event(responce_waitqueue, have_responce); //wait until responce is received
....
}
I am trying to append some data on a packet from kernel space. I have an echo client and server. I type in the command line like: ./client "message" and the server just echoes it back. The server was run with ./server .
Now, the client and server are on two different machines (may be VMs). I am writing a kernel module which runs on the client machine. Its work is to append "12345" after "message" while the packet goes out of the machine. I am presenting the code below.
/*
* This is ibss_obsf_cat.c
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/udp.h>
#include <linux/ip.h>
#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
#define __KERNEL__
/*
* Function prototypes ...
*/
static unsigned int cat_obsf_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static void hex_dump (char str[], int len)
{
}
/*
* struct nf_hook_ops instance initialization
*/
static struct nf_hook_ops cat_obsf_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_IP_POST_ROUTING,
.hook = cat_obsf_begin,
};
/*
* Module init and exit functions.
* No need to worry about that.
*/
static int __init cat_obsf_init (void)
{
printk(KERN_ALERT "cat_obsf module started...\n");
return nf_register_hook(&cat_obsf_ops);
}
static void __exit cat_obsf_exit (void)
{
nf_unregister_hook(&cat_obsf_ops);
printk(KERN_ALERT "cat_obsf module stopped...\n");
}
/*
* Modification of the code begins here.
* Here are all the functions and other things.
*/
static unsigned int cat_obsf_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
unsigned char dt[] = "12345";
unsigned char *tmp;
unsigned char *ptr;
int i, j, len;
if (skb){
iph = ip_hdr(skb);
if (iph && iph->protocol && (iph->protocol == IPPROTO_UDP)){
udph = (struct udphdr *) ((__u32 *)iph + iph->ihl);
data = (char *)udph + 8;
if(ntohs(udph->dest) == 6000){
for (i=0; data[i]; i++);
len = i;
//printk(KERN_ALERT "\nData length without skb: %d", len);
//printk(KERN_ALERT "Data is: %s", data);
//printk(KERN_ALERT "dt size: %lu", sizeof(dt));
//printk(KERN_ALERT "skb->len: %d", skb->len);
tmp = kmalloc(200*sizeof(char), GFP_KERNEL);
memcpy(tmp, data, len);
ptr = tmp + len;
memcpy(ptr, dt, sizeof(dt));
printk(KERN_ALERT "tmp: %s", tmp);
printk(KERN_ALERT "skb->tail: %d", skb->tail);
//skb_put(skb, sizeof(dt));
printk(KERN_ALERT "skb->end: %d", skb->end);
printk(KERN_ALERT "skb->tail: %d", skb->tail);
printk(KERN_ALERT "skb->tail(int): %d", (unsigned int)skb->tail);
//memset(data, 0, len + sizeof(dt));
//memcpy(data, tmp, len + sizeof(dt));
//skb_add_data(skb, tmp, len+sizeof(dt));
printk(KERN_ALERT "Now data is: %s", data);
for(i=0; data[i]; i++);
printk(KERN_ALERT "data length: %d", i);
kfree(tmp);
}
}
}
return NF_ACCEPT;
}
/*
* Nothing to be touched hereafter
*/
module_init(cat_obsf_init);
module_exit(cat_obsf_exit);
MODULE_AUTHOR("Rifat");
MODULE_DESCRIPTION("Module for packet mangling");
MODULE_LICENSE("GPL");
I want to get the "message" to be "message12345" while sending out of the client machine from kernel space. So that the server will get "message12345" and echo it back, and the client will the read just "message12345" But I am having trouble with skb_put() and skb_add_data() functions. I do not understand what error was made by me. If anyone can help me with the code, I will be highly grateful. Thanks in advance. I am also giving the Makefile for convenience. This is for the distribution kernel, not for a built kernel.
#If KERNELRELEASE is defined, we've been invoked from the
#kernel build system and use its language
ifneq ($(KERNELRELEASE),)
obj-m := ibss_obsf_cat.o
#Otherwise we were called directly from the command
#line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
Now I am quite convinced that
skb->end - skb->tail
is so small that I will have to create new packets in kernel space. I have used
alloc_skb()
skb_reserve()
skb_header_pointer()
and other useful skb functions for creating a new skb, but the thing I am running out of idea is that how to route the newly created packet in the packet flowing path. How to use
ip_route_me_harder()
I looked in the xtables-addons package for suggestion, but the function they used is different from the one in linux kernel. Any suggestion is welcomed.
About one year ago for kernel 2.6.26 I did it like this:
// Do we need extra space?
if(len - skb_tailroom(skb) > 0){
// Expand skb tail until we have enough room for the extra data
if (pskb_expand_head(skb, 0, extra_data_len - skb_tailroom(skb), GFP_ATOMIC)) {
// allocation failed. Do whatever you need to do
}
// Allocation succeeded
// Reserve space in skb and return the starting point
your_favourite_structure* ptr = (your_favourite_structure*)
skb_push(skb, sizeof(*ptr));
// Now either set each field of your structure or memcpy into it.
// Remember you can use a char*
}
Don't forget:
Recalculate UDP checksum, because you changed data in the transported data.
Change the field tot_len(total length) in the ip header, because you added data to the packet.
Recalculate the IP header checksum, because you changed the tot_len field.
Extra note:
This is just a simple thing. I see in your code you're allocating tmp as a 200 byte array and using that to store the data of your message. If you send a bigger packet you'll have a hard time debugging this as kernel crashes due to memory overflows are too painful.
I have solved the problem. It was trivial. And all I am going to do is to post my code for future references and discussion.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/route.h>
#undef __KERNEL__
#include <linux/netfilter_ipv4.h>
#define __KERNEL__
#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28
static unsigned int pkt_mangle_begin(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *));
static struct nf_hook_ops pkt_mangle_ops __read_mostly = {
.pf = NFPROTO_IPV4,
.priority = 1,
.hooknum = NF_IP_LOCAL_OUT,
.hook = pkt_mangle_begin,
};
static int __init pkt_mangle_init(void)
{
printk(KERN_ALERT "\npkt_mangle module started ...");
return nf_register_hook(&pkt_mangle_ops);
}
static void __exit pkt_mangle_exit(void)
{
nf_unregister_hook(&pkt_mangle_ops);
printk(KERN_ALERT "pkt_mangle module stopped ...");
}
static unsigned int pkt_mangle_begin (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
unsigned int data_len;
unsigned char extra_data[] = "12345";
unsigned char *temp;
unsigned int extra_data_len;
unsigned int tot_data_len;
unsigned int i;
__u16 dst_port, src_port;
if (skb) {
iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);
if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) {
udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
src_port = ntohs (udph->source);
dst_port = ntohs (udph->dest);
if (src_port == 6000) {
printk(KERN_ALERT "UDP packet goes out");
data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
data_len = skb->len - TOT_HDR_LEN;
temp = kmalloc(512 * sizeof(char), GFP_ATOMIC);
memcpy(temp, data, data_len);
unsigned char *ptr = temp + data_len - 1;
extra_data_len = sizeof(extra_data);
memcpy(ptr, extra_data, extra_data_len);
tot_data_len = data_len + extra_data_len - 1;
skb_put(skb, extra_data_len - 1);
memcpy(data, temp, tot_data_len);
/* Manipulating necessary header fields */
iph->tot_len = htons(tot_data_len + TOT_HDR_LEN);
udph->len = htons(tot_data_len + UDP_HDR_LEN);
/* Calculation of IP header checksum */
iph->check = 0;
ip_send_check (iph);
/* Calculation of UDP checksum */
udph->check = 0;
int offset = skb_transport_offset(skb);
int len = skb->len - offset;
udph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_UDP, 0);
}
}
}
return NF_ACCEPT;
}
module_init(pkt_mangle_init);
module_exit(pkt_mangle_exit);
MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi#gmail.com>");
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space");
MODULE_LICENSE("GPL");
Here the thing is that, I forgot to update the length fields and forgot to update the checksum. Now, if I present the code correctly here, all should go well. There are some
other helper functions which are not included here.