Hi I am new to Linux and have a project related to sockets. The problem I'm facing is that when I run the code with inputs eth0 for interface and ip address of my router i.e
./mycode eth0 192.168.1.1 it gives an error
You don't have permission to capture on that device (socket: Operation not permitted)
The code I took from a link is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netinet/if_ether.h>
#include <sys/ioctl.h>
int main(int argc,const char* argv[]) {
// Get interface name and target IP address from command line.
if (argc<2) {
fprintf(stderr,"usage: send_arp <interface> <ipv4-address>\n");
exit(1);
}
const char* if_name=argv[1];
const char* target_ip_string=argv[2];
// Construct Ethernet header (except for source MAC address).
// (Destination set to broadcast address, FF:FF:FF:FF:FF:FF.)
struct ether_header header;
header.ether_type=htons(ETH_P_ARP);
memset(header.ether_dhost,0xff,sizeof(header.ether_dhost));
// Construct ARP request (except for MAC and IP addresses).
struct ether_arp req;
req.arp_hrd=htons(ARPHRD_ETHER);
req.arp_pro=htons(ETH_P_IP);
req.arp_hln=ETHER_ADDR_LEN;
req.arp_pln=sizeof(in_addr_t);
req.arp_op=htons(ARPOP_REQUEST);
memset(&req.arp_tha,0,sizeof(req.arp_tha));
// Convert target IP address from string, copy into ARP request.
struct in_addr target_ip_addr={0};
if (!inet_aton(target_ip_string,&target_ip_addr)) {
fprintf(stderr,"%s is not a valid IP address",target_ip_string);
exit(1);
}
memcpy(&req.arp_tpa,&target_ip_addr.s_addr,sizeof(req.arp_tpa));
// Write the interface name to an ifreq structure,
// for obtaining the source MAC and IP addresses.
struct ifreq ifr;
size_t if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name)) {
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
} else {
fprintf(stderr,"interface name is too long");
exit(1);
}
// Open an IPv4-family socket for use when calling ioctl.
int fd=socket(AF_INET,SOCK_DGRAM,0);
if (fd==-1) {
perror(0);
exit(1);
}
// Obtain the source IP address, copy into ARP request
if (ioctl(fd,SIOCGIFADDR,&ifr)==-1) {
perror(0);
close(fd);
exit(1);
}
struct sockaddr_in* source_ip_addr = (struct sockaddr_in*)&ifr.ifr_addr;
memcpy(&req.arp_spa,&source_ip_addr->sin_addr.s_addr,sizeof(req.arp_spa));
// Obtain the source MAC address, copy into Ethernet header and ARP request.
if (ioctl(fd,SIOCGIFHWADDR,&ifr)==-1) {
perror(0);
close(fd);
exit(1);
}
if (ifr.ifr_hwaddr.sa_family!=ARPHRD_ETHER) {
fprintf(stderr,"not an Ethernet interface");
close(fd);
exit(1);
}
const unsigned char* source_mac_addr=(unsigned char*)ifr.ifr_hwaddr.sa_data;
memcpy(header.ether_shost,source_mac_addr,sizeof(header.ether_shost));
memcpy(&req.arp_sha,source_mac_addr,sizeof(req.arp_sha));
close(fd);
// Combine the Ethernet header and ARP request into a contiguous block.
unsigned char frame[sizeof(struct ether_header)+sizeof(struct ether_arp)];
memcpy(frame,&header,sizeof(struct ether_header));
memcpy(frame+sizeof(struct ether_header),&req,sizeof(struct ether_arp));
// Open a PCAP packet capture descriptor for the specified interface.
char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='\0';
pcap_t* pcap=pcap_open_live(if_name,96,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='\0') {
fprintf(stderr,"%s\n",pcap_errbuf);
}
if (!pcap) {
exit(1);
}
// Write the Ethernet frame to the interface.
if (pcap_inject(pcap,frame,sizeof(frame))==-1) {
pcap_perror(pcap,0);
pcap_close(pcap);
exit(1);
}
// Close the PCAP descriptor.
pcap_close(pcap);
return 0;
}
You need root permissions to do that. Trying running your program as root.
Related
I am trying to get familiar with tuntap devices. I have read the following article:
https://backreference.org/2010/03/26/tuntap-interface-tutorial/
but somehow the code from the article doesn't work.
I have this code:
#include <sys/socket.h> //well get our socket
#include <sys/ioctl.h> //thats our input output control
#include <sys/time.h>
#include <fcntl.h>
#include <asm/types.h> //these are data types liked signed unsingend
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //read write close and stuff
#include <signal.h> //different signals
#include <linux/if_packet.h> //interface for packets
#include <linux/if_ether.h> //interface or ethernet frames
#include <linux/if_arp.h> //interface for arp
#include <linux/if.h>
#include <linux/if_tun.h>
#include <arpa/inet.h>
int tun_alloc(char *dev, int flags) {
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
/* Arguments taken by the function:
*
* char *dev: the name of an interface (or '\0'). MUST have enough
* space to hold the interface name if '\0' is passed
* int flags: interface flags (eg, IFF_TUN etc.)
*/
/* open the clone device */
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
return fd;
}
/* preparation of the struct ifr, of type "struct ifreq" */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
if (*dev) {
/* if a device name was specified, put it in the structure; otherwise,
* the kernel will try to allocate the "next" device of the
* specified type */
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
/* try to create the device */
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
return err;
}
/* if the operation was successful, write back the name of the
* interface to the variable "dev", so the caller can know
* it. Note that the caller MUST reserve space in *dev (see calling
* code below) */
strcpy(dev, ifr.ifr_name);
/* this is the special file descriptor that the caller will use to talk
* with the virtual interface */
return fd;
}
int main(void){
unsigned int seconds = 1;
char tap_name[IFNAMSIZ];
strcpy(tap_name, "tun0");
printf("%s\n", tap_name);
int tap_fd = tun_alloc(tap_name, IFF_TUN);
void *buffer = (void *)(malloc(3000));
printf("%s\n", tap_name);
if(tap_fd < 0){
perror("Allocating interface");
exit(1);
}
int nread;
while(1){
nread = read(tap_fd, buffer, sizeof(buffer));
if (nread < 0){
perror("Nread: ");
close(tap_fd);
free(buffer);
exit(1);
}
printf("Read %d Bytes from devies %s \n", nread, tap_name);
sleep(seconds);
}
}
I executed this program on one terminal and pinged the interface from another terminal.
But when I ping the interface from the command line (ping 192.168.0.24, I have assigned that IP to the interface), on the terminal of the program there's always written "read 8 Bytes from interface", although the number of bytes should vary when I ping the interface. Does anyone see the mistake?
I'm following http://backreference.org/2010/03/26/tuntap-interface-tutorial/
The following code successfully gets a fd (usually 3) when I run it as root, but it does not create a /dev/tun77 device.
Should it?
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <linux/if_tun.h>
#include <linux/ioctl.h>
#define IFNAMSIZ 16
int tun_alloc(char *dev, int flags) {
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
/* Arguments taken by the function:
*
* char *dev: the name of an interface (or '\0'). MUST have enough
* space to hold the interface name if '\0' is passed
* int flags: interface flags (eg, IFF_TUN etc.)
*/
/* open the clone device */
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
return fd;
}
/* preparation of the struct ifr, of type "struct ifreq" */
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
if (*dev) {
/* if a device name was specified, put it in the structure; otherwise,
* the kernel will try to allocate the "next" device of the
* specified type */
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
/* try to create the device */
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
return err;
}
/* if the operation was successful, write back the name of the
* interface to the variable "dev", so the caller can know
* it. Note that the caller MUST reserve space in *dev (see calling
* code below) */
strcpy(dev, ifr.ifr_name);
/* this is the special file descriptor that the caller will use to talk
* with the virtual interface */
return fd;
}
int main(void) {
char tun_name[IFNAMSIZ];
int nread, tun_fd;
char buffer[2048];
/* Connect to the device */
strcpy(tun_name, "tun77");
tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); /* tun interface */
if (tun_fd < 0){
perror("Allocating interface");
exit(1);
} else {
printf("connected to %s on fd: %i\n", tun_name, tun_fd);
}
/* Now read data coming from the kernel */
while (1) {
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
nread = read(tun_fd, buffer, sizeof(buffer));
if (nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("Read %d bytes from device %s\n", nread, tun_name);
}
return EXIT_SUCCESS;
}
Waldner answered this on http://backreference.org/2010/03/26/tuntap-interface-tutorial/ with:
Neither. Network interfaces in Linux don't appear under /dev; the only thing you'll see there is /dev/net/tun, which is the device that should be opened as the first step to create a tun/tap interface.
If you run the sample code, you'll be able to see and configure the interface you create by using "ip link" while the program is running; when the program terminates, the interface disappears.
Alternatively, the interface can be made persistent, as explained, and in that case it will survive program termination.
In any case, no device is created under /dev (apart from the already mentioned /dev/net/tun).
Is there a way how to get an IP address of an interface in Linux using libpcap?
I have found this,
Get IP address of an interface on Linux, but that doesn't use pcap.
Also, in the pcap examples it is said that something like this should get your IP but it gives you your network address.
Using the pcap_findalldevs function:
#include <pcap/pcap.h>
#include <arpa/inet.h>
static char errbuf[PCAP_ERRBUF_SIZE];
int main() {
pcap_if_t *alldevs;
int status = pcap_findalldevs(&alldevs, errbuf);
if(status != 0) {
printf("%s\n", errbuf);
return 1;
}
for(pcap_if_t *d=alldevs; d!=NULL; d=d->next) {
printf("%s:", d->name);
for(pcap_addr_t *a=d->addresses; a!=NULL; a=a->next) {
if(a->addr->sa_family == AF_INET)
printf(" %s", inet_ntoa(((struct sockaddr_in*)a->addr)->sin_addr));
}
printf("\n");
}
pcap_freealldevs(alldevs);
return 0;
}
Output of sudo ./pcap:
eth0: 192.168.2.1
usbmon1:
usbmon2:
usbmon3:
usbmon4:
usbmon5:
any:
lo: 127.0.0.1
I would like to check a network devices status e.g. promiscous mode. Basically like shown with ip a command.
Maybe someone could push me in the right direction?
I want to do this in C for linux so linux specific headers are available.
You need to use the SIOCGIFFLAGS ioctl to retrieve the flags associated with an interface. You can then check if the IFF_PROMISC flag is set:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h> /* ioctl() */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>
#include <unistd.h> /* close() */
#include <linux/if.h> /* struct ifreq */
int main(int argc, char* argv[])
{
/* this socket doesn't really matter, we just need a descriptor
* to perform the ioctl on */
int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
struct ifreq ethreq;
memset(ðreq, 0, sizeof(ethreq));
/* set the name of the interface we wish to check */
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
/* grab flags associated with this interface */
ioctl(fd, SIOCGIFFLAGS, ðreq);
if (ethreq.ifr_flags & IFF_PROMISC) {
printf("%s is in promiscuous mode\n",
ethreq.ifr_name);
} else {
printf("%s is NOT in promiscuous mode\n",
ethreq.ifr_name);
}
close(fd);
return 0;
}
If you want to set the interface to promiscuous mode, you will need root privileges, but you can simply set the field in ifr_flags and use the SIOCSIFFLAGS ioctl:
/* ... */
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(fd, SIOCSIFFLAGS, ðreq);
How can I get the IPv4 address of an interface on Linux from C code?
For example, I'd like to get the IP address (if any) assigned to eth0.
Try this:
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int
main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
/* display result */
printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return 0;
}
The code sample is taken from here.
In addition to the ioctl() method Filip demonstrated you can use getifaddrs(). There is an example program at the bottom of the man page.
If you're looking for an address (IPv4) of the specific interface say wlan0 then
try this code which uses getifaddrs():
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
You can replace wlan0 with eth0 for ethernet and lo for local loopback.
The structure and detailed explanations of the data structures
used could be found here.
To know more about linked list in C this page will be a good starting point.
My 2 cents: the same code works even if iOS:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
showIP();
}
void showIP()
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
}
#end
I simply removed the test against wlan0 to see data.
ps You can remove "family"
I have been in the same issue recently, and this is the code I made up and it works. Make sure to use the name of the network interface, exactly as you have it (could be "eth0" or else).
gotta check if ifconfigcommand beforehand to get the interface name and use it in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void extract_ipaddress()
{
//create an ifreq struct for passing data in and out of ioctl
struct ifreq my_struct;
//declare and define the variable containing the name of the interface
char *interface_name="enp0s3"; //a very frequent interface name is "eth0";
//the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
//Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
size_t interface_name_len=strlen(interface_name);
if(interface_name_len<sizeof(my_struct.ifr_name))
{
memcpy(my_struct.ifr_name,interface_name,interface_name_len);
my_struct.ifr_name[interface_name_len]=0;
}
else
{
perror("Copy name of interface to ifreq struct");
printf("The name you provided for the interface is too long...\n");
}
//provide an open socket descriptor with the address family AF_INET
/* ***************************************************************
* All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
* ***************************************************************
*/
int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
if(file_descriptor==-1)
{
perror("Socket file descriptor");
printf("The construction of the socket file descriptor was unsuccessful.\n");
return -1;
}
//invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
if (myioctl_call==-1)
{
perror("ioctl");
printf("Ooops, error when invoking ioctl() system call.\n");
close(file_descriptor);
return -1;
}
close(file_descriptor);
/* **********************************************************************
* If this completes without error , then the hardware address of the interface should have been returned in the 'my_struct.ifr_addr' which is types as struct sockaddr_in.
* ***********************************************************************/
//extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
/* *** Cast the returned address to a struct 'sockaddr_in' *** */
struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
/* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
printf("IP Address is %s.\n", inet_ntoa(ipaddress->sin_addr));
}
If you don't mind the binary size, you can use iproute2 as library.
iproute2-as-lib
Pros:
No need to write the socket layer code.
More or even more information about network interfaces can be got. Same functionality with the iproute2 tools.
Simple API interface.
Cons:
iproute2-as-lib library size is big. ~500kb.
I found a quite easy way to get ip, by take advantage of using bash command:
hostname -I
but use "hostname -I" natively will print the result on screen, we need to use "popen()" to read result out and save it into a string, here is c code:
#include <stdio.h> // popen
#include "ip_common_def.h"
const char * get_ip()
{
// Read out "hostname -I" command output
FILE *fd = popen("hostname -I", "r");
if(fd == NULL) {
fprintf(stderr, "Could not open pipe.\n");
return NULL;
}
// Put output into a string (static memory)
static char buffer[IP_BUFFER_LEN];
fgets(buffer, IP_BUFFER_LEN, fd);
// Only keep the first ip.
for (int i = 0; i < IP_BUFFER_LEN; ++i)
{
if (buffer[i] == ' ')
{
buffer[i] = '\0';
break;
}
}
char *ret = malloc(strlen(buffer) + 1);
memcpy(ret, buffer, strlen(buffer));
ret[strlen(buffer)] = '\0';
printf("%s\n", ret);
return ret;
}