Assume that I implemented a kernel driver that parses RX packet and decides to pass it to the user space depending on EthType. What are the "official" ways to do that in the Linux kernel?
The only one that comes on my mind is the user application opens a socket to the kernel and listens on it, while the kernel pushes packets satisfying criteria (eg. specific EthType) in to the socket's buffer. I'm certainly not accurate about this, but I hope you get my point :)
Are there any other ways to do this?
Thanks.
You can achieve your goal by using Netfilter framework. Netfilter framework helps intercept a ingrees/egrees packet. The points where packets can be intercepted inside the Kernel/Network stack are called as HOOKS in Netfilter.We can write a kernel module, which can get hooked at any of these HOOKS. The kernel module must have a function defined by us, which can parse the packet and its headers and than take a decision to whether drop a packet, send it to kernel stack, queue it to user space etc.
The packet of our interest can be intercepted at IP_PREROUTING hook and queued by returning NF_QUEUE from our function. The packets will be queued and can be accessed by any application.
Please go through Netfilter documentation.
Regards,
Roy
When the packet arrives on the NIC, these packets are first copied onto the kernel buffers and then copied onto the user space, which are accessed through the socket() followed by read()/write() calls in the user space. You may want to refer to Kernel Network Flow for more details.
Additionally, NIC can directly copy the packets into the DMA bypassing the CPU. Refer to: What happens after a packet is captured?
Related
I'm trying, finally, to understand eBPF and maybe use it in an upcoming project.
For sake of simplicity I started with reading bcc documentation.
In my project I'll need to send some data over network upon some kernel function calls.
Can that be done without sending the data to userspace first?
I see that I can redirect skbs from one socket to another etc., and I see that I can submit custom data to user space. Is there a way to get the best of both worlds?
EDIT: I'm trying to log some file system events to another server that'll collect this data from multiple machines. Those machines can be fairly busy in some situations. It should be real time and with low latency.
I'd love to avoid going through userspace to prevent copying the data back and forth and to reduce sw overhead as much as possible.
Thank you all!
It seems this question can be summarized to: is it possible to send data over the network from a BPF tracing program (kprobes, tracepoints, etc.)?
The answer to that question is no. As far as I know, there are currently no way to craft and send packets over the network from BPF programs. You can resend a received packet to the network with some helpers, but they are only available to networking BPF programs.
I'm building a HIL/SIL test with Simulink, which tests the Vehicle Control Unit(VCU) from a vehicle. This VCU talks with a Power Distribution Module(PDM) over a J1939 CAN network. The PDM handles the in- and outputs from switches and to actuators and puts the information on the CAN bus. The VCU then knows what the PDM is seeing from connected sensors. In turn, the VCU puts info on the CAN bus on how the PDM should control the connected actuators.
My laptop is hooked to the same CAN bus with a Vector adapter and Simulink.
To test the VCU, I need to mimic the PDM and send messages to the VCU as if I were the PDM. The VCU then has to take the correct actions and control the real PDM accordingly.
Obviously, if I just mimic the PDM, my messages will interfere with those sent from the real PDM. So basically, I need the PDM to shut up and only listen. I do the talking for the PDM. However, the PDM is not configurable in a listen-only mode, so I have to intercept all messages it sends so they never arrive at the VCU.
My idea was that i'd detect(by observing the arbitration field of all messages) when the PDM starts sending, and pull a bit down in the arbitration field. It'd recognise the priority of my 'message' over its own, and it'd stop transmitting. It'd be as if the CAN bus is always to busy to give room to the PDM. This would shut up the PDM without it throwing errors. But other suggestions are welcome.
So (how) is it possible to intercept J1939 CAN messages in MATLAB/Simulink, or with a separate CAN controller?
Here is an idea, how to realize what you are looking for. You need some extra hardware, however.
This is the rough outline:
Setup a CAN-gateway device, which has two independent CAN-interfaces can0 and can1.
Disconnect the PDM from the CAN-bus and connect it to one of the interfaces of your CAN-gateway, e.g. can0
Connect the second interface of the CAN-gateway, can1, to the original CAN-bus, which also includes your laptop and the VCU
Program your CAN-gateway to forward all incoming CAN-frames on can1 to the can0 interface
As you want to ignore all messages from the PDM, simply ignore the CAN-frames coming in on interface can0 and not forward them to can1
Example, how to realize such a CAN-gateway:
Hardware: Use a Raspberry Pi and a CAN extension board with two can-interfaces, such as the PiCAN2 duo board.
Software: Write a small program to forward traffic between the interfaces can0 and can1, using socketcan, which is already included in the Linux kernel.
In case your devices are communicating via the higher layer J1939 transport protocol, you might also need to get the J1939 transport protocol running on the Raspberry Pi. If you are simply using 29-bit indentifiers with a maximum payload of 8 byte of data, this should also not be necessary.
Alternatively, you could also use a more expensive commercial solution, this CAN-Router for example.
Your original idea:
I think what you are envisioning is technically feasible, but might have some other drawbacks.
As the drivers of can controllers typically don't expose interfaces to interactively manipulate CAN-frames while their transmission is still ongoing, you could directly address a can-transceiver from a microcontroller
A few researchers realized a CAN Denial of service attack by turning the first recessive bit in a CAN-frame after the arbitration ID into a dominant bit for certain selected CAN-IDs. They used an Arduino Uno and a Microchip MCP2551 E/P CAN transceiver. The code used is also available online. As this interactive manipulation of CAN-frames during transmission is related to what you are looking for, this could be a good starting point for you.
Still I see some drawbacks, when you silence the PDM this way:
You will not only silence the PDM this way, but also (at least) delay the transmission of other nodes on the CAN-bus with arbitration IDs that have
lower priority than the messages from the PDM
It is very likely that the PDM will go into some error state, when it is not able to successfully send its CAN-frames to the bus after a certain number of retries
Yet another idea:
In case you are able to adapt the software of the VCU, change it in a way that it does not consume the CAN-frames from the PDM, but CAN-frames from your laptop by using different CAN-IDs for the same messages. You will have to change the dbc-file for that purpose.
I'm implementing a kernel module that drives GPIOs. I offer the possibility for the userland to perform actions on it via ioctls, but I'd like to get deeper and set up a "notification" system, where the kernel module will contact directly userland on a detected event. For example, a value change on a GPIO (already notified by interrupt in the kernel module).
The main purpose is to avoid active polling loops in userland, and I really don't know how to interface kernel module and userland to keep speed, efficiency, and more or less passive.
I can't find anything on a good practice in this case. Some people talk about having a character interface (via a file in /dev) and performing a blocking read() from userland, and so get notified when the read returns.
This method should be good enough, but in case of very fast GPIO value changes, the userland would maybe be too slow to handle a notification and finally would be crushed by tons of notifications it can't handle.
So I'm looking for a method like userland callback functions, that could be called from the kernel module on an event.
What do you guys think is the best solution ? Is there any existing way of solving this specific problem ?
Thank you :)
Calling from the kernel to userspace is certainly possible, for instance spawning a userspace process (consider the kernel launches init, udev and some more) or using IPC (netlink and others).
However, this is not what you want.
As people mentioned to you, the way to go is to have a char device and then use standard and well-known select/poll semantics. I don't think you should be worried about this being slow, assuming your userspace program is well-designed.
In fact, this design is so common that there is an existing framework called UIO or Userspace I/O (see here and here).
I'm sorry, I don't know if you could call userland callbacks from kernel space, but you can make your user space application to listen on different signals like SIGKILL, SIGTERM, etc. which you can send to a user space process from kernel space.
There are also SIGUSR1 and SIGUSR2, which are reserved for custom use/implementation. Your application could listen on SIGUSR1 and/or SIGUSR2. Then you only have to check, why you were notified.
I know, it's not exactly what you wanted, but maybe it's a little help. ;)
I finally changed for something else, as spawning userland processes was far too slow and error likely.
I changed my software design to make the userland call an ioctl to get last events. The ioctl is blocking via wait queues, sleeping while the event queue is empty.
Thanks for your answer guys !
IS there a way I can in user-space get notification about a packet being dropped at Layer-2 in 802.11.
According to my understanding what happens is, when a packet is sent out on the medium, there are Layer-2 ACKs which are received if it is delivered correctly (if not,it does the retransmission and ultimately drops the packet if not delivered after several retries..)
I want to be able to access this notification (in user-space)and change the behavior of packet transmission.
I want to be able to send the packet to another host from the FIB rather than dropping the packet.
I have read about libpcap libraries and netfilter hooks which allows me to capture packet and inject them back on the networking stack..
But I'm not able to find hooks (if any, for the wireless stack) to help me capture the packet notification in Layer-2.
Please correct me if I'm not understanding something correctly. Also, any heads-up or links to read would be great.
No, you cannot, at least not using the standardised sockets interfaces. 802.11 is a link layer, and the sockets API is strictly link-layer agnostic: unless it's going to work on all link layers, it's not in sockets. There are good reasons for that: the kind of cross-layer interaction that you envision has been tried many times, and it's always turned out more trouble than it's worth.
You didn't give us any details about the application — but the best solution is most probably to change your application-layer protocol to send explicit acknowledgments, and send your data over the fallback route when you fail to receive an ACK.
Is it possible to have libpcap remove a packet instead of just sniff it as it passes through? I'm wanting to intercept each packet and encapsulate it into a new packet along with measurement data, but both packets (mine and the original) both reach the destination.
It's not possible. You need to write a driver (for your operating system) to make the networking stack filter out packets.
The only way you could do this is by being the only physical path between the sender and receiver and turning off packet forwarding on the interceptor.
If you're capturing wireless traffic, there's nothing you can do. No software library can remove radio waves from the ambient air.
No, libpcap cannot "remove a packet".
It's not quite clear what you want to achieve, but it looks like you want to receive data, add some additional information to it, and republish it. If you are working with a datagram protocol such as UDP, then you might be able to simply resend your augmented data to a different UDP port.
In response to Ben S, you can't remove packets off the air, but you can stop them reaching their destination - using ARP cache poisoning etc.
As others mentioned, you can not use libpcap. libpcap is a passive listener. If you are on Linux, you can use a netfilter, which hooks into iptables. Here is an example of how to do that.
http://www.linuxjournal.com/article/7184