I am writing a kernel module which forms its own packet at ip level and then sends the data . I just want to know how to find the ip address of a local network interface.
There are defined ioctls SIOCGIFADDR (to get if address) and SIOCSIFADDR (to set if address).
All device configuration for IPv4 is done in net/ipv4/devinet.c. You can refer to this source file to get more information.
Wanting to read interface addresses reeks of a design problem. However, if you are looking for determining the preferred source address to use when contacting a remote peer is given in struct rt6_info.rt6i_prefsrc after obtaining it with ip6_route_output. Something along the lines of (with no implied guarantees):
int pick_addr(struct in6_addr *saddr, struct net *net, const struct in6_addr *daddr)
{
struct rt6_info *rt;
struct flowi6 fl6;
int ret;
memset(&fl6, 0, sizeof(fl6));
memcpy(&fl6.daddr, daddr, sizeof(*daddr));
dst = (struct rt6_info *)ip6_route_output(net, NULL /* or sk if you have it */, &fl6);
ret = rt->dst.error;
if (ret == 0)
memcpy(saddr, &rt->rt6i_prefsrc.addr, sizeof(*saddr));
dst_release(&rt->dst);
return ret;
}
We have if_getconfig function available in linux-x.y.z/Documentation/networking/ifenslave.c file which is a very good example of how to use ioctls and fetch address from kernel space
Related
I'm trying to create a firewall in C as a linux kernel module. as part of the firewall, I've implemented a hook function which performs packets inspection inside the PRE_ROUTING hook point.
In the hook function I need to deduce the packet direction based on its source and destination networking devices.
Whenever I try to extract the source and destination devices, in the packet inspection function, a kernel panic occurs and the OS crashes, and I have no idea why (I've followed linux/netfilter.h strictly). I would more than appreciate any help!
The relevant part of the hook function is as below:
unsigned int inspect_packet(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
char *src_device;
char *dst_device;
src_device = state->in->name;
dst_device = state->in->name;
/* Deduce the packets direction by the networking devices direction */
if (src_device[5] == IN_DEVICE_NUM && dst_device[5] == OUT_DEVICE_NUM)
{
/* some code */
}
}
As you can see, I used (as in the header files) the state->in and state->out fields in order to extract the source and destination device of the packet.
Note: The kernel panic certainly occurs from the code above, the rest of the code is irrelevant.
Solution:
As found in the comments above, the mistake which was made is the assumption the destination device of the packet is already assigned when the hook function was called. The assumption is problematic because the hook function is registered in the PRE_ROUTING hook and therefore still has no destination networking device. In order to solve the problem, we can deduce the packet direction just from the source device.
Here is the fixed version of the code:
unsigned int inspect_packet(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
char *src_device;
src_device = state->in->name;
/* Deduce the packets direction just by the source networking device */
if (src_device[5] == IN_DEVICE_NUM)
{
/* some code */
}
}
As proposed in the presentation Security Monitoring with eBPF I'm trying to hook into security_socket_connect.
While my gobpf/bcc based code partly works, I seem not be able to read the IP address in the sockaddr struct.
The relevant part looks like this:
int security_socket_connect_entry(struct pt_regs *ctx, struct socket *sock, struct sockaddr *address, int addrlen)
{
u32 address_family = address->sa_family;
if (address_family == AF_INET) {
struct ipv4_data_t data4 = {.pid = pid};
struct sockaddr_in *addr2 = (struct sockaddr_in *)address;
After that I try to read the IP address in addr2. The first try was:
data4.daddr = addr2->sin_addr.s_addr;
The second try was with bpf_probe_read:
bpf_probe_read(&data4.daddr, sizeof(data4.daddr), (void *)((long)addr2->sin_addr.s_addr));
Both options present the same error:
R9 invalid mem access 'inv'
HINT: The invalid mem access 'inv' error can happen if you try to dereference memory without first using bpf_probe_read() to copy it to the BPF stack. Sometimes the bpf_probe_read is automatic by the bcc rewriter, other times you'll need to be explicit.
A repo with a buildable sample can be found here: socket-connect-bpf
I figured it out thanks to an answer to issue #1858 in the bcc repo.
We have to operate on the pointer, so the IP address can be read like this:
bpf_probe_read(&data4.daddr, sizeof(data4.daddr), &addr2->sin_addr.s_addr);
I want to compare the detected device information ( dev_info of type struct rte_eth_dev_info dev_info ) associated with each port with configured pci device address details ( of type struct rte_pci_addr pciaddr).
for (port = 0; port < nb_sys_ports; port++) {
rte_eth_dev_info_get(port, &dev_info);
}
But In struct struct rte_eth_dev_info, field rte_pci_device *pci_dev has been replaced with field struct rte_device *device.
So how do I obtain the rte_pci_device details from rte_device.
DPDK supports now non-PCI buses, so it's a bit more complicated. But still, there are few examples. Here is a snippet from the Ethtool:
struct rte_pci_device *pci_dev;
rte_eth_dev_info_get(port_id, &dev_info);
if (dev_info.device)
bus = rte_bus_find_by_device(dev_info.device);
if (bus && !strcmp(bus->name, "pci")) {
pci_dev = RTE_DEV_TO_PCI(dev_info.device);
snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
"%04x:%02x:%02x.%x",
pci_dev->addr.domain, pci_dev->addr.bus,
pci_dev->addr.devid, pci_dev->addr.function);
}
Basically, we get the bus of the DPDK port. If it's a PCI, it's safe to use RTE_DEV_TO_PCI() macro. The macro returns a pointer to struct rte_pci_device, which has the PCI address.
I've got the TCP Echo example working well on my hardware, and yesterday figured out how to get a UDP Broadcast working. After further thought, I've realized is that what I really need is to be able to set up a TCP Connection to a Static IP, the idea being that my hardware can connect to a server of some sort and then use that connection for all its transactions. The difference is that whereas the echo example sets up a passive connection, that binds with the incoming source (as I understand it), I want to initiate the connection deliberately to a known IP.
Based on what I found on Wikia Here Here
I've attempted as a base case to implement a function that can send a packet to a Defined IP. I'm simply trying to send a packet to my PC, and I'm looking for it on Wireshark.
void echo_tx_tcp()
{
err_t wr_err = ERR_OK;
struct tcp_pcb *l_tcp_pcb;
l_tcp_pcb = tcp_new();
ip_addr_t dest_ip =
{ ((u32_t)0x0C0C0C2BUL) };
wr_err = tcp_bind(l_tcp_pcb, &dest_ip, 12);
wr_err = tcp_connect(l_tcp_pcb, &dest_ip, 12, echo_accept);
tcp_sent(l_tcp_pcb, echo_sent);
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 1024, PBUF_RAM);
unsigned char buffer_send[1024] = "My Name Is TCP";
p->payload = buffer_send;
p->len = 1024;
p->tot_len = 1024;
wr_err = tcp_write(l_tcp_pcb, p->payload, p->len, 1);
wr_err = tcp_output(l_tcp_pcb);
if(wr_err == ERR_OK)
{
p->len++;
}
return;
}
The last if statement just exists so that I can inspect the wr_err value with a debugger. The err is coming back OK but the packet is not seen on wireshark. My setup is my hardare as well as my PC connected to a router in an isolated manner. The IP Address of the PC locally is 12.12.12.43
Am I missing a step here?
The tcp_write() function will fail and return ERR_MEM if:
The length of the data exceeds the current send buffer size.
The length of the queue of the outgoing segment is larger than the upper limit defined in lwipopts.h.
The number of bytes available in the output queue can be retrieved with the tcp_sndbuf() function.
Potential solution(s):
Try again but send less data.
Monitor the amount of space available in the send buffer and only send (more) data when there is space available in the send buffer.
Suggestions:
tcp_snd_buf() can be used to find out how much send buffer space is available.
tcp_sent() can be implemented with callback function, that will be called when send butter space is available.
I am trying to generate arp requests from within the kernel but I do not understand the difference between the 'target MAC address' and the 'destination MAC address'. The kernel function that I am using is this one:
void arp_send(int type, int ptype, __be32 dest_ip,
struct net_device *dev, __be32 src_ip,
const unsigned char *dest_hw, const unsigned char *src_hw,
const unsigned char *target_hw)
Does anyone know the difference between 'target_hw' (the target MAC address) and 'dst_hw' (the destination MAC address)? For me they should be the same...
The arp_send function is a generic one, used to send both ARP requests and responses.
In your case (ARP request) the target_hw is the information you want to learn, so this field can be ignored (set to NULL, see RFC826 example)
dest_hw will also be NULL - which will result in using broadcast address (see arp_create comment)
I'm assuming IPv4 over Ethernet here. For other Layer2/3 protocols it might look different.