Insert data in the packet header in kernel - c

I want to insert some data in the header of packet but please guide me how to do that
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <net/ip.h>
struct my_head_struct {
int a;
};
/* This is the structure we shall use to register our function */
static struct nf_hook_ops nfho;
/* Name of the interface we want to drop packets from */
static char *drop_if = "eth0";
/* This is the hook function itself */
unsigned int hook_func(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
unsigned int length,truesize;
printk("Inside the hook function\n");
if (strcmp(in->name, drop_if) == 0) {
struct iphdr *iph = NULL;
struct tcphdr *tcph = NULL;
length = skb->len;
truesize=skb->truesize;
iph = ip_hdr((skb));
tcph = (struct tcphdr *)(skb_network_header((skb)) + ip_hdrlen((skb))); // access tcp header.
printk(KERN_ALERT "INFO: Source IP Address: %pI4\n",&iph->saddr);
printk(KERN_ALERT "INFO: Destination IP Address: %pI4\n",&iph->daddr);
printk(KERN_ALERT "INFO: Source Port: %u.\n",tcph->source);
printk(KERN_ALERT "INFO: Destination Port: %u.\n",tcph->dest);
printk("length is %d\n",length);
printk("truesize is %d\n",truesize);
struct my_head_struct * my_head= NULL;
struct sk_buff *newskb;
newskb = skb_copy_expand(skb, sizeof(struct my_head_struct), 0, GFP_ATOMIC);
if(newskb==NULL)
{
printk("Failed to allocate mem\n");
//return SEND_FAIL_MEMORY;
}
else
{
// /* need add check of newskb value for error control */
my_head->a = 21; //want to push this in new skb
}
printk("Dropped packet on %s...\n", drop_if);
return NF_ACCEPT;
} else {
return NF_ACCEPT;
}
}
/* Initialisation routine */
int init_module()
{
printk("netfilter interface module inserted\n");
/* Fill in our hook structure */
nfho.hook = hook_func; /* Handler function */
nfho.hooknum = 0;// NF_IP_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
return 0;
}
/* Cleanup routine */
void cleanup_module()
{
printk("Netfilter interface module removed\n");
nf_unregister_hook(&nfho);
}
I am getting packet in the kernel netfilter hook and hooki want to put that 21 value in the header of the packet and print the value.
How should i do that.

You can use the control block (skb->cb) of the skb to store your data, it has 40 bytes for your disposal (But the data is not guaranteed to be valid across network layers).
You can do something like:
(struct my_head_struct *)(skb->cb)->a = 21;

Related

How to print correctly a IP using NETFILTER in C

I have the following code, it only catch the packets and prints the IP source and destination:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
static struct nf_hook_ops nfho;
unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
unsigned int src_ip = (unsigned int)ip_header->saddr;
unsigned int dest_ip = (unsigned int)ip_header->daddr;
printk(KERN_INFO "IPs: %u \t to \t %u \n", src_ip, dest_ip);
return NF_ACCEPT;
}
int init_module() { /* Fill in our hook structure */
nfho.hook = hook_func; /* Handler function */
nfho.hooknum = NF_INET_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
return 0;
}
void cleanup_module() {
nf_unregister_hook(&nfho);
}
But, I don't know how to print it correctly (like a IP X.X.X.X) because it shows the following information:
IPs: 16777343 to 16842879
IPs: 4198316624 to 67108884
IPs: 16842879 to 16777343
Can someone help me?
Thanks!
Use %pI4 for the format specifier.
e.g. printk(KERN_DEBUG "IPs: %pI4 \t to \t %pI4 \n", &src_ip, &dest_ip);
This is documented in Documentation/printk-formats.txt.
I think you can you inet_ntoa function to get the readable IP address: https://linux.die.net/man/3/inet_ntoa

Socket code works in main but fails in other function

The first code snippet is just of main all I am doing is calling the outOfMain function
int main(int argc , char* argv[]) {
outOfMain();
}
The second is outOfMain - The code I want to work
void outOfMain() {
printf("%s\n", "project 2 started");
int mpSockDescriptor = mp_socket(AF_INET, SOCK_MPTCP, 0);
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(5233);
serverAddress.sin_addr.s_addr = inet_addr("xxx.xxx.xx.xx");
struct sockaddr* sAddr = (struct sockaddr*)&serverAddress;
int mpConn = mp_connect( mpSockDescriptor, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr));
if(mpConn) {
printf("failure to connect\n");
}
printf("adsf\n");
struct sockaddr_in clientAddress;
clientAddress.sin_family = AF_INET;
clientAddress.sin_port = htons(5233);
clientAddress.sin_addr.s_addr = inet_addr("localhost");
struct mptcp_header mpHeader;
mpHeader.seq_num = 1;
mpHeader.dest_addr = serverAddress;
mpHeader.src_addr = clientAddress;
mpHeader.total_bytes = sizeof("MPREQ 1");
mpHeader.ack_num = 1;
struct packet packing;
packing.header = &mpHeader;
char* sendReq = (char*) malloc(128*sizeof(char));
strcpy(sendReq, "MPREQ 1");
packing.data = (char*) malloc(128*sizeof(char));
strcpy(packing.data, sendReq);
printf("%s\n", packing.data);
printf("%d\n", mpSockDescriptor);
printf("%zu\n",mp_send(mpSockDescriptor, &packing, sizeof(packing), 0));
struct packet packRecv;
printf("adf\n");
printf("%d\n", mpSockDescriptor);
mp_recv(mpSockDescriptor, &packRecv, sizeof(struct packet), 0);
}
Then the third is the header file just to show that I am including outOfMain so the act of calling it isn't giving me the error
#ifndef MPTCP_H
#define MPTCP_H
// C libraries
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// MPTCP macros
#define SOCK_MPTCP 2 // socket type for mptcp connections
#define RWIN 2048 // maximum receiver window
#define MSS 128 // sender maximum segment size
/******************************************************************************
* TCP data structures *
******************************************************************************/
/******************************************************************************
* packet header holds information about the current packet + connection *
******************************************************************************/
void outOfMain();
struct mptcp_header {
struct sockaddr_in dest_addr; // remote destination address
struct sockaddr_in src_addr; // local sender address
int seq_num; // sequence number ( first data byte )
int ack_num; // ACK number ( next expected data byte )
int total_bytes; // total bytes of data to transmit
};
/******************************************************************************
* packet holds information about the data contained + connection *
******************************************************************************/
struct packet {
struct mptcp_header * header; // pointer to packet header
char * data; // segment of data
};
struct sendStruct {
char** buff;
int portNumber;
struct sockaddr_in* cInfo;
};
/******************************************************************************
* TCP wrapper functions *
******************************************************************************/
/******************************************************************************
* receive UDP datagram(s) as TCP packet *
* - returns total bytes of data received *
******************************************************************************/
ssize_t mp_recv ( int sockfd, struct packet * recv_pkt, size_t data_len, int flags );
/******************************************************************************
* send UDP datagram(s) as TCP packet *
* - returns total bytes of data sent *
******************************************************************************/
ssize_t mp_send ( int sockfd, const struct packet * send_pkt, size_t data_len, int flags );
/******************************************************************************
* create connection with hostname, port *
* - returns 0 on success *
******************************************************************************/
int mp_connect( int sockfd, const struct sockaddr * addr, socklen_t addrlen );
/******************************************************************************
* create MPTCP socket *
* - returns socket descriptor for new connection *
******************************************************************************/
int mp_socket ( int domain, int type, int protocol );
/******************************************************************************
* prints packet header information + data load *
* - returns nothing, prints to standard out *
******************************************************************************/
void print_pkt( const struct packet * );
void failSuccess();
#endif // MPTCP_H
What I am doing in order is:
creating a multi-thread socket
Connecting that socket to a specific port and server address.
Sending a specific string to the server
Waiting for a response using mp_recv
What I don't understand is that when this exact same code is inside of main (), it works perfectly. But, when it is not in main(), it has a segfault 11 at the mp_recv function call. So I feel like the solution must have more to do with how C works and not my specific code.
Also, I need to have it outside of main() because I need to be able to use multi-threading.
I feel like I must be missing some elementary lesson in C right now.
You got lucky once, unlucky the other time. You have not initialized struct packet packRecv;.

Nf_hook_ops returns incompatible pointer when assigning to hook_func -C -Linux -Netfilter

I am trying to write my own Netfilter kernel module on Ubuntu 16.04 LTS, I am trying to assign hook_func to nfho.hook but I get the following error:
error: assignment from incompatible pointer type
[-Werror=incompatible-pointer-types]
nfho.hook = hook_func;
I have looked on other solutions, mostly ended up on double checking parameters including changing *skb to **skb. I have read that the parameters might depend on the kernel version but couldn't find how to find out the right parameters to be passed.
How can I get that to work and also how do I check what parameters should be passed in hook_func on my kernel version?
Full code:
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
static struct nf_hook_ops nfho; //struct holding set of hook function options
// function to be called by hook
unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
struct tcphdr *tcp_header;
if (ip_header->protocol == 6)
{
printk(KERN_INFO "TCP Packet\n");
tcp_header = (struct tcphdr *)(skb_transport_header(skb)+20);
printk(KERN_INFO "Source Port: %u\n", tcp_header->source);
}
return NF_ACCEPT;
}
int init_module()
{
nfho.hook = hook_func;
nfho.hooknum = NF_INET_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
return 0;
}

Netfilter kernel module to intercept packets and log them

I had a basic code. This code drops and logs all the incoming and outgoing packets.
I want to write a netfilter kernel module to intercept packets and log them in the kernel logs. It should be able to detect different(show 1 or 2 as example) kinds of TCP based reconnaissance packets. The module should detect these packets and log to kernel logs. I don't want to filter the packets, just identify and log them.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
static struct nf_hook_ops nfho; //struct holding set of hook function options
//function to be called by hook
unsigned int hook_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
printk(KERN_INFO "packet dropped\n"); //log to var/log/messages
return NF_DROP; //drops the packet
}
//Called when module loaded using 'insmod'
int init_module()
{
nfho.hook = hook_func; //function to call when conditions below met
nfho.hooknum = NF_IP_PRE_ROUTING; //called right after packet recieved, first hook in Netfilter
nfho.pf = PF_INET; //IPV4 packets
nfho.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions
nf_register_hook(&nfho); //register hook
return 0; //return 0 for success
}
//Called when module unloaded using 'rmmod'
void cleanup_module()
{
nf_unregister_hook(&nfho); //cleanup – unregister hook
}
First, this module drops only incoming packets. The reason is the following row: nfho.hooknum = NF_IP_PRE_ROUTING;.
About your question: I don't understand what are "based reconnaissance packets", but you can extract all the data from the packet and show them in kernel logs. For example:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
static struct nf_hook_ops nfho; //struct holding set of hook function options
//function to be called by hook
unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb); //you can access to IP source and dest - ip_header->saddr, ip_header->daddr
struct tcphdr *tcp_header;
if (ip_header->protocol == 6) //TCP protocol
{
printk(KERN_INFO "TCP Packet\n");
tcp_header = (struct tcphdr *)(skb_transport_header(skb)+20); //Note: +20 is only for incoming packets
printk(KERN_INFO "Source Port: %u\n", tcp_header->source); //can access dest in the same way
}
return NF_ACCEPT; //accept the packet
}
//Called when module loaded using 'insmod'
int init_module()
{
nfho.hook = hook_func; //function to call when conditions below met
nfho.hooknum = NF_INET_PRE_ROUTING; //called right after packet recieved, first hook in Netfilter
nfho.pf = PF_INET; //IPV4 packets
nfho.priority = NF_IP_PRI_FIRST; //set to highest priority over all other hook functions
nf_register_hook(&nfho); //register hook
return 0; //return 0 for success
}
//Called when module unloaded using 'rmmod'
void cleanup_module()
{
nf_unregister_hook(&nfho); //cleanup – unregister hook
}
You could simply run the ufw firewall utility,
(which you should be running all the time anyway).
start it with:
sudo ufw enable
then to assure it is running :
sudo ufw status
then turn the logging function on :
sudo ufw logging on
then :
cd /var/log
then to view the log :
sudo cat ufw.log
This will give a log of everything that is input/output.

how to move packet from NF_INET_PRE_ROUTING to NF_INET_POST_ROUTING?

I have a kernel module that utilizes netfilter hooks. The goal is to forward packets to another destination. As I can see by design packets coming from outside with daddr set to my servers IP pass through NF_INET_PRE_ROUTING and then suppose to be queued for local application. On NF_INET_PRE_ROUTING I alter specific packets (detect my own protocol) and replace daddr with remote servers IP and saddr with my servers IP. I would like to do it from within kernel module itself but cannot find a way to either move existing packet to another routing point (either NF_INET_FORWARD or NF_INET_LOCAL_OUT or even NF_INET_POST_ROUTING) or to create new packet and insert it into TCP/IP stack as if it is sent from server itself. Currently the packet simply goes to the blackhole after first hook. I do not see it going to any other hooks somehow. How could I do that?
My current code (testing code where remote server is same as client):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/route.h>
#define DEBUG 1
static struct nf_hook_ops nfho;
static __be32 srv_addr = 0x620aa8c0;
static __be32 cli_addr = 0x630aa8c0;
static __be32 rem_addr = 0x630aa8c0;
static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){
struct iphdr *ip_header;
struct tcphdr *tcp_header;
ip_header = (struct iphdr *)skb_network_header(skb);
skb_set_transport_header(skb, ip_header->ihl * 4);
tcp_header = (struct tcphdr *)skb_transport_header(skb);
#if DEBUG > 0
if(tcp_header->dest == ntohs(80) || tcp_header->source == ntohs(80))//(ip_header->saddr == cli_addr || ip_header->saddr == srv_addr || ip_header->saddr == rem_addr) &&
printk(KERN_INFO "[HTTP] Got a packet to %d.%d.%d.%d:%d from %d.%d.%d.%d:%d in hooknum=%d\n",
ip_header->daddr & 0x000000FF,
(ip_header->daddr & 0x0000FF00) >> 8,
(ip_header->daddr & 0x00FF0000) >> 16,
(ip_header->daddr & 0xFF000000) >> 24,
ntohs(tcp_header->dest),
ip_header->saddr & 0x000000FF,
(ip_header->saddr & 0x0000FF00) >> 8,
(ip_header->saddr & 0x00FF0000) >> 16,
(ip_header->saddr & 0xFF000000) >> 24,
ntohs(tcp_header->source),
hooknum);
#endif
if(ip_header->saddr == cli_addr && tcp_header->dest == ntohs(80)){
ip_header->daddr = rem_addr;
ip_header->saddr = srv_addr;
ip_header->check = 0;
ip_send_check(ip_header);
tcp_header->check = 0;
tcp_header->check = tcp_v4_check(skb->len - 4*ip_header->ihl, ip_header->saddr, ip_header->daddr, csum_partial((char *)tcp_header, skb->len - 4*ip_header->ihl,0));
okfn(skb);
return NF_STOP;
}
if(ip_header->saddr == rem_addr && tcp_header->source == ntohs(80)){
ip_header->daddr = cli_addr;
ip_header->saddr = srv_addr;
ip_header->check = 0;
ip_send_check(ip_header);
tcp_header->check = 0;
tcp_header->check = tcp_v4_check(skb->len - 4*ip_header->ihl, ip_header->saddr, ip_header->daddr, csum_partial((char *)tcp_header, skb->len - 4*ip_header->ihl,0));
okfn(skb);
return NF_STOP;
}
return NF_ACCEPT;
}
static int __init init_main(void) {
nfho.hook = hook_func;
nfho.hooknum = 0;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Successfully inserted protocol module into kernel.\n");
#endif
return 0;
}
static void __exit cleanup_main(void) {
nf_unregister_hook(&nfho);
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Successfully unloaded protocol module.\n");
#endif
}
module_init(init_main);
module_exit(cleanup_main);
MODULE_LICENSE("GPL v3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
I couldn't find any way to programmatically forward packets in a more or less proper way.
The only way I found (seems to be very popular solution) is to manually modify all related fields in skb_buff and transmit altered packet through dev_queue_xmit. This way isn't good, because it does not implement finding a good route for packet. F.e. if neighbouring network includes many nodes that actually could be used for packet routing it doesn't seem to be possible to find a proper route from kernel module (or I am not aware of such way). Also source code for kernels TCP/IP stack shows presence of ip_forward function, which is not available from any part of kernel module and my try to reproduce that function ended up in dragging half of TCP/IP stack into module. This function could be ideal option for programmatical packet forwarding since it only takes a few parameters and all will alter all needed parts of packet by itself.
Anyways. My own fixed code now looks like this:
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include "my_mod.h"
#define DRIVER_AUTHOR "AlexKey"
#define DRIVER_DESC "HTTP packets manipulations"
#define DEBUG 1
static struct nf_hook_ops nfho;
static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){
struct iphdr *ip_header;
struct tcphdr *tcp_header;
struct ethhdr *eth_header;
u32 saddr, daddr;
u16 source, dest;
/* Get all the headers */
eth_header = (struct ethhdr *)skb_mac_header(skb);
ip_header = (struct iphdr *)skb_network_header(skb);
skb_set_transport_header(skb, ip_header->ihl * 4);
tcp_header = (struct tcphdr *)skb_transport_header(skb);
/* If the packet source or dest are not 80 then the packet is not for us :) */
if(tcp_header->source != ntohs(80) && tcp_header->dest != ntohs(80))
return NF_ACCEPT;
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Got packet on %d from %d\n", htons(tcp_header->dest), htons(tcp_header->source));
#endif
saddr = ip_header->saddr;
daddr = ip_header->daddr;
source = tcp_header->source;
dest = tcp_header->dest;
/* In link layer header change sender mac to our ethernet mac
and destination mac to sender mac :) ping-pong */
memcpy(eth_header->h_dest,eth_header->h_source,ETH_ALEN);
memcpy(eth_header->h_source,skb->dev->dev_addr,ETH_ALEN);
/* Set new link layer headers to socket buffer */
skb->data = (unsigned char *)eth_header;
skb->len += ETH_HLEN;
/* Setting it as outgoing packet */
skb->pkt_type = PACKET_OUTGOING;
/* Swap the IP headers sender and destination addresses */
memcpy(&ip_header->saddr, &daddr, sizeof(u32));
memcpy(&ip_header->daddr, &saddr, sizeof(u32));
/* If transmission suceeds then report it stolen
if it fails then drop it */
if(dev_queue_xmit(skb)==NET_XMIT_SUCCESS){
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Successfully sent packet\n");
#endif
return NF_STOLEN;
} else {
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Sending failed\n");
#endif
return NF_DROP;
}
}
static int __init init_main(void) {
nfho.hook = hook_func;
nfho.hooknum = 0;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Successfully inserted protocol module into kernel.\n");
#endif
return 0;
}
static void __exit cleanup_main(void) {
nf_unregister_hook(&nfho);
#if DEBUG > 0
printk(KERN_INFO "[HTTP] Successfully unloaded protocol module.\n");
#endif
}
module_init(init_main);
module_exit(cleanup_main);
MODULE_LICENSE("GPL v3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
I would love to hear any modifications to this code.
Alex, I had the exact same problem you had trying to send the mangled skb from kernel. I went through the same thought process, but couldn't find an elegant solution that will properly handle the routing of the outgoing packet. Until I found that I can also use sockets in the kernel.
Create a raw socket in your kernel module using sock_create in socket.h like so:
struct socket *mySock;
if ( sock_create(PF_INET, SOCK_RAW, IPPROTO_RAW, &mySock) != 0 )
{
/* Error creating socket */
}
Once you modified the IP header, you can then use a function to send your skb using sock_sendmsg:
int sock_send(struct socket *sock, struct sockaddr_in *addr, struct iovec *iov, int iovlen, int totalLen)
{
struct msghdr msg;
mm_segment_t oldfs;
int size = 0;
if (sock == NULL || sock->sk == NULL)
{
return 0;
}
msg.msg_flags = 0;
msg.msg_name = addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = iovlen;
/* Set to kernel data segment since sock_sendmsg expects user space pointers */
oldfs = get_fs();
set_fs(KERNEL_DS);
size = sock_sendmsg(sock, &msg, totalLen);
set_fs(oldfs);
return size;
}
Remember with IPPROTO_RAW socket, you must make the IP header yourself, but you already have one in the skb. Now you just have to create and populate the struct iovec array and pass it to sock_send.
For struct sockaddr_in *addr, use the same destination address as the IP header:
struct sockaddr_in addr = { .sin_family = PF_INET,
.sin_port = 0, /* 0 for RAW socket */
.sin_addr = { .s_addr = dstAddr } };
Remember to return NF_DROP or free the skb and return NF_STOLEN to clean it up once you are done with the skb.
The way to do this using kernel hooks is to manually modify all related fields in skb_buff and transmit altered packet through dev_queue_xmit. As you are trying to create a packet "out of thin air" to a destination, you need to be careful with the routing. Assuming that the routing is properly set up from the userspace point of view, all you need to do to enable the packet to fly, is to use ip_route_output() before dev_queue_xmit(). For example:
struct rtable *rt;
struct net *nt;
// do the packet mangling, headers copying here
skb->dev = new_dev; // new_dev is the iface through which to reach the dest
nt = dev_net(skb->dev);
rt = ip_route_output(nt, ip_header->daddr, ip_header->saddr,
RT_TOS(ip_header->tos), skb->dev_ifindex);
skb_dst_set(skb, &(rt->dst));
return NF_ACCEPT; // pass the mangled packet on, business as usual

Resources