pcap_loop does just wait - c

I'm trying to do a little sniffer using pcap in C like explained here
My problem is that pcap_loop absolutly catch no packets and/or does nothing, my callback function is never called. my guess was the time out value but even if i set it to 20 (ms), nothing changes. It hope it s only a simple error i can't see, but i'll let you guys try to figure it out, cause it's been messing my brain too much !!
Thanks
Nikko
Edit : i choose wlan0 as interface and it works with the program given at the link
My main :
int main(int argc, char* argv[]) {
// interface & err buff
char *dev, errbuff[PCAP_ERRBUF_SIZE];
int i = 0,inum= -1;
// it filters out only packet from this machin
char filter_exp[] = "ip host localhost";
struct bpf_program fp; /* compiled filter program (expression) */
/* typedef, no need for struct ... */
bpf_u_int32 mask;
bpf_u_int32 net;
int num_packets = 10;
// 1.0+ API pcap version
pcap_if_t * alldevs;
pcap_if_t * pdev;
pcap_t * handle;
// 1st argument interface
if(argc == 2) {
dev = argv[1];
printf("Chosen interface : %s\n",dev);
}
//+1.0 api version
if(pcap_findalldevs(&alldevs,errbuff)){
fprintf(stderr,"findalldev failed to retrieve interface\n %s",errbuff);
return(2);
}
if(alldevs == NULL){
fprintf(stderr,"Retrieved interface is null\n");
return(2);
}
// select all interfaces
for(pdev = alldevs; pdev != NULL;pdev = pdev->next) {
printf("Device %d : ",++i);
print_pcap_if_t(pdev);
//print_pcap_addr(pdev->addresses);
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i){
fprintf(stderr,"Device %d not in list.\n",i);
return(2);
}
/* Jump to the selected adapter */
for(pdev=alldevs, i=0; i< inum - 1 ;pdev=pdev->next, i++);
printf("\n-------------------------------------------------\n");
//printf("Chosen device : %s",pdev->name);
//print_pcap_if_t(pdev);
/* activate device */
printf("activating\n");
handle = pcap_open_live(pdev->name,SNAP_LEN,1,1000,errbuff);
if(handle == NULL){
fprintf(stderr,"Could not open device for sniffing");
return(2);
}
/* compile filter */
if(pcap_compile(handle,&fp,filter_exp,0,net) == -1) {
fprintf(stderr,"Could not compile filtering rules");
return(EXIT_FAILURE);
}
/* apply filter */
if(pcap_setfilter(handle,&fp) == -1) {
fprintf(stderr,"Could not set filtering rules");
return(EXIT_FAILURE);
}
printf("Waiting for packets to come in your hands");
fflush(stdout);
pcap_loop(handle,num_packets,got_packet,NULL);
pcap_freecode(&fp);
pcap_close(handle);
pcap_freealldevs(alldevs);
return(0);
}

ip host localhost
"localhost" is the name for the IP address 127.0.0.1; it is not the IP address of your machine on the Internet, it's a special IP address used to send IPv4 packets from your machine to itself (e.g., "ftp localhost" if you want to test the FTP server on your machine by connecting to it from a command prompt on your machine).
Traffic to or from other hosts will not come from, or be sent, to, 127.0.0.1.
If your machine has the IP address 10.0.1.2, for example, try "ip host 10.0.1.2".

Ok i found the problem :
my filter "ip host localhost" aws the reason. I changed it to "ip" and there it was =)
I dont really understand though. What i do is i launch the program, and just refresh a web page after that. So my first request is a GET or stg, with source = localhost , no ? And the response will contains my address also in the destination field. According to man page :
host HOST True if either the IPv4/v6 source or destination of the packet is
HOST.
Would it be that it does no translation of "localhost" when setting the filter ?
Anyway , i hope it could help some others...

Related

Resource temporarily unavailable in gethostbyname()

I was writing my first client in C when I reached the point where I have to send a socket to the server. When i try to get its address I get a
Resource temporarily unavailable
and I can't find what is causing this problem.
dadesSoftConfig->ipServer has inside localhost
struct hostent *ent;
ent = gethostbyname(dadesSoftConfig->ipServidor);
if (ent == NULL) {
int errnum = errno;
fprintf(stderr, "Client finalitzat: %s\n", strerror(errnum));
exit(EXIT_FAILURE);
}
I do not send any socket, wait for any data yet when I do this call , this is happening at the very beginning, even before the register phase of my protocol.
As requested, this is a print of the dadesSoftConfig:
DEBUG_INFO: Nom: SW-01
Mac: 89F107457A36
Server: localhost
Server-port: 2019
And this is how I print it:
void print_software_configuration(TDadesSoftConfig *dades) {
char *msg;
msg = (char *) malloc(sizeof(char) * 75);
if (sprintf(msg, "\tNom: %s \t\tMac: %s \t\tServer: %s \t\tServer-port: %d\n",
dades->nom, dades->mac, dades->ipServidor, dades->serverPort) < 0) {
fprintf(stderr, "No s'ha pogut mostrar el contingut llegit\n");
} else {
print_debug_info(msg);
}
free(msg);
}
I tried sending "127.0.0.1" to gethostbyname() function and the code perfectly works, even when I store it to my struct. Any idea why it doesn't work when sending "localhost"?
As pointed by my prints, the data structure was correct, but the data it contained was not. Info should be displayed separated by \t\t not a \n\t\t.
The problem was solved when setting correctly the delimiters to strtok() function which parses the input.

Why is pcap_datalink() always returning 1 (Ethernet), even on wireless device?

I'm having an issue where by pcap_datalink() is always returning 1. To my understanding this is LINKTYPE_ETHERNET. But, the device I am using is a wireless card and in my case en0.
This is stopping me from putting the card into monitor mode, and stopping my WLAN filters from working. I've tried to run this on both OSX and Linux with the same results. I also run as root.
Here's the part of my code that's causing the problem. For the example, assume dev is set to en0 (wireless device on Mac).
#include <stdio.h>
#include <pcap.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pcap_t *pcap_h;
char *dev, errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
struct pcap_pkthdr header;
const u_char *packet;
if(argc < 2)
{
printf("Usage: %s device\n", argv[0]);
exit(EXIT_FAILURE);
}
dev = argv[1];
if((pcap_h = pcap_create(dev, errbuf)) == NULL)
{
printf("pcap_create() failed: %s\n", errbuf);
exit(EXIT_FAILURE);
}
if(pcap_can_set_rfmon(pcap_h) == 0)
{
printf("Monitor mode can not be set.\n");
}
if(pcap_set_rfmon(pcap_h, 1) != 0)
{
printf("Failed to set monitor mode.\n");
exit(EXIT_FAILURE);
}
if(pcap_activate(pcap_h) != 0)
{
printf("pcap_activate() failed\n");
exit(EXIT_FAILURE);
}
/*
* Compile a filter to sniff 802.11 probe requests
* Filter: type mgt subtype probe-req
*/
if(pcap_compile(pcap_h, &fp, "type mgt subtype probe-req", 0, PCAP_NETMASK_UNKNOWN) == -1)
{
printf("pcap_compile() failed: %s\n", pcap_geterr(pcap_h));
exit(EXIT_FAILURE);
}
/*
* Set the compiled filter
*/
if(pcap_setfilter(pcap_h, &fp) == -1)
{
printf("pcap_setfilter() failed: %s\n", pcap_geterr(pcap_h));
exit(EXIT_FAILURE);
}
pcap_freecode(&fp);
packet = pcap_next(pcap_h, &header);
printf("Header: %d\n", header.len);
pcap_close(pcap_h);
return 0;
}
Any idea's why pcap_datalink() is always returning 1?
Edit
Updated code, and added pcap_set_rfmon() before the call to pcap_activate(). I get an error:
pcap_compile() failed: 802.11 link-layer types supported only on 802.11
Are you shure this is what's is stopping you from putting the card into monitor mode, and stopping your WLAN filters from working, or do you do this call to pcap_datalink() as a check trying to pinpoint the issue?
Be aware that, from PCAP-LINKTYPE(7):
For a live capture or ``savefile'', libpcap supplies, as the
return value of the pcap_datalink(3PCAP) routine, a value that
indicates the type of link-layer header at the beginning of the
packets it provides. This is not necessarily the type of link-layer
header that the packets being captured have on the network from
which they're being captured; for example, packets from an IEEE 802.11
network might be provided by libpcap with Ethernet headers that
the network adapter or the network adapter driver generates from the
802.11 headers.
So I would not take this LINKTYPE_ETHERNET / DLT_EN10MB return value as the sure indication of a problem here.
EDIT:
Also, pcap_set_rfmon() is supposed to be call before the handle is activated, which is not visible in your code.
pcap is rather touchy about the order things should be done. Have a look at the man pages for pcap_can_set_rfmon and pcap_set_rfmon.
The order should be:
pcap_create
pcap_can_set_rfmon
pcap_set_rfmon (if so far so good)
then and only then, pcap_activate

c get server public ip

I would like to know how to get the public ip of my server with C programming language.I already know how to do this with libcurl but now i want to understand how to get this info with the socket programming (if it is possible).I've already tried with struct hostent *hp but i get only the local address 127.0.0.1
This is the code i've used:
int main(int argc, char *argv[]){
struct hostent *hp;
int i=0;
if((hp=gethostbyname(argv[1])) == NULL){
herror("gethostbyname()");
exit(1);
}
fprintf(stdout, "Hostname: %s\n", hp->h_name);
/* fprintf (stdout,"IP server: %s\n",inet_ntoa(*((struct in_addr *)hp->h_addr))); con questa printo solo 1 ip */
while (hp->h_addr_list[i] != NULL) { /* mentre così printo tutti gli eventuali ip */
printf("IP: %s\n", inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i])));
i++;
}
return 0;
}
You can't do it on your own, there's no reliable way. Let's say you're behind a NAT box: you can never know the inside global address (i.e. the public address used by the NAT box). What's more, the NAT box might have multiple public addresses.
This happens because your public address is not your address. The public address is just a mirage, i.e. the way outside hosts perceive you. So it makes sense: you can only find it out by asking outside hosts.
TLDR
Do a request to an outside host:
[cnicutar#fresh ~]$ curl ifconfig.me
192.0.2.42
It is trivial to do it using libcurl or with your own sockets.

get LAN ip and print it

Does anyone know how do I get my LAN IP and print it on the screen.
*I don't mean on shell, but in c programming.
**I will appreciate if you'll post me a sample code.
There's a few approaches; first, you could set up a connection to a known peer using connect(2) and then read the local socket 'name' with getsockname(2). This is a pretty poor mechanism, but it is easy.
But, getsockname(2) will only report one IP address, when a machine may have thousands of IP addresses, and which IP is returned will depend in part upon the peer that you chose! So, not very reliable.
A much better answer is to use rtnetlink(7) to read the IP addresses for the machine directly from the kernel: you would send RTM_GETADDR messages to the kernel for each interface on the machine and read the answers back. Your best bet for understanding how to use this is probably to read the source code for the ip program.
Another option is to use the SIOCGIFCONF ioctl(2) on an IP socket. This interface isn't as flexible as the rtnetlink(7) interface, so it might not always be correct, but it'll be a mid-way point. The ifconfig(8) utility uses this approach for displaying ifconfig -a output. Again, your best bet would be to read the source. (There is some slight documentation in ioctl_list(2).)
The getifaddrs() function from <ifaddrs.h> is the simplest way to get the current interfaces and corresponding addresses:
#include <stdio.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct ifaddrs *iflist, *iface;
if (getifaddrs(&iflist) < 0) {
perror("getifaddrs");
return 1;
}
for (iface = iflist; iface; iface = iface->ifa_next) {
int af = iface->ifa_addr->sa_family;
const void *addr;
char addrp[INET6_ADDRSTRLEN];
switch (af) {
case AF_INET:
addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
break;
default:
addr = NULL;
}
if (addr) {
if (inet_ntop(af, addr, addrp, sizeof addrp) == NULL) {
perror("inet_ntop");
continue;
}
printf("Interface %s has address %s\n", iface->ifa_name, addrp);
}
}
freeifaddrs(iflist);
return 0;
}
gethostbyname should help you to do this. Example:
GetLocalAddress()
{
char ac[80];
// Get my host name
if (gethostname(ac, sizeof(ac)) != -1)
{
printf("Host name: %s\n", ac);
// Find IP addresses
struct hostent* p_he = gethostbyname(ac);
if (p_he != 0)
{
for (int i=0; p_he->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, p_he->h_addr_list[i], sizeof(struct in_addr));
printf("IP address %d: %s\n", i, inet_ntoa(addr));
}
}
}
You might want to filter to remove 127.0.0.1 from the list.

listening using Pcap with timeout

I want to write a small application using Libpcap in C on Linux.
Currently, it starts to sniff and wait for the packets. But that's not what I need actually. I want it to wait for N seconds and then stop listening.
How can I achieve that?
Here is my code:
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
printf("got packet\n);
}
int main()
{
int ret = 0;
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "udp dst port 1500"; /* filter expression */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
}
You should call pcap_breakloop() when you want stop listening. So one way would be to:
setup an alarm to trigger in N seconds,
install a signal handler for SIGALRM signal,
call pcap_breakloop() inside the handler to make pcap_loop() return.
code:
void alarm_handler(int sig)
{
pcap_breakloop(handle);
}
int main()
{
...
alarm(N);
signal(SIGALRM, alarm_handler);
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
}
Note: As for using libpcap's read timeout to do this, it won't and can't work, man pcap explicitly warns against it:
The read timeout cannot be used to cause calls that read packets to return within a limited period of time [...] This means that the read timeout should NOT be used, for example, in an interactive application to allow the packet capture loop to poll for user input periodically, as there's no guarantee that a call reading packets will return after the timeout expires even if no packets have arrived.
If you look at this page from the tcpdump website, you can see the follwing:
Opening the device for sniffing
The task of creating a sniffing session is really quite simple. For this, we use pcap_open_live(). The prototype of this function (from the pcap man page) is as follows:
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,
char *ebuf)
The first argument is the device that we specified in the previous section. snaplen is an integer which defines the maximum number of bytes to be captured by pcap. promisc, when set to true, brings the interface into promiscuous mode (however, even if it is set to false, it is possible under specific cases for the interface to be in promiscuous mode, anyway). to_ms is the read time out in milliseconds (a value of 0 means no time out; on at least some platforms, this means that you may wait until a sufficient number of packets arrive before seeing any packets, so you should use a non-zero timeout). Lastly, ebuf is a string we can store any error messages within (as we did above with errbuf). The function returns our session handler.
If this does not work, let us know.
I have been studying and testing these code fragments for a while. Somewhere, I noticed the observation that when you exit pcap_loop, although you may have seen packets, the exit conditions suggest that you have seen none. I assume from this that all the processing of the packet must occur in the scope of the callback function. So if I want to reset quickly and be ready for another packet, I will need to spawn another process to work on each packet.
Old post but I was researching and came across this.
From the man page for pcap_loop() it specifically says, "It does not return when live read timeouts occur; instead, it attempts to read more packets."
But the man pages for pcap_dispatch() and pcap_next() both indicate they return on timeout.

Resources