How to properly put network interface into promiscuous mode on Linux - c

So how do you do this properly?
I know how to do it by creating socket, then setting IFF_PROMISC flag using ioctl (as explained in "howto check a network devices status in C?" and elsewhere), but this looks flawed at least in theory.
you read flags via ioctl
you update flags
someone else modified flags
you set updated flags via ioctl
Is there a better way or do I simply worry too much?
Later I found that one should add interface to PACKET_MR_PROMISC via setsockopt (which also does not have a race) like this:
void set_promisc(const char *ifname, bool enable)
{
struct packet_mreq mreq = {0};
int sfd;
int action;
if ((sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("unable to open socket");
return;
}
mreq.mr_ifindex = if_nametoindex(ifname);
mreq.mr_type = PACKET_MR_PROMISC;
if (mreq.mr_ifindex == 0) {
perror("unable to get interface index");
return;
}
if (enable)
action = PACKET_ADD_MEMBERSHIP;
else
action = PACKET_DROP_MEMBERSHIP;
if (setsockopt(sfd, SOL_PACKET, action, &mreq, sizeof(mreq)) != 0) {
perror("unable to enter promiscouous mode");
return;
}
close(sfd);
}
Unfortunately this has no effect whatsoever on interface, although it should, if I unserstand the doc correctly. Possibly broken since 2001 (tm)?
Comments in pcap source also complain about this.

PACKET_MR_PROMISC turns on promiscuous mode for the device. That will not be reflected in the status shown by ifconfig as it does not modify the state of the global IFF_PROMISC flag on the device. That does not mean it hasn't been done though. This is how the pcap library works now and the fact that wireshark (and a dozen other utilities) can open a device and see packets not addressed to the local system shows that it works.
There is an internal counter on each device that is incremented each time a process uses PACKET_MR_PROMISC, and decremented when that process goes away. That solves the race you originally described.
From the last link you provided:
> IFF_PROMISC is not set,
It's not supposed to be set.
The correct way to put into promiscuous mode the device to which a
PF_PACKET socket is to do a SOL_PACKET/PACKET_ADD_MEMBERSHIP
"setsockopt()" call with PACKET_MR_PROMISC as the argument (see the
"packet(7)" man page), and that's what libpcap is doing.
The old way of directly setting IFF_PROMISC had problems - to quote the
comment at the front of "pcap-linux.c":
[snipped]

Related

How to use libnl and netlink socket for connect devices to AP programatically?

I'm creating a C library that manages a lot of peripherical of my embedded device. The S.O. used, is a Linux distro compiled with yocto. I'm trying to make some functions to connect my device to wifi (well-know) router, with netlink (using the libnl commands). With the help of this community, I've developed a function able to scan the routers in the area. Some of you know how to use the libnl command to connecting my device to router wifi?
I've developed the following code, that tries to connect to an AP called "Validator_Test" (that have no authentication password). The software return no error, but my device still remain disconnected from the AP. Some of you know what is wrong in my code? Unfortunately, i've not found any example or documentation for this operation.
static int ap_conn() {
struct nl_msg *msg = nlmsg_alloc();
int if_index = if_nametoindex("wlan0"); // Use this wireless interface for scanning.
// Open socket to kernel.
struct nl_sock *socket = nl_socket_alloc(); // Allocate new netlink socket in memory.
genl_connect(socket); // Create file descriptor and bind socket.
int driver_id = genl_ctrl_resolve(socket, "nl80211"); // Find the nl80211 driver ID.
genlmsg_put(msg, 0, 0, driver_id, 0, (NLM_F_REQUEST | NLM_F_ACK), NL80211_CMD_CONNECT, 0);
nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index); // Add message attribute, which interface to use.
nla_put(msg, NL80211_ATTR_SSID, strlen("Validator_Test"), "Validator_Test");
nla_put(msg, NL80211_ATTR_MAC, strlen("00:1e:42:21:e4:e9"), "00:1e:42:21:e4:e9");
int ret = nl_send_auto_complete(socket, msg); // Send the message.
printf("NL80211_CMD_CONNECT sent %d bytes to the kernel.\n", ret);
ret = nl_recvmsgs_default(socket); // Retrieve the kernel's answer. callback_dump() prints SSIDs to stdout.
nlmsg_free(msg);
if (ret < 0) {
printf("ERROR: nl_recvmsgs_default() returned %d (%s).\n", ret, nl_geterror(-ret));
return ret;
}
nla_put_failure:
return -ENOSPC;
}
Thanks to all of you!
Thanks for the code.
Based on your code, I modified and did the test here; it works.
The source code is at:
https://github.com/neojou/nl80211/blob/master/test_connect/src/test_connect_nl80211.c
Some suggestions for this:
Make sure the test environment is correct
Before test the code, maybe you can try to use iw to do the test.
iw is the open source tool, which uses netlink also.
you can type "sudo iw wlan0 connect Validator_Test"
and then use iwconfig to see if it is connected or not first.
( Suppose there is no security setting at the AP as you said )
there are two differences between your source code and mine
(1) don't need to set NL80211_ATTR_MAC
(2) ret = nl_recvmsgs_default(socket);
not sure if there is any judgement of the return value of your ap_conn(),
but it seems better to return 0 in ap_conn(), when nl_recvmsgs_default() returns 0.

Faking an input device for testing purpose

What I want to do
I'm writing a daemon which listen to the input devices for keys presses and send signals via D-Bus. The main goal is to manage audio volume and screen backlight level by requesting changes or informing about changes.
I use libevdev to handle the input device events.
I wrote a function for opening an input device located at a specified path:
Device device_open(const char *path);
That function works well, but while I'm writing unit tests for it, I wanted to create file fixtures with different properties (existence of the file, read access, etc.) to check the error handling of my function and memory management (as I store data in a structure).
What I have already done
But testing it with a real input device (located at /dev/input/event*) needs root access rights. Setting read access for everyone on /dev/input/event* files works but seems risky to me. Executing my tests as root is worse !
Creating a device using mknod works but needs to be done as root.
I also tried to use character special files (because input devices are one of those) allowing read for everyone (like /dev/random, /dev/zero, /dev/null and even the terminal device i'm currently using: /dev/tty2).
But those devices does not handles ioctl requests needed by libevdev: EVIOCGBIT is the first request returning an error "Inappropriate ioctl for device".
What I'm looking for
I want to be able to create device files as a regular user (the user executing the unit tests). Then, by setting access rights I should be able to test my function behavior for different kinds of file (read only, no read allowed, bad device type, etc.).
If it appears to be impossible, I will certainly refactor my function using private helpers. But how to do it. Any examples ?
Thanks.
Edit: I tried to express better my needs.
Create a group for users who are allowed to access the device, and an udev rule to set the ownership of that input event device to that group.
I use teensy (system) group:
sudo groupadd -r teensy
and add each user into it using e.g.
sudo usermod -a -g teensy my-user-name
or whatever graphical user interface I have available.
By managing which users and service daemons belong to the teensy group, you can easily manage the access to the devices.
For my Teensy microcontrollers (that have native USB, and I use for HID testing), I have the following /lib/udev/rules.d/49-teensy.rules:
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", GROUP:="teensy", MODE:="0660"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", GROUP:="teensy", MODE:="0660"
You only need the third line (SUBSYSTEMS=="usb", one) for HID devices, though. Make sure the idVendor and idProduct match your USB HID device. You can use lsusb to list the currently connected USB devices vendor and product numbers. The matching uses glob patterns, just like file names.
After adding the above, don't forget running sudo udevadm control --reload-rules && sudo udevadm trigger to reload the rules. Next time you plug in your USB HID device, all members of your group (teensy in the above) can access it directly.
Note that by default in most distributions, udev also creates persistent symlinks in /dev/input/by-id/ using the USB device type and serial. In my case, one of my Teensy LC's (serial 4298820) with a combined keyboard-mouse-joystic device provides /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-event-kbd for the keyboard event device, /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if01-event-mouse for the mouse event device, and /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if03-event-joystick and /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if04-event-joystick for the two joystick interfaces.
(By "persistent", I do not mean these symlinks always exist; I mean that whenever that particular device is plugged in, the symlink of exactly that name exists, and points to the actual Linux input event character device.)
The Linux uinput device can be used to implement a virtual input event device using a simple privileged daemon.
The process to create a new virtual USB input event device goes as follows.
Open /dev/uinput for writing (or reading and writing):
fd = open("/dev/uinput", O_RDWR);
if (fd == -1) {
fprintf(stderr, "Cannot open /dev/uinput: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
The above requires superuser privileges. However, immediately after opening the device, you can drop all privileges, and have your daemon/service run as a dedicated user instead.
Use the UI_SET_EVBIT ioctl for each event type allowed.
You will want to allow at least EV_SYN; and EV_KEY for keyboards and mouse buttons, and EV_REL for mouse movement, and so on.
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1 ||
ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1 ||
ioctl(fd, UI_SET_EVBIT, EV_REL) == -1) {
fprintf(stderr, "Uinput event types not allowed: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
I personally use a static constant array with the codes, for easier management.
Use the UI_SET_KEYBIT ioctl for each key code the device may emit, and UI_SET_RELBIT ioctl for each relative movement code (mouse code). For example, to allow space, left mouse button, horizontal and vertical mouse movement, and mouse wheel:
if (ioctl(fd, UI_SET_KEYBIT, KEY_SPACE) == -1 ||
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_X) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_Y) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_WHEEL) == -1) {
fprintf(stderr, "Uinput event types not allowed: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
Again, static const arrays (one for UI_SET_KEYBIT and one for UI_SET_RELBIT codes) is much easier to maintain.
Define a struct uinput_user_dev, and write it to the device.
If you have name containing the device name string, vendor and product with the USB vendor and product ID numbers, version with a version number (0 is fine), use
struct uinput_user_dev dev;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
if (write(fd, &dev, sizeof dev) != sizeof dev) {
fprintf(stderr, "Cannot write an uinput device description: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
Later kernels have an ioctl to do the same thing (apparently being involved in systemd development causes this kind of drain bamage);
struct uinput_setup dev;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
if (ioctl(fd, UI_DEV_SETUP, &dev) == -1) {
fprintf(stderr, "Cannot write an uinput device description: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
The idea seems to be that instead of using the former, you can try the latter first, and if it fails, do the former instead. You know, because a single interface might some day not be enough. (That's what the documentation and commit say, anyway.)
I might sound a bit cranky, here, but that's just because I do subscribe to both the Unix philosophy and the KISS principle (or minimalist approach), and see such warts completely unnecessary. And too often coming from the same loosely related group of developers. Ahem. No personal insult intended; I just think they are doing poor job.
Create the virtual device, by issuing an UI_DEV_CREATE ioctl:
if (ioctl(fd, UI_DEV_CREATE) == -1) {
fprintf(stderr, "Cannot create the virtual uinput device: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
At this point, the kernel will construct the device, provide the corresponding event to the udev daemon, and the udev daemon will construct the device node and symlink(s) according to its configuration. All this will take a bit of time -- a fraction of a second in the real world, but enough that trying to emit events immediately might cause some of them to be lost.
Emit the input events (struct input_event) by writing to the uinput device.
You can write one or more struct input_events at a time, and should never see short writes (unless you try to write a partial event structure). Partial event structures are completely ignored. (See drivers/input/misc/uinput.c:uinput_write() uinput_inject_events() for how the kernel handles such writes.)
Many actions consists of more than one struct input_event. For example, you might move the mouse diagonally (emitting both { .type == EV_REL, .code == REL_X, .value = xdelta } and { .type == EV_REL, .code == REL_Y, .value = ydelta } for that single movement). The synchronization events ({ .type == EV_SYN, .code == 0, .value == 0 }) are used as a sentinel or separator, denoting the end of related events.
Because of this, you'll need to append an { .type == EV_SYN, .code == 0, .value == 0 } input event after each individual action (mouse movement, key press, key release, and so on). Think of it as the equivalent of a newline, for line-buffered input.
For example, the following code moves the mouse diagonally down right by a single pixel.
struct input_event event[3];
memset(event, 0, sizeof event);
event[0].type = EV_REL;
event[0].code = REL_X;
event[0].value = +1; /* Right */
event[1].type = EV_REL;
event[1].code = REL_Y;
event[1].value = +1; /* Down */
event[2].type = EV_SYN;
event[2].code = 0;
event[2].value = 0;
if (write(fd, event, sizeof event) != sizeof event)
fprintf(stderr, "Failed to inject mouse movement event.\n");
The failure case is not fatal; it only means the events were not injected (although I don't see how that could happen in current kernels; better be defensive, just in case). You can simply retry the same again, or ignore the failure (but letting the user know, so they can investigate, if it ever happens). So log it or output a warning, but no need for it to cause the daemon/service to exit.
Destroy the device:
ioctl(fd, UI_DEV_DESTROY);
close(fd);
The device does get automatically destroyed when the last duplicate of the original opened descriptor gets closed, but I recommend doing it explicitly as above.
Putting steps 1-5 in a function, you get something like
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
static const unsigned int allow_event_type[] = {
EV_KEY,
EV_SYN,
EV_REL,
};
#define ALLOWED_EVENT_TYPES (sizeof allow_event_type / sizeof allow_event_type[0])
static const unsigned int allow_key_code[] = {
KEY_SPACE,
BTN_LEFT,
BTN_MIDDLE,
BTN_RIGHT,
};
#define ALLOWED_KEY_CODES (sizeof allow_key_code / sizeof allow_key_code[0])
static const unsigned int allow_rel_code[] = {
REL_X,
REL_Y,
REL_WHEEL,
};
#define ALLOWED_REL_CODES (sizeof allow_rel_code / sizeof allow_rel_code[0])
static int uinput_open(const char *name, const unsigned int vendor, const unsigned int product, const unsigned int version)
{
struct uinput_user_dev dev;
int fd;
size_t i;
if (!name || strlen(name) < 1 || strlen(name) >= UINPUT_MAX_NAME_SIZE) {
errno = EINVAL;
return -1;
}
fd = open("/dev/uinput", O_RDWR);
if (fd == -1)
return -1;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
do {
for (i = 0; i < ALLOWED_EVENT_TYPES; i++)
if (ioctl(fd, UI_SET_EVBIT, allow_event_type[i]) == -1)
break;
if (i < ALLOWED_EVENT_TYPES)
break;
for (i = 0; i < ALLOWED_KEY_CODES; i++)
if (ioctl(fd, UI_SET_KEYBIT, allow_key_code[i]) == -1)
break;
if (i < ALLOWED_KEY_CODES)
break;
for (i = 0; i < ALLOWED_REL_CODES; i++)
if (ioctl(fd, UI_SET_RELBIT, allow_rel_code[i]) == -1)
break;
if (i < ALLOWED_REL_CODES)
break;
if (write(fd, &dev, sizeof dev) != sizeof dev)
break;
if (ioctl(fd, UI_DEV_CREATE) == -1)
break;
/* Success. */
return fd;
} while (0);
/* FAILED: */
{
const int saved_errno = errno;
close(fd);
errno = saved_errno;
return -1;
}
}
static void uinput_close(const int fd)
{
ioctl(fd, UI_DEV_DESTROY);
close(fd);
}
which seem to work fine, and requires no libraries (other than the standard C library).
It is important to realize that the Linux input subsystem, including uinput and struct input_event, are binary interfaces to the Linux kernel, and therefore will be kept backwards compatible (except for pressing technical reasons, like security issues or serious conflicts with other parts of the kernel). (The desire to wrap everything under the freedesktop.org or systemd umbrella is not one.)

How to create a non blocking socket without fcntl?

I'm working on a system that doesn't run unix / linux / windows or any familiar OS.
Yet, there are some libraries for sockets, one of them is socket.h.
The thing is that there is setsockopt function there, and some options, but there isn't fcntl.h library. I saw that this is the only way to get and set the socket's flags (O_NONBLOCK is what i seek).
Also, I saw that It is possible to use setsockopt with so_rcvtimeo and so_sndtimeo. I tried it and it is still blocking. The connect function was stuck when I was unplugging the ethernet cable right before the execution reached the connect line (in debug mode of course).
Is there a way to do it with the socket.h library only ?
Thanks,
Edit:
I'm using a system with Texas Instruments chip.
This is my current code, which doesn't work. "connect" returns -1 and I don't have errno to check what went wrong.
if (setsockopt(s, SOL_SOCKET, SO_BLOCKING, (char *)&isBlockingOption, sizeof(isBlockingOption)) < 0) {
/* closing the socket and exiting */
}
connect(s, &controlAddressStruct, sizeof(controlAddressStruct));
FD_ZERO(&conSocketSet);
FD_SET(s, &conSocketSet);
connectTimeout.tv_sec = 5;
connectTimeout.tv_usec = 0;
selectRet = fdselect( (int)s + 1, NULL, &conSocketSet, NULL, &connectTimeout);
if (selectRet == 1) {
socketLen = sizeof(so_error);
getsockopt(s, SOL_SOCKET, SO_ERROR, &so_error, &socketLen);
if (so_error == 0) {
return s;
}
}
return INVALID_SOCKET;
now, when the ethernet cable is plugged between the two systems, so_error = 0 and s is returned. Then when I read the FTP server reply, I get error so I exit the program.
But, if I removed the setsockopt for the SO_BLOCKING, everything is fine and the FTP server sends me the requested file.
If the send() and recv() interfaces are similar to the BSD sockets interface at all, the fourth parameter should correspond to flags. If so, you may be able to pass in MSG_DONTWAIT to the fourth parameter to effect non-blocking I/O.

Socket programming for multi-clients with 'select()' in C

This is a question about socket programming for multi-client.
While I was thinking how to make my single client and server program
to multi clients,I encountered how to implement this.
But even if I was searching for everything, kind of confusion exists.
I was thinking to implement with select(), because it is less heavy than fork.
but I have much global variables not to be shared, so I hadn`t considered thread to use.
and so to use select(), I could have the general knowledge about FD_functions to utilize, but here I have my question, because generally in the examples on websites, it only shows multi-client server program...
Since I use sequential recv() and send() in client and also in server program
that work really well when it`s single client and server, but
I have no idea about how it must be changed for multi cilent.
Does the client also must be unblocking?
What are all requirements for select()?
The things I did on my server program to be multi-client
1) I set my socket option for reuse address, with SO_REUSEADDR
2) and set my server as non-blocking mode with O_NONBLOCK using fctl().
3) and put the timeout argument as zero.
and proper use of FD_functions after above.
But when I run my client program one and many more, from the second client,
client program blocks, not getting accepted by server.
I guess the reason is because I put my server program`s main function part
into the 'recv was >0 ' case.
for example with my server code,
(I`m using temp and read as fd_set, and read as master in this case)
int main(void)
{
int conn_sock, listen_sock;
struct sockaddr_in s_addr, c_addr;
int rq, ack;
char path[100];
int pre, change, c;
int conn, page_num, x;
int c_len = sizeof(c_addr);
int fd;
int flags;
int opt = 1;
int nbytes;
fd_set read, temp;
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("socket error!");
return 1;
}
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_port = htons(3500);
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1)
{
perror("Server-setsockopt() error ");
exit(1);
}
flags = fcntl(listen_sock, F_GETFL, 0);
fcntl(listen_sock, F_SETFL, flags | O_NONBLOCK);
//fcntl(listen_sock, F_SETOWN, getpid());
bind(listen_sock, (struct sockaddr*) &s_addr, sizeof(s_addr));
listen(listen_sock, 8);
FD_ZERO(&read);
FD_ZERO(&temp);
FD_SET(listen_sock, &read);
while (1)
{
temp = read;
if (select(FD_SETSIZE, &temp, (fd_set *) 0, (fd_set *) 0,
(struct timeval *) 0) < 1)
{
perror("select error:");
exit(1);
}
for (fd = 0; fd < FD_SETSIZE; fd++)
{
//CHECK all file descriptors
if (FD_ISSET(fd, &temp))
{
if (fd == listen_sock)
{
conn_sock = accept(listen_sock, (struct sockaddr *) &c_addr, &c_len);
FD_SET(conn_sock, &read);
printf("new client got session: %d\n", conn_sock);
}
else
{
nbytes = recv(fd, &conn, 4, 0);
if (nbytes <= 0)
{
close(fd);
FD_CLR(fd, &read);
}
else
{
if (conn == Session_Rq)
{
ack = Session_Ack;
send(fd, &ack, sizeof(ack), 0);
root_setting();
c = 0;
while (1)
{
c++;
printf("in while loop\n");
recv(fd, &page_num, 4, 0);
if (c > 1)
{
change = compare_with_pre_page(pre, page_num);
if (change == 1)
{
page_stack[stack_count] = page_num;
stack_count++;
}
else
{
printf("same as before page\n");
}
} //end of if
else if (c == 1)
{
page_stack[stack_count] = page_num;
stack_count++;
}
printf("stack count:%d\n", stack_count);
printf("in page stack: <");
for (x = 0; x < stack_count; x++)
{
printf(" %d ", page_stack[x]);
}
printf(">\n");
rq_handler(fd);
if (logged_in == 1)
{
printf("You are logged in state now, user: %s\n",
curr_user.ID);
}
else
{
printf("not logged in.\n");
c = 0;
}
pre = page_num;
} //end of while
} //end of if
}
} //end of else
} //end of fd_isset
} //end of for loop
} //end of outermost while
}
if needed for code explanation : What I was about to work of this code was,
to make kind of web pages to implement 'browser' for server.
I wanted to make every client get session for server to get login-page or so.
But the execution result is, as I told above.
Why is that?
the socket in the client program must be non-blocking mode too
to be used with non-blocking Server program to use select()?
Or should I use fork or thread to make multi client and manage with select?
The reason I say this is, after I considered a lot about this problem,
'select()' seems only proper for multi client chatting program... that many
'forked' or 'threaded' clients can pend to, in such as chat room.
how do you think?...
Is select also possible or proper thing to use for normal multi-client program?
If there something I missed to let my multi client program work fine,
please give me some knowledge of yours or some requirements for the proper use of select.
I didn`t know multi-client communication was not this much easy before :)
I also considered to use epoll but I think I need to understand first about select well.
Thanks for reading.
Besides the fact you want to go from single-client to multi-client, it's not very clear what's blocking you here.
Are you sure you fully understood how does select is supposed to work ? The manual (man 2 select on Linux) may be helpful, as it provides a simple example. You can also check Wikipedia.
To answer your questions :
First of all, are you sure you need non-blocking mode for your sockets ? Unless you have a good reason to do so, blocking sockets are also fine for multi-client networking.
Usually, there are basically two ways to deal with multi-clients in C: fork, or select. The two aren't really used altogether (or I don't know how :-) ). Models using lightweight threads are essentially asynchronous programming (did I mention it also depends on what you mean by 'asynchronous' ?) and may be a bit overkill for what you seem to do (a good example in C++ is Boost.Asio).
As you probably already know, the main problem when dealing with more than one client is that I/O operations, like a read, are blocking, not letting us know when there's a new client, or when a client has said something.
The fork way is pretty straighforward : the server socket (the one which accepts the connections) is in the main process, and each time it accepts a new client, it forks a whole new process just to monitor this new client : this new process will be dedicated to it. Since there's one process per client, we don't care if i/o operations are blocking or not.
The select way allows us to monitor multiple clients in one same process : it is a multiplexer telling us when something happens on the sockets we give it. The base idea, on the server side, is first to put the server socket on the read_fds FD_SET of the select. Each time select returns, you need to do a special check for it : if the server socket is set in the read_fds set (using FD_ISSET(...)), it means you have a new client connecting : you can then call accept on your server socket to create the connection.
Then you have to put all your clients sockets in the fd_sets you give to select in order to monitor any change on it (e.g., incoming messages).
I'm not really sure of what you don't understand about select, so that's for the big explaination. But long story short, select is a clean and neat way to do single-threaded, synchronous networking, and it can absolutely manage multiple clients at the same time without using any fork or threads. Be aware though that if you absolutely want to deal with non-blocking sockets with select, you have to deal extra error conditions that wouldn't be in a blocking way (the Wikipedia example shows it well as they have to check if errno isn't EWOULDBLOCK). But that's another story.
EDIT : Okay, with a little more code it's easier to know what's wrong.
select's first parameter should be nfds+1, i.e. "the highest-numbered file descriptor in any of the three sets, plus 1" (cf. manual), not FD_SETSIZE, which is the maximum size of an FD_SET. Usually it is the last accept-ed client socket (or the server socket at beginning) who has it.
You shouldn't do the "CHECK all file descriptors" for loop like that. FD_SETSIZE, e.g. on my machine, equal to 1024. That means once select returns, even if you have just one client you would be passing in the loop 1024 times ! You can set fd to 0 (like in the Wikipedia example), but since 0 is stdin, 1 stdout and 2 stderr, unless you're monitoring one of those, you can directly set it to your server socket's fd (since it is probably the first of the monitored sockets, given socket numbers always increase), and iterate until it is equal to "nfds" (the currently highest fd).
Not sure that it is mandatory, but before each call to select, you should clear (with FD_ZERO for example) and re-populate your read fd_set with all the sockets you want to monitor (i.e. your server socket and all your clients sockets). Once again, inspire yourself of the Wikipedia example.

Reading from a promiscuous network device

I want to write a real-time analysis tool for wireless traffic.
Does anyone know how to read from a promiscuous (or sniffing) device in C?
I know that you need to have root access to do it. I was wondering if anyone knows what functions are necessary to do this. Normal sockets don't seem to make sense here.
On Linux you use a PF_PACKET socket to read data from a raw device, such as an ethernet interface running in promiscuous mode:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
This will send copies of every packet received up to your socket. It is quite likely that you don't really want every packet, though. The kernel can perform a first level of filtering using BPF, the Berkeley Packet Filter. BPF is essentially a stack-based virtual machine: it handles a small set of instructions such as:
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
BPF's exit code tells the kernel whether to copy the packet to the socket or not. It is possible to write relatively small BPF programs directly, using setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ). (WARNING: The kernel takes a struct sock_fprog, not a struct bpf_program, do not mix those up or your program will not work on some platforms).
For anything reasonably complex, you really want to use libpcap. BPF is limited in what it can do, in particular in the number of instructions it can execute per packet. libpcap will take care of splitting a complex filter up into two pieces, with the kernel performing a first level of filtering and the more-capable user-space code dropping the packets it didn't actually want to see.
libpcap also abstracts the kernel interface out of your application code. Linux and BSD use similar APIs, but Solaris requires DLPI and Windows uses something else.
I once had to listen on raw ethernet frames and ended up creating a wrapper for this. By calling the function with the device name, ex eth0 I got a socket in return that was in promiscuous mode.
What you need to do is to create a raw socket and then put it into promiscuous mode. Here is how I did it.
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
return raw_socket;
}
Then when you have your socket you can just use select to handle packets as they arrive.
You could use the pcap library (see http://www.tcpdump.org/pcap.htm) which is also used by tcpdump and Wireshark.
Why wouldn't you use something like WireShark?
It is open source, so at least you could learn a few things from it if you don't want to just use it.
WireShark on linux has the capability to capture the PLCP (physical layer convergence protocol) header information.

Resources