wireless sniffing using pcap, MAC address filter - capture

I am writing a wireless packet sniffer program in C. I have set my wireless interface in monitor mode using airmon-ng, and now i am sniffing on the interface "mon0". I am using linux(ubuntu 10.10).
I want to set MAC address as the filter for the packets.
I have done it as shown below, but it says
"mon0 no IPV4 address assigned"
pcap_lookupnet(dev,&net,&mask,errbuf);
printf("%s\n",errbuf);
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
printf("Couldn't open device %s: %s\n", dev, errbuf);
return 2;
}
if(pcap_compile(handle,&fp,argv[0],0,net)==-1){
fprintf(stderr,"Error calling pcap_compile\n");exit(1);}
if(pcap_setfilter(handle,&fp) == -1){
fprintf(stderr,"Error setting filter\n");exit(1);}
/* The call pcap_loop() and pass our callback function */
pcap_loop(handle, 10, my_callback, NULL);
Please help me, how i can set the filter for MAC address??

"no IPV4 address assigned" is an error from pcap_lookupnet(). All it means is that the network interface on which you're trying to capture does not have an IPv4 address assigned to it. What airmon-ng did was to create a "monitor" interface for the Wi-Fi adapter; the regular network interface for the adapter might have an IP address assigned to it, but the monitor interface won't have one.
The only place where the IP address matters is for ip broadcast filter expressions; if you're not filtering for IPv4 broadcast addresses, which you probably won't be, there's no need to get the IPv4 address. To quote the pcap_compile() man page:
If the netmask of the network on which packets are being captured isn't known to the program, or if packets are being captured on the Linux "any" pseudo-interface that can capture on more than one network, a value of 0 can be supplied; tests for IPv4 broadcast addreses won't be done correctly, but all other tests in the filter program will be OK.
so just pass 0 as the "net" argument to pcap_compile().
If you want to search for packets being sent to a particular MAC address, you can just use wlan dst XX:XX:XX:XX:XX:XX; if you want to search for packets being sent from a particular MAC address, you can just use wlan src XX:XX:XX:XX:XX:XX; if you want to search for packets being sent to or from a particular MAC address, you can just use wlan host XX:XX:XX:XX:XX:XX. If you care about the access point address, rather than the station address, you'll need to use filters such as wlan ra XX:XX:XX:XX:XX:XX or wlan ta XX:XX:XX:XX:XX:XX, at least with newer versions of libpcap. (See the pcap-filter man page or, if you don't have a pcap-filter man page, the tcpdump man page for details.)

Related

Connection between "IFA_CACHEINFO" rtnetlink attribute and "IFA_F_PERMANENT" flag in Linux kernel

If I add a new IPv4 address to a network interface(for example, ip -4 addr add 192.0.2.1/24 dev eth0) without rtnetlink IFA_CACHEINFO attribute and then ask for IPv4 addresses configured on that interface(for example, ip -4 addr show dev eth0), then the rtnetlink result is returned with IFA_F_PERMANENT flag set. How and where in the kernel code are IFA_CACHEINFO attribute and IFA_F_PERMANENT flag connected?
According to this RFC the IFA_F_PERMANENT means that you specified the address yourself (you haven't let Linux come up with an address for you) and Linux will use it even after the interface is rebooted.
The ip command you used did exactly this, so that is why you got the IFA_F_PERMANENT flag and AFAIK it has nothing to do with IFA_CACHEINFO.
The IFA_CACHEINFO attribute and IFA_F_PERMANENT flag are connected in the kernel code by the __rtnl_newlink() function. This function is responsible for allocating a new interface and setting up the IFA_CACHEINFO attributes with the IFA_F_PERMANENT flag set. The function is located in net/core/rtnetlink.c.

Sending MPLS tagged packets from a Linux application

I have written some VPN software which now needs to be able to be able to tag de-tunnelled traffic with MPLS tags.
I've looked at the source of Mausezahn (which can send MPLS packets) and it seems to construct the whole ethernet frame, using various helper functions, and then gives that ethernet frame to the kernel with libnet_write.
staging/send_eth.c:
...
tmpls = libnet_build_mpls(tx.mpls_label,
tx.mpls_exp,
tx.mpls_bos,
tx.mpls_ttl,
NULL,
0,
l,
0);
...
t = libnet_build_ethernet (tx.eth_dst,
tx.eth_src,
tx.eth_type,
tx.eth_payload,
tx.eth_payload_s,
L,
t);
if (t == -1)
{
fprintf(stderr, " mz/create_eth_frame: Can't build Ethernet header: %s\n",
libnet_geterror(l));
exit(EXIT_FAILURE);
}
if (verbose) (void) print_frame_details();
libnet_write(L);
...
My code currently uses an IP-level tunnel interface (e.g. tun0) to deliver packets into the kernel.
If I wish to use MPLS will I need to start using a tap interface instead?
Or is there another way, such as ioctls on tun0's fd?
Or do I need to use libnet_write?

UDP Broadcast sendto failed:"network is unreachable" on linux 2.6.30

I write a program using udp broadcast.Code segment as follows:
struct sockaddr_in broadcast_addr;
socklen_t sock_len=sizeof(broadcast_addr);
bzero(&broadcast_addr,sock_len);
broadcast_addr.sin_family=AF_INET;
broadcast_addr.sin_port=12345;
broadcast_addr.sin_addr.s_addr=inet_addr("255.255.255.255");
int fd=socket(AF_INET,SOCK_DGRAM,0);
int broadcast_enable=1;
setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&broadcast_enable,sizeof(broadcast_enable));
uint8_t send_buf[100];
int ret=sendto(fd,send_buf,sizeof(send_buf),0,
(struct sockaddr*)&broadcast_addr,sock_len);
if(ret==-1)
perror("sendto failed");
output:
sendto failed: Network is unreachable
But when I run "add default gateway" command like " route add default gw 10.10.10.111 ",the error disappears.When setting a new ipaddress to netdev,command as above should be ran,otherwise the error comes. Why? Thanks.
Not sure why 255.255.255.255 isn't working for you. However, I've never used that as a broadcast IP myself. When I send a broadcast packet I usually derive the broadcast IP from my subnet mask, i.e. if your subnet mask is 255.255.255.0 (/24) and say your IP is 192.168.0.5, then to send a UDP broadcast your destination IP should be 192.168.0.255.

getifaddrs to parse only the IP from etherenet interface (eth) or wlan interface

I have used the program which is present in the following link http://www.linuxhowtos.org/manpages/3/getifaddrs.htm .
but it prints all the IP like loopback,eth0,eth1 lo etc
now I need to get only the ip which are active excpet loopback ip
ex
$iffconfig
eth6 Link encap:Ethernet HWaddr 08:00:27:47:99:da
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe47:99da/64 Scope:Link
as the ifconfig gives the active interface and correspoding IPs
what has to be changed in this code to get the above thing working ?
Change
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
with
if (ifa->ifa_addr == NULL)
continue;
if ((strcmp("lo", ifa->ifa_name) == 0) ||
!(ifa->ifa_flags & (IFF_RUNNING)))
continue;
family = ifa->ifa_addr->sa_family;
and add this line just after the other includes
#include <net/if.h>
The added lines just check for "lo" interface name, contained into ifa->ifa_name, and check the flags of the interfaces. Testing IFF_RUNNING bit ( look at net/if.h for further definitions) will return only running interfaces.
If you want to check other feature of the interfaces, just check for this flags (taken from net/if.h)
IFF_UP Interface is running.
IFF_BROADCAST Valid broadcast address set.
IFF_DEBUG Internal debugging flag.
IFF_LOOPBACK Interface is a loopback interface.
IFF_POINTOPOINT Interface is a point-to-point link.
IFF_RUNNING Resources allocated.
IFF_NOARP No arp protocol, L2 destination address not set.
IFF_PROMISC Interface is in promiscuous mode.
IFF_NOTRAILERS Avoid use of trailers.
IFF_ALLMULTI Receive all multicast packets.
IFF_MASTER Master of a load balancing bundle.
IFF_SLAVE Slave of a load balancing bundle.
IFF_MULTICAST Supports multicast
IFF_PORTSEL Is able to select media type via ifmap.
IFF_AUTOMEDIA Auto media selection active.
IFF_DYNAMIC The addresses are lost when the interface goes down.
IFF_LOWER_UP Driver signals L1 up (since Linux 2.6.17)
IFF_DORMANT Driver signals dormant (since Linux 2.6.17)
IFF_ECHO Echo sent packets (since Linux 2.6.25)
EDIT
if you need to discriminate IPV6 GUA and ULA address use this macros
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((__const uint32_t *) (a))[0] & htonl(0x70000000)) \
== htonl (0x20000000))
#endif /* IS ADDR GLOBAL */
#ifndef IN6_IS_ADDR_ULA
#define IN6_IS_ADDR_ULA(a) \
((((__const uint32_t *) (a))[0] & htonl(0xfe000000)) \
== htonl (0xfc000000))
#endif /* IS ADDR ULA */
the parameter must be taken from ((sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;

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