I am writing a kernel module which registers a hook with netfilter. The handler is not being called if I ssh/telnet into the machine where the module is loaded.
struct nf_hook_ops my_hook_ops;
my_hook_ops.hook = hook_handler;
my_hook_ops.pf = PF_INET;
my_hook_ops.hooknum = NF_INET_PRE_ROUTING;
my_hook_ops.priority = NF_IP_PRI_FIRST;
nf_register_hook(&my_hook_ops);
The handler function:
unsigned int hook_handler(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
if(!skb)
return NF_ACCEPT;
struct iphdr* ip_header;
struct tcphdr* tcp_header;
union ip_address ipaddr;
printk(KERN_INFO "Entered handler\n");
if(skb->protocol == 8)
return NF_ACCEPT;
// Log the received packet
ip_header = ip_hdr(skb);
tcp_header = tcp_hdr(skb);
ipaddr.saddr = ip_header->saddr;
printk(KERN_INFO "Received packet:\nIP Address: %u.%u.%u.%u\nProtocol: %d\nSource port: %d\nDestination port: %d\n",
ipaddr.a[0],ipaddr.a[1],ipaddr.a[2],ipaddr.a[3],
skb->protocol,
tcp_header->source,
tcp_header->dest);
return NF_ACCEPT;
}
The hook is being called for protocol 8 (Exterior Gateway Protocol). The second printk never gets printed. Am I missing anything?
The protocol used here is different from the IP protocol number as assigned by IANA, for which 8 is for EGP and EGP has been outdated.
The protocol field for sk_buff is defined in , for which 8 is for ETH_P_IP. As your data is allways IP traffic,the first conditional check is always true. So the second part of code never get executed.
A couple of thoughts:
a hook handler takes a (struct skbuff **), not a (struct skbuff *)
following on from the above, skb->protocol doesn't exist. You want either (*skb)->protocol or you want the following idiom:
struct sk_buff *sock_buf = *skb;
if(sock_buff->protocol)
If the packet is an EGP packet, you should not be expecting output from the second printk, because you return before it.
You need to study how sk_buff works, the protocol field initialized by the function `eth_type_trans' which takes on ETH_P_* values. All ETH_P_* values are defined in if_ether. Here are some of these values.
#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
You clearly see that 0x08 is defined for Internet Protocol packet. And your code clearly return in case of 8 (which is IP packet)
if(skb->protocol == 8)
return NF_ACCEPT;
Your ssh/telnet clearly IP packet(s) and rejected by above code. Please use proper protocol defined values defined in if_ethr
Related
I want to use the write sycall for copying a struct
from userspace to kernel.
In both user and kernel space, the struct is defined as
struct packet{
unsigned char packet[256];
int length;
}__attribute__ ((packed));
User space uses a local variable of type struct packet and passes it to the write syscall.
struct packet p;
/* ... (fill in data) */
printf("packet.length: %d\n",packet.length); /* looks correct */
result = write(uartFD, &p, sizeof(struct packet));
The kernel side looks like this, checking for correct length is done, just removed from example.
/* write syscall */
ssize_t packet_write(
struct file *file_ptr,
const char __user *user_buffer,
size_t count, loff_t *position)
{
struct packet p;
int retval;
if (copy_from_user((void*)&p, user_buffer, sizeof(struct packet))){
retval = -EACCES;
goto err;
}
/* looks wrong - different numbers like 96373062 or 96373958 */
printk("packet length: %d\n",p.length);
The opposite direction using read sycall is working as expected:
/* read syscall */
struct packet p;
/* ... (fill in data) */
copy_to_user(user_buffer, (void*)&p, sizeof(struct packet));
/* userspace */
read(uartFD, (void*)&packet, sizeof(struct packet));
What am I doing wrong with write syscall?
(Posted on behalf of the OP).
This is solved - it was my own silly. Both copying an integer and an unsigned char buffer separately was working, so it had to be something about the struct.
One site was packed, the other was not... reusing old code...
I'm trying to send a Hello message from linux kernel after a UDP connect (which calls the function ip4_datagram_connect). Since the protocol number in this message needs to be different than UDP (This is a custom protocol which I'm building with UDP as the base code), I can't use the netpoll API.
So I'm trying to use the functions (picked up from udp_sendmsg())-
ip_make_skb(struct sock *sk,
struct flowi4 *fl4,
int getfrag(void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen,
struct ipcm_cookie *ipc, struct rtable **rtp,
unsigned int flags)
to generate the sk_buff and
int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
to send out the generated sk_buff.
My problem is, the function ip_make_skb requires the pointers *from and length which in the udp_sendmsg function are the pointer to and the length of the data in the user space(+ length of udphdr) and then ip_make_skb() copies the data from the userspace. Since I'm just sending a Hello message from the kernel, this is a wasteful step for me (I don't need any data from the user space).
So can I just set the *from pointer to some dummy location and length to zero(+sizeof(struct udphdr))? If yes, what kind of value for *from will be appropriate?
Or is this completely wrong and I should do something else?
Edit 1: For now, I'm doing this
void *from = "Hello";
This will give me a valid pointer in the memory, but I feel it's a dirty way to do this. Tt works though.
I am trying to to detect the a outgoing packets in my kernel(Netfilter) module. I am using a strcmp function to achieve it. The kernel always crashes after loading my kernel module with strcmp function. I tried removing the strcmp function - loaded without any problem. I hope the problem is with all string function, I also tried strstr() - my system crashed
The logic behind this, Incoming packet will have eth[0-9]+ assigned to "in->name" and "out->name" will be and vice-versa for outgoing packet.
Any insight to detect a outgoing packet? I knew another option is to use output_hook instead of prerouting and postrouting hook. But here I want to mangle both incoming and outgoing packet in different way. Does the kernel version I am using doesn't support string function inside modules?
$ uname -a
Linux vmdsk01 2.6.32-21-generic #32-Ubuntu SMP Fri Apr 16 08:09:38 UTC 2010 x86_64 GNU/Linux
Include Part
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/ip.h>
#include <linux/string.h>
Main Hook
31 unsigned int main_hook(unsigned int hooknum,
32 struct sk_buff *skb,
33 const struct net_device *in,
34 const struct net_device *out,
35 int (*okfn)(struct sk_buff*))
36 {
37 if( strcmp(out->name, "<NULL>") == NULL ) // Outgoing packet must not have <NULL>
38 {
39 printk( KERN_INFO "OUTGOING PACKET");
40 }
41 ....
I also tried replacing line 37 with following, my system hangs
37 if( strstr(out->name, "eth") != NULL ) // Outgoing packet must have eth[0-9]+
You might have NULL pointer in out struct pointer. You may add some sanity checks in main_hook like:
unsigned int main_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff*))
{
if (!out)
return -EINVAL;
if( strncmp(out->name, "<NULL>", IFNAMSIZ) == 0 ) // Outgoing packet must not have <NULL>
{
printk( KERN_INFO "OUTGOING PACKET");
}
....
So I've added check for out pointer and using strncmp instead of strcmp where IFNAMSIZ is size of out->name as defined in include/linux/netdevice.h. Also, str(n)cmp does not return NULL, it returns 0.
Check it and please provide any crash messages.
I understood the issue, the hook function is sequence of iterations like while(1) checking for packet. A iteration may or may not received a packet. If an iteration received a packet, the struct "out" would be available and its members could be accessible; I made a mistake by trying to access a member without checking availability of struct.
The following code fixed the purpose and working fine.
if(out)
{
if( strcmp(out->name, "<NULL>") ) // Outgoing packet must not have <NULL>
{
printk( KERN_INFO "Outgoing Packet");
}
}
struct i2c_algorithm has function pointer template for master_xfer for i2c bus implementation. Where can I find the default function routine of master_xfer in linux kernel source.?
Please someone guide me..
What master_xfer is set to depends on your platform and bus. Look under drivers/i2c/busses/ to find where this function pointer is set. Note that it could be set to NULL.
An example of where it is set is in drivers/i2c/busses/i2c-pxa.c:
static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
Also look at include/linux/i2c.h:
struct i2c_algorithm {
/* If an adapter algorithm can't do I2C-level access, set master_xfer
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
};
:
* An i2c_msg is the low level representation of one segment of an I2C
* transaction. It is visible to drivers in the #i2c_transfer() procedure,
* to userspace from i2c-dev, and to I2C adapter drivers through the
* #i2c_adapter.#master_xfer() method.
*
There is i2c-gpio.c file in /driver/i2c/busses/. In that we are filling master_xfer function with bit_xfer. It does bit banging implementation.
I am trying to capture all of transferred packets on a computer. My code works fine in Windows XP but it only captures outgoing packets on Windows 7 and cannot see incoming packets.
Here is a version of the code which just calculate the size of received packets (it seems big but most of it is just definitions). This code works correctly on Windows XP but nothing happens on Windows 7 (it stuck at recvfrom) (the code is complete and you could give a try on Win7):
#include <Winsock2.h>
#include <Mstcpip.h>
#include <iostream>
#include <string>
using namespace std;
#pragma comment(lib,"Ws2_32.lib")
struct SIP4HEADER
{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short ident; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
u_long saddr; // Source address
u_long daddr; // Destination address
u_int op_pad; // Option + Padding
};
// Error handling parts is removed for clarity
void main()
{
WSAData wsa={0};
WSAStartup(MAKEWORD(2,2),&wsa);
string strIPAddress;
cout << "Enter a local IP address to monitor: ";
cin >> strIPAddress;
SOCKET ListenSocket = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
sockaddr_in sa_in;
sa_in.sin_family = AF_INET;
sa_in.sin_addr.s_addr = inet_addr( strIPAddress.c_str() ); //My local IP address
sa_in.sin_port = htons(0);
bind(ListenSocket,(SOCKADDR *) &sa_in, sizeof(sa_in));
int rcv=RCVALL_IPLEVEL;
DWORD b=0;
WSAIoctl(ListenSocket,SIO_RCVALL,&rcv,sizeof(rcv),0,0,&b,0,0);
char buf[2000];
SIP4HEADER* ih = (SIP4HEADER*)buf;
DWORD ReceivedKBytes = 0;
DWORD t = 0;
while( recvfrom(ListenSocket,buf,_countof(buf),0,NULL,NULL)!=-1 )
{
if(sa_in.sin_addr.s_addr == ih->daddr)
t += ntohs(ih->tlen) ;
// update each 20KB
if(t > 20*1024)
{
t=0;
ReceivedKBytes += 20;
cout << "Received KBs: " << ReceivedKBytes << endl;
}
}
}
The only thing made me suspect was this article on MSDN who says:
A call to the bind function with a raw
socket for the IPPROTO_TCP protocol is
not allowed
but i am using IPPROTO_IP, and bind function documentation also says:
The bind function may also be used to
bind to a raw socket (the socket was
created by calling the socket function
with the type parameter set to
SOCK_RAW)
So it seems this is not the problem. Despite this, I don't get any error from calling bind and other functions in this code. I also omitted calling bind function which causes recvfrom make error 10022 Invalid argument. I also replaced IPPROTO_IP with IPPROTO_TCP but it doesn't help neither.
I am not sure whether I am doing it right or not, but this code works without any problem on Windows XP. Anyway, I am looking for a way to get received and sent packets related to a local IP address on Windows XP/7.
Also:
I am running this code on privileged (admin) mode in Windows 7.
The Winpcap or other third-party libraries is not an available option for me.
I had the same problem. Turned out it was Windows 7 Firewall that stopped the sniffer from seeing inbound data. Turned it off and finally, the code worked.
I run your code on my Win7 and it works. I do see following lines printed out:
Received KBs: 20
Received KBs: 40
Received KBs: 60
Received KBs: 80
Received KBs: 100
Probably check your firewall?