I'm working on a low level sniffer based on libpcap. Everything works perfectly but the assert with pcap_set_rfmon() fails each time. I don't think that I made any mistake to get this result. I post a little snippet of the main function. If you have some ideas about a solution, it would be helpful. I tried with various NICs and dongles but on none of them, the monitor mode can be set.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#define JUMBO_FRAMES_MTU 9000
#define BIGGER_THAN_ALL_MTUS (64*1024)
#define ERR(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char **argv)
{
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle;
if (argc < 2){
ERR("usage : ./prog itf-name\n");
}
/* exiting if strlen of itf > 14 */
if (strlen(argv[1]) > IFNAMSIZ){
ERR("Interface name too long");
}
strncpy(opt_args->device, argv[1], strlen(argv[1]) + 1);
handle = pcap_create(opt_args->device, errbuf);
if (handle == NULL){
(void)fprintf(stderr, "FATAL ERROR : couldn't create sock handle : %s\n", errbuf);
goto fatal_error;
}
/* setting snaplen to 1500 */
assert(pcap_set_snaplen(handle, ETHERNET_MTU) == 0);
assert(pcap_setnonblock(handle, -1, errbuf) != -1);
/* if we can't put the device in monitor mode, so we display a warning
but keep doing the capture */
/* I have a warning here */
if (pcap_can_set_rfmon(handle) != 1){
(void)fprintf(stderr, "WARNING : device can't be set up in monitor mode : %s\n",
pcap_geterr(handle));
} else{
assert(pcap_set_rfmon(handle, 1) == 0);
}
/* we need now to launch the session capture */
if (pcap_activate(handle) < 0){
(void)fprintf(stderr, "FATAL ERROR : couldn't activate PCAP sock : %s\n",
pcap_geterr(handle));
goto fatal_error;
}
/* pcap loop ... */
pcap_close(handle);
return 0;
fatal_error;
pcap_close(handle);
return 1;
}
Related
I've been following the official documentation on creating a TUN device. There's very little documentation, but what even is there does not seem to work. Here's what I have so far:
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
return 7; // tun_alloc_old(dev); // this does not happen, linux docs don't say what tun_alloc_old is anyway
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TUN;
if( *dev ) {
printf("setting ifr.ifr_name to \"%s\"\n", dev);
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
printf("ifr.ifr_name is \"%s\"\n", ifr.ifr_name);
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
perror("ERR");
close(fd);
printf("GOT ERROR: %d\n", err);
return err;
}
printf("past TUNSETIFF error checking\n");
strcpy(dev, ifr.ifr_name);
return fd;
}
int main() {
char name[128];
strcpy(&name, "tun23");
int tun = tun_alloc(name);
printf("tun_alloc: %s id: %d\n", name, tun);
if(tun == -1) return -1;
while(1) {
printf("in loop\n");
char buf[128];
ssize_t readAmount = read(tun, buf, 128);
printf("finished read\n");
if(readAmount == -1) {
printf("read 0 bytes\n");
continue;
}
printf("Read %d: ", readAmount);
for(int i = 0; i < 128; i++) {
printf("%hhx", buf[i]);
}
printf("\n");
}
return tun;
}
Compiler step is gcc -g3 test.c && a.out.
When ran as non-root, I get this output
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
ERR: Operation not permitted
GOT ERROR: -1
tun_alloc: tun23 id: -1
And as root, it successfully gets into the loop, but then the call to read seems to block.
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
past TUNSETIFF error checking
tun_alloc: tun23 id: 3
in loop
(In the event of an XY problem, the reason I'm doing this is to try and make a very simple vpn-like application)
The issue is that while it's blocking in this loop, no TUN devices are created. I am looking in /dev/. I'm not sure how I would give it any bytes to read.
Edit: added a proper perror call and the respective output Operation not permitted, valgrind output, and a couple print statements. Going to try and debug the strcpy error.
Edit: fixed the strcpy error, was pretty simple. Seems to fail in non-root due to a lack of permission to create TUN devices.
I have developped a C program for my embedded Board. This program make the green LED lights on when I push and release the BUTTON.
The green LED is defined under "/sys/class/leds" and the BUTTON is under "/dev/input/event0".
This is the code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
void change_led_state(char *led_path, int led_value)
{
char lpath[64];
FILE *led_fd;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
led_fd = fopen(lpath, "w");
if (led_fd == NULL) {
fprintf(stderr, "simplekey: unable to access led\n");
return;
}
fprintf(led_fd, "%d\n", led_value);
fclose(led_fd);
}
void reset_leds(void)
{
change_led_state(LED_PATH "/" green "/brightness", 0);
}
int configure_leds(void)
{
FILE *l_fd;
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
reset_leds();
exit(0);
}
The compilation is going well.
When I execute the code it shows me this :
Starting simplekey app
File Path: /dev/input/event0
When I push the BUTTON nothing happens and when I release it the LED changes state and it shows me this in the terminal :
BTN pressed
The problem is that the code continue executing until I press CTRL+C to exit.
I just want it to wait until the event ( pressing BUTTON ) happens then change LED state and finally exit automatically.
My question is how to modify the program for this purpose ? I thought about using Threads and Signals but I don't have any idea about them. Thank you!
I presume you are running all this under a system complying either SVr4, or 4.3BSD ot POSIX.1-2001 (or later versions).
You are missing the the check on the read() return value, which is not size_t but rather ssize_t (that is it is signed).
Your code could then be changed like this:
/* ... */
ssize_t rb; /* !!! */
/* ... */
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb <= 0) /* Check for the EOF */
break;
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
Please, refer to the friendly man pages.
I am actually trying to write a small program to catch global keyboard inputs from specific USB keyboards under linux.
I am testing with this piece of code :
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/event2";
struct input_event ev;
ssize_t n;
int fd;
char name[256]= "Unknown";
// int codes[2];
// codes[0] = 58; /* M keycap */
// codes[1] = 49; /* assign to N */
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0)
{
printf("The device on %s says its name is '%s'\n", dev, name);
}
/*
int err = ioctl(fd, EVIOCSKEYCODE, codes);
if (err) {
perror("evdev ioctl");
}*/
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
Ths point is that I don't know how to change some input key by other. I tried by calling write() on currently red event by changing the event code, sent key was still previous one, and I tried to used ioctl with EVIOCSKEYCODE, but the call failed with an "invalid argument" error (and I'm not sure to call it correctly).
How can I change outputed key correctly ?
Use the EVIOCGRAB ioctl to grab the input device, so that by reading the events you consume them. Normally (not-grabbed) the events are not consumed when you read them. The ioctl takes an additional parameter, (int)1 for grabbing, (int)0 for releasing.
To re-inject any events, just write them to the uinput device. See eg. a mouse example here. (The event structures are the same type, you only need to write a struct uinput_user_dev structure to the uinput device first, to describe your new input device (which provides the mapped events).)
In other words, you don't remap: you consume and forward.
while running the code below, one of the CPU cores reaches 100% usage. With or without traffic. What is wrong?
Example code:
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <errno.h>
void my_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char*
packet)
{
//nothing, nothing at all...
//printf("+");
}
int main(int argc,char **argv)
{
int i;
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* descr;
const u_char *packet;
struct bpf_program fp; /* hold compiled program */
bpf_u_int32 maskp; /* subnet mask */
bpf_u_int32 netp; /* ip */
if(argc != 2){
fprintf(stdout, "Usage: %s \"expression\"\n"
,argv[0]);
return 0;
}
/* Now get a device */
dev = pcap_lookupdev(errbuf);
if(dev == NULL) {
fprintf(stderr, "%s\n", errbuf);
exit(1);
}
/* Get the network address and mask */
pcap_lookupnet(dev, &netp, &maskp, errbuf);
/* open device for reading in promiscuous mode */
descr = pcap_open_live(dev, BUFSIZ, 1,-1, errbuf);
if(descr == NULL) {
printf("pcap_open_live(): %s\n", errbuf);
exit(1);
}
/* Now we'll compile the filter expression*/
if(pcap_compile(descr, &fp, argv[1], 0, netp) == -1) {
fprintf(stderr, "Error calling pcap_compile\n");
exit(1);
}
/* set the filter */
if(pcap_setfilter(descr, &fp) == -1) {
fprintf(stderr, "Error setting filter\n");
exit(1);
}
/* loop for callback function */
pcap_loop(descr, -1, my_callback, NULL);
return 0;
}
compile with: gcc example.c -o example -lpcap
run with: ./example "tcp" or the filter you like.
As you can see it is the typical example, the main and the callback function for the loop: pcap_loop(descr, -1, my_callback, NULL);
The callback is empty (useless) but it is just to show that the problem is not in the callback.
You specified timeout -1 here:
descr = pcap_open_live(dev, BUFSIZ, 1,-1, errbuf);
It turns pcap_loop into a busy loop, as poll continuously times out instantly.
Use something like 1000 (milliseconds) if you have no reason for other value.
I want to send a opened file descriptor between two different programs. So I am using ioctl with named pipes to do so. But there I am getting "Invalid argument" error for ioctl().
#include <stropts.h>
#include "accesories.c"
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#define MSGSIZ 63
char *fifo = "fifo";
int send_err(int fd, int errcode, const char *msg)
{
int n;
if ((n = strlen(msg)) > 0)
if (write(fd, msg, n) != n) /* send the error message */
return(-1);
if (errcode >= 0)
errcode = -1; /* must be negative */
if (send_fd(fd, errcode) < 0)
return(-1);
return(0);
}
int send_fd(int fd, int fd_to_send)
{
char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */
buf[0] = 0; /* null byte flag to recv_fd() */
if (fd_to_send < 0) {
buf[1] = -fd_to_send; /* nonzero status means error */
if (buf[1] == 0)
buf[1] = 1; /* -256, etc. would screw up protocol */
} else {
buf[1] = 0; /* zero status means OK */
}
//printf("From the write %d\n",buf[0]);
if (write(fd, buf, 2) != 2)
return(-1);
if (fd_to_send >= 0)
if (ioctl(fd, I_SENDFD, fd_to_send) < 0)
{
printf("Eroor ::: %s\n",strerror(errno));
return(-1);
}
return(0);
}
int main(int argc, char const *argv[])
{
int fd, j, nwrite;
char msgbuf[MSGSIZ+1];
int fd_to_send;
if((fd_to_send = open("vi",O_RDONLY)) < 0)
printf("vi open failed");
if(argc < 2)
{
fprintf(stderr, "Usage: sendmessage msg ... \n");
exit(1);
}
/* open fifo with O_NONBLOCK set */
if((fd = open(fifo, O_WRONLY | O_NONBLOCK)) < 0)
printf("fifo open failed");
/* send messages */
for (j = 1; j < argc; j++)
{
if(strlen(argv[j]) > MSGSIZ)
{
fprintf(stderr, "message too long %s\n", argv[j]);
continue;
}
strcpy(msgbuf, argv[j]);
if((nwrite = write(fd, msgbuf, 6)) == -1)
printf("message write failed");
}
printf("From send_fd %d \n",send_fd(fd,fd_to_send));
exit(0);
}
The file accessories .h only contain some common include files nothing else.
First I am sending a simple message and then calling send_fd which is first sending a 2 byte message and then have to send file descriptor using ioctl(). But it is not.
It looks like linux doesn't support I_SENDFD. The comments indicate that I_SENDFD is in the documentation, but is not actually supported, and results in the error message you encountered. The wikipedia entry for STREAMS states the linux kernel does not have any support for streams. The wikipedia entry does point to a couple of third-party packages that could be used to add streams support, but LiS has not been ported to the 2.6 kernel, and OpenSS7 hasn't had any active development in 4 years.
However, linux does support something similar. This mechanism uses a special message type SCM_RIGHTS to deliver a file descriptor over a UNIX domain socket with sendmsg and obtained from recvmsg. Examples can be found with a simple web search, a complete example seems to be from the book The Linux Programming Interface, with source for sending and receiving.