I am very new to the world of Linux kernel networking domain and facing some issue related to the handling of IP packets that have the IP router alert option present in their options section.
I am working with kernel version 5.2.20 which is compiled to X86_64 architecture (let me know if further information is needed).
Preface:
According to RFC 2113, the presence of the IP router alert option in the IP packet header means that (section 2.0):
“The goal, then, is to provide a mechanism whereby routers can intercept packets not addressed to them directly”.
One such protocol that leverages this option, is the RSVP. The situation I am facing is the following:
I have 4 routers in a “row” topology (for the matter and for simpllicity). Lets name them:
R1 —> R2 —> R3 —> R4
R1 is the RSVP tunnel “head”.
R4 is the RSVP tunnel “tail”.
The RSVP goal is to construct a tunnel from R1 —> R4. For that to happen, R1 sends an RSVP message (i.e. – RSVP Path message towards R4). Note: that the source IP of this packet is R1 IP and the destination IP address of this packet is R4 IP.
It should passed and be proccessed by ALL routers along the path, which in this case are R2 & R3 (and finally offcourse R4), just as it says according to the RSVP RFC, section 3.1.3:
“Each RSVP-capable node along the path(s) captures a Path message and processes it to create path state…”
At some point of time, due to network issues, R2 does NOT have a route to R4, i.e. – in the RIB (Routing Information Base) of R2, the address of R4 is not
present, therefor, R2 can NOT “forward” packets (and in particular the RSVP message) towards R4.
The RSVP application on R2, HOWEVER, as mentioned above, due to the presence of the IP router alert option, MUST recive the RSVP Path message that arrives at him (in order to process it, deduce that a new “path” should be considered, and indicate that back to R1 by sending back to him an RSVP Error message).
Now comes the Linux kernel networking part:
When the situation above takes place, i.e. – R2 does NOT have a route to R4, it appears, that the ROUTING logic (phase of the netfilter flow) that this packet traverse within R2 Linux kernel drops the message, thus leaving the RSVP application NOT getting the message even though it should.
While, on the other hand, where the same situation takes place, BUT R2 does HAVE a route to R4 –> the message is passed towards the RSVP application.
Recall, that in BOTH situations, the IP router alert option is present in the IP header packet, however, it seems that in the “problematic” situation, it might
not being considered (or its presence is not “strong enough” to enforce the message to be passed to the RSVP application).
I looked a little into the Linux kernel networking code, and found the following function:
ip_call_ra_chain
(can be found here).
So, in general, there is some “consideration” within the Linux kernel about this situation, i.e. – when the IP router alert is present in the packet header options’ section.
So the questions are:
- Is it some bug in the Linux kernel networking subsystem (i.e. – that the IP router alert option is set in the IP header YET the packet is NOT passed to the proper socket)?
Anyways, I was wondering how this situation can be “fixed” without explictly modifying the Linux kernel source code – so I read a little about the netfiler framework
and on the ability to “extend” the netfilter “packets flow” with the help of some netfilter hook function (which will be implemented within a new Linux kernel module that
I will write and load).
As of my understanding, the “requierments” of such netfilter hook function, in my case will be:
a) It needs to be part of the NF_IP_PRE_ROUTING
chain.
b) It needs (must?) be the very FIRST function in this chain (i.e. – NF_IP_PRI_FIRS
)?
c) It is relevant only for IPv4 packets (in my case) so it should have PF_INET
?
I came up with this “semi-finalized” proposal:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#define MY_PROTOCOL 46 // RSVP protocol number in IP header protocol field
static struct nf_hook_ops nfho;
// Function to check if the IP Router Alert option is set
static bool has_router_alert_option(const struct iphdr *iph)
{
const unsigned char *options;
int optlen;
int opt_off;
if (!(iph->ihl > 5)) {
return false; // No options present
}
optlen = (iph->ihl - 5) * 4;
options = (const unsigned char *)(iph + 1);
for (opt_off = 0; opt_off < optlen; opt_off += options[opt_off + 1] ? options[opt_off + 1] : 1) {
if (options[opt_off] == IPOPT_RA) {
return true; // Router Alert option found
}
}
return false;
}
unsigned int nf_hook_fn(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *iph;
iph = ip_hdr(skb);
if (!iph) {
return NF_ACCEPT;
}
// Check for specific criteria: protocol and Router Alert option
if (iph->protocol == MY_PROTOCOL && has_router_alert_option(iph)) {
// Inject the packet into the relevant socket
struct socket *sock = get_your_target_socket();
if (sock) {
sock_queue_rcv_skb(sock->sk, skb);
return NF_STOLEN; // Packet is taken over by the socket
}
}
return NF_ACCEPT; // Otherwise, let the packet pass normally and return to the netfilter flow
}
static int __init my_module_init(void)
{
nfho.hook = nf_hook_fn;
nfho.hooknum = NF_INET_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &nfho);
return 0;
}
static void __exit my_module_exit(void)
{
nf_unregister_net_hook(&init_net, &nfho);
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Netfilter Hook to pass RSVP packets to their socket");
MODULE_AUTHOR("Guy Avraham");
- The questions here are, if so:
2.1 Is that correct in general? Is it a legitimate approach?
2.2 What I am still missing is the logic to find the “correct” socket to pass the packet to
which should be within the get_your_target_socket()
function – how can I deduce the correct socket?
Appriciate your assitance!
Guy.