How to find owner socket of sk_buff in Linux kernel? - linux

I'm trying to find the owner socket of an sk_buff instance, say, skb. My ultimate goal is to find a specific TCP option and somehow let the user space application to know. I plan to set a socket option when I find the TCP option and let the user space app to call getsockopt(). Therefore I need to know the ownership between sk_buff and sock.
I find there is a field in sk_buff:
struct sock *sk;
However, when I try to retrieve this field at tcp_parse_options in tcp_input.c, I always get skb->sk == NULL.
So I'm wondering how can I find the owner here?
Also, I find 3 places that seems to set the owner socket:
http://lxr.free-electrons.com/source/net/ipv4/tcp_input.c?v=3.11#L4181
http://lxr.free-electrons.com/source/net/ipv4/tcp_input.c?v=3.11#L4196
http://lxr.free-electrons.com/source/net/ipv4/tcp_input.c?v=3.11#L4456
I also add a new flag in sk_buff for indicating and set it at tcp_parse_options. Then I check this flag at these three places. But none of them shows the flag is set so that I cannot determine whether to set the socket option.
Any idea or suggestion for this problem?
Thanks in advance!

From the sk_buff (skb) you can get the sock (sk) with something like this:
const struct tcphdr *th = tcp_hdr(skb);
struct sock *sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
if (sk)
struct socket* = sk->sk_socket;
That worked for me. Don't forget to add the right headers.

Related

How the function works cdev_add()?

Do I understand correctly that when the structure is initialized
struct dev_t dev;
dev = MKDEV(major,minor_first);
I create only the device file, it's right to say - to the node. Next, should I indicate how I will work with this device? To do this, you need the function
cdev_add(&my_ch_dev, dev, minor_count);
after
cdev_init(&my_ch_dev ,&dev_fops);
So, I mean that my driver will work with the created node as a character device? Thanks in advance!
Here is the details how it works
dev = MKDEV(major,minor_first);
Still kernel doesn't know whether we selected major/minor number or not, so for this you need to register he device by calling register_chrdev_region()
register_chrdev_region(dev,minor_count,"AYRAT_DEVICE"); so till now number(major/minor) has reserved the name(dev) so that other driver will not get the same name. Next you need to register your driver with kernel.
register with cdev by calling cdev_init(&my_ch_dev ,&dev_fops); Next you need to inform to kernel that we filled all member of struct cdev, so for this use cdev_add().
cdev_add(&my_ch_dev, dev, minor_count);

Define new socket option for use in TCP kernel code

I'm trying to add some functionality to the TCP kernel code (in tcp_input.c). I want the code I've implemented to run only in certain situations. I want to add a control flag, which can be set from a user-space application.
I (think I) need to add a new socket option, so that I can accomplish the following with setsockopt().
kernel space:
if(tcp_flags.simulate_ecn_signal) {
// run code for simulating ecn signal
}
user space:
if(tcp_info.tcpi_retransmits > LIMIT) {
u8 simulate_ecn_signal = 1;
// set the flag, so that the kernel code runs
if (setsockopt(sock, IPPROTO_TCP, TCP_FLAGS, &simulate_ecn_signal, sizeof(simulate_ecn_signal)) < 0)
printf("Can't set data with setsockopt.\n");
}
In the example code above I've added an example flag simulate_ecn_signal which I thought could be a member of a (new) socket option (struct) called tcp_flags (that potentially could contain multiple flag values).
How do I define a new socket option, in order to accomplish this?

Retrieving session Id in linux kernel (Kernel Space)

I want to retrieve the sessionid of the current process in linux kernel (Kernel Space). I saw task_struct has a field sessionid but it is defined only when the macro CONFIG_AUDITSYSCALL is ON. So i tried to build the kernel with this macro ON but still i was not getting the result. Also I tried getting its value from function with CONFIG_AUDITSYSCALL on audit_get_sessionid(current) but was getting either -1 or junk value ( different from getsid(0) method in user space).
I am struck at this point. Any suggestion would be of great help.
You can take a look at the getsid syscall at here: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=kernel/sys.c#l1106
SYSCALL_DEFINE1(getsid, pid_t, pid)
{
struct task_struct *p;
struct pid *sid;
int retval;
rcu_read_lock();
if (!pid)
sid = task_session(current);
else {
...
Which suggest you can use the kernel function task_session() to get the session id.
pid_vnr(task_session(current)); would do what u want!!

Printable IPv6 address and port from struct inet_sock

Do you know any way to print in readable format an ipv6 address and its port from the inet_sock struct?
My question has two parts. One is which are the structure members that have this information and the second is how to print them in readable format.
Thanks!
printk has new modifiers which help printing inet addresses (I think since kernel 2.6.24). So you can try several ways, as an example:
//destination address
printk("%pI6 %d\n", my_inet_socket->pinet6->daddr,
ntohs(my_inet_socket->inet_dport));
//source address
printk("%pI6 %d\n", my_inet_socket->pinet6->saddr,
ntohs(my_inet_socket->inet_sport));
Here's how many modifiers you have and how they print the IPv6 address. You can check http://www.kernel.org/doc/Documentation/printk-formats.txt for more info.
%pI6 0001:0002:0003:0004:0005:0006:0007:0008
%pi6 00010002000300040005000600070008
%pI6c 1:2:3:4:5:6:7:8
For older kernels you need to use NIP6 like this:
//destination address
printk(NIP6_FMT " %d\n", NIP6(my_inet_socket->pinet6->daddr),
ntohs(my_inet_socket->inet_dport));
//source address
printk(NIP6_FMT " %d\n", NIP6(my_inet_socket->pinet6->saddr),
ntohs(my_inet_socket->inet_sport));
As a last note, you can check net/ipv6/tcp_ipv6.c from the kernel itself. It has tons of examples. Hope this helps you

linux raw ethernet socket bind to specific protocol

I'm writing code to send raw Ethernet frames between two Linux boxes. To test this I just want to get a simple client-send and server-receive.
I have the client correctly making packets (I can see them using a packet sniffer).
On the server side I initialize the socket like so:
fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));
where MY_ETH_PROTOCOL is a 2 byte constant I use as an ethertype so I don't hear extraneous network traffic.
when I bind this socket to my interface I must pass it a protocol again in the socket_addr struct:
socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
If I compile and run the code like this then it fails. My server does not see the packet. However if I change the code like so:
socket_address.sll_protocol = htons(ETH_P_ALL);
The server then can see the packet sent from the client (as well as many other packets) so I have to do some checking of the packet to see that it matches MY_ETH_PROTOCOL.
But I don't want my server to hear traffic that isn't being sent on the specified protocol so this isn't a solution. How do I do this?
I have resolved the issue.
According to http://linuxreviews.org/dictionary/Ethernet/ referring to the 2 byte field following the MAC addresses:
"values of that field between 64 and 1522 indicated the use of the new 802.3 Ethernet format with a length field, while values of 1536 decimal (0600 hexadecimal) and greater indicated the use of the original DIX or Ethernet II frame format with an EtherType sub-protocol identifier."
so I have to make sure my ethertype is >= 0x0600.
According to http://standards.ieee.org/regauth/ethertype/eth.txt use of 0x88b5 and 0x88b6 is "available for public use for prototype and vendor-specific protocol development." So this is what I am going to use as an ethertype. I shouldn't need any further filtering as the kernel should make sure to only pick up ethernet frames with the right destination MAC address and using that protocol.
I've worked around this problem in the past by using a packet filter.
Hand Waving (untested pseudocode)
struct bpf_insn my_filter[] = {
...
}
s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
struct sock_fprog pf;
pf.filter = my_filter;
pf.len = my_filter_len;
setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf));
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(protocol);
sll.sll_ifindex = if_nametoindex("eth0");
bind(s, &sll, sizeof(sll));
Error checking and getting the packet filter right is left as an exercise for the reader...
Depending on your application, an alternative that may be easier to get working is libpcap.

Resources