I'm developing a C application using libpcap.
I can capture frames using this code that I developed:
void ethernetCaptureHandler( u_char *args, const struct pcap_pkthdr *packet_header, const u_char *packet_body)
{
struct ether_header *eptr;
eptr = (struct ether_header *) packet_body;
fprintf(stdout,"ethernet header source: %s\n"
,ether_ntoa((const struct ether_addr *)&eptr->ether_shost));
fprintf(stdout," destination: %s\n"
,ether_ntoa((const struct ether_addr *)&eptr->ether_dhost));
}
void *listenEthernetFrame(void *ehternetInterface){ //Thread Handler
struct ether_header *eptr;
char error_buffer[PCAP_ERRBUF_SIZE];
pcap_t *handle;
int timeout_limit = 10000; /* In milliseconds */
char *ethernet = (char *)ehternetInterface;
/* Open device for live capture */
handle = pcap_open_live(
ethernet,
BUFSIZ,
0,
timeout_limit,
error_buffer
);
if (handle == NULL) {
fprintf(stderr, "Could not open device %s: %s\n", ethernet, error_buffer);
return 2;
}
pcap_loop(handle, 0, ethernetCaptureHandler, NULL);
}
ethernetCaptureHandler function can listen to ethernet frames and as you can see I can get mac source and mac destination.
The question is: is there a way to know if the frame is sent or received? (supposing that frame mac source and mac destination doesn't change from node to an other)
Else is there a way to capture just only received frames?
Related
I'm new with Winapi and currently trying to send arp packets using raw sockets. Here is my code:
#include "winsock2.h"
#include "windows.h"
#include "time.h"
#include "stdio.h"
#include "ws2tcpip.h"
#include "conio.h"
#define ETH_HW_ADDR_LEN 6
#define IP_ADDR_LEN 4
#define ARP_FRAME_TYPE 0x0806
#define ETHER_HW_TYPE 1
#define IP_PROTO_TYPE 0x0800
#define OP_ARP_REPLY 2
struct arp_packet {
u_short hw_type; // Hardware type (HTYPE)
u_short prot_type; // Protocol type (PTYPE)
u_char hw_addr_size; // Hardware length (HLEN)
u_char prot_addr_size; // Protocol length (PLEN)
u_short op; // Operation
u_char sndr_hw_addr[ETH_HW_ADDR_LEN]; // Sender hardware address (SHA)
u_char sndr_ip_addr[IP_ADDR_LEN]; // Sender protocol address (SPA)
u_char rcpt_hw_addr[ETH_HW_ADDR_LEN]; // Target hardware address (THA)
u_char rcpt_ip_addr[IP_ADDR_LEN]; // Target protocol address (TPA)
};
void get_ip_addr( struct in_addr* in_addr, char* str ){
struct hostent *hostp;
in_addr->s_addr = inet_addr(str);
if ( in_addr->s_addr == -1 ){
if( (hostp = gethostbyname(str)))
{memcpy (in_addr, hostp->h_addr, hostp->h_length);}
else {
fprintf( stderr, "send_arp: unknown host [%s].\n", str ) ;
exit(1);
}
}
} ; // get_ip_addr
int main()
{
struct in_addr src_in_addr, targ_in_addr;
struct arp_packet pkt;
char *sender_mac = "AA-AA-AA-AA-AA-AA";
char *receiver_mac = "88-9F-FA-6E-64-3Q";
SOCKET s;
int optval;
hostent *server;
WSADATA wsock;
if (WSAStartup(MAKEWORD(2,2),&wsock) != 0)
{
fprintf(stderr,"WSAStartup() failed");
exit(EXIT_FAILURE);
}
printf("Initialised successfully.\n");
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==SOCKET_ERROR)
{
printf("Creation of raw socket failed %d\n.", WSAGetLastError());
return 0;
}
printf("Raw TCP Socket Created successfully.\n");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
{
printf("failed to set socket in raw mode %d\n.", WSAGetLastError());
return 0;
}
printf("Successful.\n");
pkt.hw_type = htons(ETHER_HW_TYPE);
pkt.prot_type = htons(IP_PROTO_TYPE);
pkt.hw_addr_size = ETH_HW_ADDR_LEN;
pkt.prot_addr_size = IP_ADDR_LEN;
pkt.op = htons(OP_ARP_REPLY);
strcpy((char *)pkt.sndr_hw_addr, sender_mac);
strcpy((char *)pkt.rcpt_hw_addr, receiver_mac);
get_ip_addr( &src_in_addr, "192.168.1.53");
get_ip_addr( &targ_in_addr, "192.168.1.113");
memcpy( pkt.sndr_ip_addr, &src_in_addr, IP_ADDR_LEN);
memcpy( pkt.rcpt_ip_addr, &targ_in_addr, IP_ADDR_LEN);
if((sendto(s , (const char* )&pkt , sizeof(pkt), 0, 0, 0))==SOCKET_ERROR)
{
printf("Error sending Packet : %d\n", WSAGetLastError());
}
return 0;
}
As this is just for educational purposes I hardcoded MAC and ip addresses As you can see I'm trying to send ARP reply to some ip address. I'm using cygwin to compile, and the output is:
$ ./test.exe
Initialised successfully.
Raw TCP Socket Created successfully.
Successful.
Error sending Packet : 10057
I've searched and 10057 means Socket is not connected. But I don't know why I'm getting this error. Then I decided to change sendto function to this:
SOCKADDR_IN dest;
if((sendto(s , (const char* )&pkt , sizeof(pkt), 0, (SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
just to see what would have happened, I still got error but it was different 10047. Which means that Address family not supported by protocol family. But in msdn documentation I've seen that This is a possible value when the af parameter is AF_UNSPEC, AF_INET, or AF_INET6 and the type parameter is SOCK_RAW or unspecified I'm using windows 7. Thanks.
I have a linux kernel module that needs to process the data received via netfilter hook as a socket buffer.
The data received on Debian 8 (kernel: 3.16.0) is good but with SlackWare 14.0 (kernel: 3.2.29) the data is incorrect. I do not understand what's wrong. I searched everywhere on the forum and on Google but I never found a solution.
This is my nfilter hook function:
static unsigned int magic_packet_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) {
struct iphdr *iph;
struct tcphdr *tcph;
//Return if empty
if(!skb)
return NF_ACCEPT;
//Get ip header
iph = ip_hdr(skb);
//Check protocol
if(iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;
//Get tcp header
tcph = tcp_hdr(skb);
//Get & check data
char *data;
data = (char *)((unsigned char *)tcph+(tcph->doff*4));
if(!data)
return NF_ACCEPT;
//Print in dmesg
#ifdef DEBUG
printk("anhackit data: %s\n", data);
#endif
//Convert source ip to string
char ip[16];
snprintf(ip, 16, "%pI4", &iph->saddr);
//Convert destination port to string
char port[6];
sprintf(port, "%u", ntohs(tcph->dest));
#ifdef DEBUG
printk("anhackit - magic packet received from %s on port %s !\n", ip, port);
#endif
return NF_ACCEPT;}
I hope someone can help me. Thanks in advance.
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;
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
I am trying to convert hping3 to hping6. hping3 uses Pcap library to receive IPv4 packets. But I need to receive IPv6 packets.
That is possible. libpcap is able to catch anything on the wire.
Example using ETHERTYPE_IPV6:
static u_int16_t ether_packet(u_char *args, const struct pcap_pkthdr *pkthdr, co
nst u_char *p) {
struct ether_header *eptr = (struct ether_header*)p;
assert(pkthdr->caplen <= pkthdr->len);
assert(pkthdr->caplen >= sizeof(struct ether_header));
return eptr->ether_type;
}
// This is the callback. assumes ethernet frame.
static void pcap_callback(u_char *args,const struct pcap_pkthdr* pkthdr,const u_
char* p)
{
const u_int16_t type = ether_packet(args, pkthdr, p);
switch (ntohs(type)) {
case ETHERTYPE_IP:
// handle IPv4
break;
case ETHERTYPE_IPV6:
// handle v6
break;
}
}