Can I access the 4 addresses available in the mac header of the Wireless 802.11 packets? - linux

I am writing a module that hooks a function on OUTPUT hook of the kernel netfilter. I want to access the complete information inside the mac header of the packet esp all the 4 addresses or in some cases 3 addresses of the mac header. I am using the struct sk_buff to get the packet's fields but it does not give any fields other than
ethhdr = (struct ethhdr *)skb_mac_header(skb);
eth_hdr(skb)->h_dest;
eth_hdr(skb)->h_source;
eth_hdr(skb)->h_proto;
these fields.
Can anyone give me some code that can extract them at the OUTPUT hook of the netfilter in Linux where this would be added as a hook function? Or if this is possible anyways?

Related

Where did Wireshark/tcpdump/libpcap intercept packet inside Linux kernel?

According to this, wireshark is able to get the packet before it is dropped (therefore I cannot get such packets by myself). And I'm still wondering the exact location in linux kernel for wireshark to fetch the packets.
The answer goes as "On UN*Xes, it uses libpcap, which, on Linux, uses AF_PACKET sockets." Does anyone have more concrete example to use "AF_PACKET sockets"? If I understand wireshark correctly, the network interface card (NIC) will make a copy of all incoming packets and send it to a filter (berkeley packet filter) defined by the user. But where does this happen? Or am I wrong with that understanding and do I miss anything here?
Thanks in advance!
But where does this happen?
If I understood you correctly - you want to know, where is initialized such socket.
There is pcap_create function, that tries to determine type of source interface, creates duplicate of it and activates it.
For network see pcap_create_interface function => pcap_create_common function => pcap_activate_linux function.
All initialization happens in pcap_activate_linux => activate_new function => iface_bind function
( copy descriptor of device with handlep->device = strdup(device);,
create socket with socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)),
bind socket to device with bind(fd, (struct sockaddr *) &sll, sizeof(sll)) ).
For more detailed information read comments in source files of mentioned functions - they are very detailed.
After initialization all work happens in a group of functions such as pcap_read_linux, etc.
On Linux, you should be able to simply use tcpdump (which leverages the libpcap library) to do this. This can be done with a file or to STDOUT and you specify the filter at the end of the tcpdump command..

How to create a kernel module that can intercept all packets coming to/from a network interface

I have 2 port NIC on my system - eth0 and eth1 as seen by Linux.
I want to intercept all packets coming in/to eth0, send them out through eth1 to an external device connected to the same switch as eth1 is. So I need to slap on an additional header to make it reach the correct external device.
I know that there is a concept of network taps that both the transmit and receive code in the kernel send to, but how do I create one? Also I want to capture not just IP, but all ethernet packets, I know NETFILTER_HOOK would have helped me get me IPv4 packets.
The can be readily implemented with a rx_handler:
static rx_handler_result_t handle_frame(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
struct net_device *whereto_dev;
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb))
return RX_HANDLER_CONSUMED;
*pskb = skb;
whereto_dev = rcu_dereference(skb->dev->rx_handler_data);
skb->dev = whereto_dev;
return RX_HANDLER_ANOTHER; /* Do another round in receive path */
}
They are registered via netdev_rx_handler_register(slave_dev, handle_frame, whereto). See the bonding or my uman driver for example usage.
dev_add_pack would work too, but it seems, apart from af_packet.c, all all-packet-catching users of dev_add_pack have been migrated to use rx_handlers, e.g. https://patchwork.ozlabs.org/patch/367236/. The patch's discussion suggests this might be more effecient.

How to printk with IP address or MAC address in Linux Kernel Source Code

I have to change TCP Congestion Control algorithm a little bit by modifying Linux Kernel Source Code. But to check if the result is correct, I need to log info of MAC or IP address.
I used PRINTK function to print messages for kernel. But I feel hard to print out MAC/IP address of hosts.
printk("%pM \n", mac)
But what is mac refer to?
In TCP source code, I often work with skbuff or sock struct.
Thank you.
UPDATE:
struct iphdr *iph = ip_hdr(skb);
printk(KERN_DEBUG "%pI4", iph->saddr);
Linux documents the printk format specifier extensions in the file Documentation/printk-formats.txt available as part of the kernel's source code. For your example,
IPv4 addresses:
%pI4 1.2.3.4
%pi4 001.002.003.004
%p[Ii][hnbl]
For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
specifiers result in a printed address with ('i4') or without ('I4')
leading zeros.
The parameter passed would be a pointer to the IP address to print (skbuff, socket structure, etc).
Are you looking for something like this?
from arch/xtensa/platforms/iss/network.c:
printk("(%pM) ", lp->mac);
i found it using this command
grep -R "mac)" * | grep printk
It might be easier to help if you could tell us which file/line you are currently working on.

How to extract the MAC address of an interface from witthin a driver code

I'm new to Linux Kernel programming and driver programming. I'm working with madwifi drivers, on Linux with kernel version 2.6.32-37 and wish to extract the MAC address of an interface inside the driver code. I know this information supposed to be found in the netdevice structure fields, but not quite sure which one of them is the right one.
My questions are:
What is the difference between the *dev an the *real?
Which one of them should I use? (they're both in use in different parts of the code and I don't understand when should I use the former and when the latter).
Quoting from http://www.makelinux.net/ldd3/chp-17-sect-3:
unsigned char dev_addr[MAX_ADDR_LEN];
Hardware (MAC) address length and device hardware addresses. The Ethernet address length is six octets (we are referring to the hardware ID of the interface board), and the broadcast address is made up of six 0xff octets; ether_setup arranges for these values to be correct. The device address, on the other hand, must be read from the interface board in a device-specific way, and the driver should copy it to dev_addr. The hardware address is used to generate correct Ethernet headers before the packet is handed over to the driver for transmission. The snull device doesn't use a physical interface, and it invents its own hardware address.
Hope that helps.
There is code in a network driver to access/set MAC address.
There is even a callback defined in net_device_ops
.ndo_set_mac_address = netdev_set_mac_address
It is handled differently on each network device depending on HW registers architecture.
For example for Xilinx AXI MAC address is written to net_device structure and specific HW registers of network controller:
static void axienet_set_mac_address(struct net_device *ndev, void *address)
{
struct axienet_local *lp = netdev_priv(ndev);
if (address)
memcpy(ndev->dev_addr, address, ETH_ALEN);
if (!is_valid_ether_addr(ndev->dev_addr))
eth_random_addr(ndev->dev_addr);
/* Set up unicast MAC address filter set its mac address */
axienet_iow(lp, XAE_UAW0_OFFSET,
(ndev->dev_addr[0]) |
(ndev->dev_addr[1] << 8) |
(ndev->dev_addr[2] << 16) |
(ndev->dev_addr[3] << 24));
axienet_iow(lp, XAE_UAW1_OFFSET,
(((axienet_ior(lp, XAE_UAW1_OFFSET)) &
~XAE_UAW1_UNICASTADDR_MASK) |
(ndev->dev_addr[4] |
(ndev->dev_addr[5] << 8))));
}
So once MAC address is set, commands like ifconfig don't get it from device driver accessing HW registers, but from net_device structure.

Is there a kernel module that returns exactly what a simple 'ifconfig' does?

I'm writing a kernel module that needs information about the local machine's interfaces just like the ones retuned by a simple 'ifconfig' command, I've searched a lot for it, but couldn't find anything
You can get all of that information through the struct net_device one way or another.
As Albert Veli said, you can get this struct net_device pointer using __dev_get_by_name().
If you tell us what information you need specifically we might even be able to point you to the correct fields.
Finding the MAC address is fairly simple:
struct net_device *dev = __dev_get_by_name("eth0");
dev->dev_addr; // is the MAC address
dev->stats.rx_dropped; // RX dropped packets. (stats has more statistics)
Finding the IP address is rather harder, but not impossible:
struct in_device *in_dev = rcu_dereference(dev->ip_ptr);
// in_dev has a list of IP addresses (because an interface can have multiple)
struct in_ifaddr *ifap;
for (ifap = in_dev->ifa_list; ifap != NULL;
ifap = ifap->ifa_next) {
ifap->ifa_address; // is the IPv4 address
}
(None of this was compile tested, so typos are possible.)
See for example the in6_dump_addrs function in net/ipv6/addrconf.c for how to get at addresses. For link properties like link layer address, see core/rtnetlink.c instead. ifconfig and its ioctls are obsolete (on Linux), so better don't think in terms of that now-bug-ridden program.

Resources