My app creates a tap interface, and everything works well. But on FreeBSD, when it exits, the tap interface remains. To delete it, I have to manually run this command:
sudo ifconfig tap0 destroy
But I'd like to do this programmatically within my application. Where can I find the docs for SIOCIFDESTROY? Here is what I've tried when my app exits:
struct ifreq ifr;
memset(&ifr, '\0', sizeof(ifr));
strcpy(ifr.ifr_name, "tap0");
int sock = socket(PF_INET, SOCK_STREAM, 0);
err = ioctl(sock, SIOCIFDESTROY, &ifr);
At this point, err is zero, but the tap interface still exists when the app ends. Anyone know what else I might be missing?
The tricky part was trying to find documentation to describe is the parameter to pass to ioctl(). I never did find anything decent to read.
Turns out a completely blank ifreq with just the tap interface name set is all that is needed. In addition to the original code I included in the question, also note that I close the tap device file descriptor prior to deleting the actual tap interface. I can only imagine that might also be relevant:
close(device_fd);
struct ifreq ifr;
memset(&ifr, '\0', sizeof(ifr));
strcpy(ifr.ifr_name, "tap0");
int sock = socket(PF_INET, SOCK_STREAM, 0);
err = ioctl(sock, SIOCIFDESTROY, &ifr);
Related
I wrote a systray area applet that displays the status of IWD backed WiFi connection. Right now my app polls iwctl station wlp4s0 show every minute and parses the result. Is there a way to avoid polling and use some sort of a notification hook?
I have found a way to do this with linux netlink protocol.
man 7 netlink
apt get install libnl-3-dev libnl-genl-3-dev
Basically:
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
struct sockaddr_nl snl = { .... };
bind(fd, &snl, sizeof(snl));
while (1) {
recv(fd, buf, sizeof(buf), 0);
struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
...
}
recv will block until events related to network interfaces happen, then data you need is in nlh.
For example check for new connection:
if (nlh->nlmsg_type == RTM_NEWADDR) ...
I need to find the specific interface which is used by a socket, so that I can keep stats for it, using the sysfs files (/sys/class/net/<IF>/statistics/etc).
I've tried two different approaches in the test code below, but both fail. The first one connects to a remote server, and uses ioctl with SIOCGIFNAME, but this fails with 'no such device'. The second one instead uses getsockopt with SO_BINDTODEVICE, but this again fails (it sets the name length to 0).
Any ideas on why these are failing, or how to get the I/F name? after compiling, run the test code as test "a.b.c.d", where a.b.c.d is any IPV4 address which is listening on port 80. Note that I've compiled this on Centos 7, which doesn't appear to have IFNAMSZ in <net/if.h>, so you may have to comment out the #define IFNAMSZ line to get this to compile on other systems.
Thanks.
EDIT
I've since found that this is essentially a dupe of How can I get the interface name/index associated with a TCP socket?, so I should probably remove this. (Only) one of the answers there is correct (https://stackoverflow.com/a/37987807/785194) - get your local IP address with getsockname, and then look up this address in the list returned by getifaddrs.
On the general issue that sockets are essentially dynamic (mentioned below, and several times in the other question): not really relevant. I've checked the kernel source, and sockets have an interface index and interface name, and the API includes at least three ways to get the current name, and other routines to look up the name from the index, and vice-versa. However, the index is somtimes zero, which is not valid, which is why the getsockopt version below fails. No idea why ioctl fails.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main(int argc, char **argv) {
int sock;
struct sockaddr_in dst_sin;
struct in_addr haddr;
if(argc != 2)
return 1;
if(inet_aton(argv[1], &haddr) == 0) {
printf("'%s' is not a valid IP address\n", argv[1]);
return 1;
}
dst_sin.sin_family = AF_INET;
dst_sin.sin_port = htons(80);
dst_sin.sin_addr = haddr;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
if(connect(sock, (struct sockaddr*)&dst_sin, sizeof(dst_sin)) < 0) {
perror("connect");
return 1;
}
printf(
"connected to %s:%d\n",
inet_ntoa(dst_sin.sin_addr), ntohs(dst_sin.sin_port));
#if 0 // ioctl fails with 'no such device'
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// get the socket's interface index into ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
return 1;
}
// get the I/F name for ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFNAME, &ifr) < 0) {
perror("SIOCGIFNAME");
return 1;
}
printf("I/F is on '%s'\n", ifr.ifr_name);
#else // only works on Linux 3.8+
#define IFNAMSZ IFNAMSIZ // Centos7 bug in if.h??
char optval[IFNAMSZ] = {0};
socklen_t optlen = IFNAMSZ;
if(getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &optval, &optlen) < 0) {
perror("getsockopt");
return 1;
}
if(!optlen) {
printf("invalid optlen\n");
return 1;
}
printf("I/F is on '%s'\n", optval);
#endif
close(sock);
return 0;
}
TCP (and UDP) sockets are not bound to interfaces, so there is really no facility for answering this query. Now it's true that in general, a given socket will end up passing packets to a specific interface based on the address of the peer endpoint, but that is nowhere encoded in the socket. That's a routing decision that is made dynamically.
For example, let's say that you are communicating with a remote peer that is not directly on your local LAN. And let's say you have a default gateway configured to be 192.168.2.1 via eth0. There is nothing to prevent your configuring a second gateway, say, 192.168.3.1 via eth1, then taking eth0 down. As long as the new gateway can also reach the remote IP, eth1 can now be used to reach the destination and your session should continue uninterrupted.
So, if you need this info, you'll need to infer it from routing entries (but realize that it is not guaranteed to be static, even though in practice it will likely be so). You can obtain the address of your peer from getpeername(2). You can then examine the available routes to determine which one will get you there.
To do this, you could parse and interpret /proc/net/route for yourself, or you can just ask the ip command. For example, my route to an (arbitrary) ibm.com address goes through my eth0 interface, and connecting a socket to there, my local address will be 192.168.0.102 (which should match what getsockname(2) on the connected socket returns):
$ ip route get 129.42.38.1
129.42.38.1 via 192.168.0.1 dev eth0 src 192.168.0.102
cache
Code snippet below; basically, I am grabbing the active vt and issuing an ioctl KDGETLED against that terminal for the current state of the capslock/numlock/scrolllock keys and I always get result=0, regardless of the state of the lock keys.
I've tried this on multiple Linux boxes, all running variants of Ubuntu (e.g. Mint). I've tried other fds for the KDGETLED command such as "/dev/tty", "/dev/console", 0, etc. I'm running into the same problem with KDGKBLED. Are others experiencing the same issue, am I doing something silly, am I running into poorly written drivers, or something else?
int fd;
vt_stat stat;
fd = open("/dev/tty0", O_RDONLY);
if (ioctl(fd, VT_GETSTATE, &stat) == -1) {
fprintf(stderr, "Error on VT_GETSTATE\n");
exit(1);
}
close(fd);
char tty[128];
sprintf(tty, "/dev/tty%d", stat.v_active);
printf("Query tty: %s\n", tty);
char result;
fd = open(tty, O_RDWR | O_NDELAY, 0);
if (ioctl(fd, KDGETLED, &result) == -1) {
fprintf(stderr, "Error on KDGETLED\n");
exit(1);
}
close(fd);
printf("LED flag state: %d\n", result);
Thanks, in advance, to all who review my question.
Checkout the driver code, especially the struct file_operations instance for that driver, and check the function assigned to the .ioctl member - if that is poorly coded (I've seen a lot of shitty stuff happening in ioctls) then that is definitely your issue.
In this case I am pretty sure it is the drivers fault. As long the ioctl command shows no compile error, everything - especially error handling and input checking - is the task of the driver.
Is there possible that accept() (on redhat Enterprise 4/linux kernel 2.6) return a same socket value for different tcp connections from the same process of a same application and same machine?
I am so surprised that when I got such a result that many connections have the same socket value on server side when I checked the log file!! How is it possible?!!
By the way, I am using TCP blocking socket to listen.
main(){
int fd, clientfd, len, clientlen;
sockaddr_in address, clientaddress;
fd = socket(PF_INET, SOCK_STREAM, 0);
....
memset(&address, 0, sizeof address);
address.sin_address = AF_INET;
address.sin_port = htons(port);
....
bind(fd, &address, sizeof address);
listen(fd, 100);
do {
clientfd = accept(fd, &clientaddress, &clientlen);
if (clientfd < 0) {
....
}
printf("clientfd = %d", clientfd);
switch(fork()){
case 0:
//do something else
exit(0);
default:
...
}
} while(1);
}
my question is that why printf("clientfd = %d"); prints a same number for different connections!!!
If server runs in multiple processes (like Apache with mpm worker model), then every process has its own file descriptor numbering starting from 0.
In other words, it is quite possible that different processes will get exact same socket file descriptor number. However, fd number it does not really mean anything. They still refer to different underlying objects, and different local TCP ports.
The socket is just a number.It is a hook to a data structure for the kernel.
BTW TCP uses IP. Look up the RFC
That printf() doesn't print any FD at all. It's missing an FD parameter. What you are seeing could be a return address or any other arbitrary junk on the stack.
I am trying to implement a netdevice (net_device) in linux kernel. This is simple net_device which pass the command/data from user space to kernel space and vice versa this is the goal of this simple net_device. I am using socket for passing command/data from user space to kernel space . After googling i successed in registering net_device and able to see my device in /sys/class/net/abc0 (device name)
when coming to file operation there is no clear idea of the flow
struct net_device_ops
{
.ndo_open =open,
.ndo_close = close,
.ndo_start_xmit = start_xmit
}
if i issue write in socket will it call start_xmit in data link layer.
If i want to call open method, how to call it using socket
How to call start_xmit using socket
How will i find , there is data packet in the receive buffer and pass it to user space.
There is no clear flow/information about simple net_device (except ethernet) can any suggest a link/pdf.
I tried writing simple socket program to test open,close,start_xmit. where socket read/write is not calling open,close,star_xmit .
Is there any way to test the developed net_device ?
Thank you
I found how to test the open,close function .
type : ifconfig abc0(Device name) up will call open method
type : ifconfig abc0(Device name) down will call close method
Can some one help me how to test these methods with sockets.
SIOCSIFFLAGS, -> IFF_UP you can actually set or unset it while doing an ioctl to the netdevice abc0.
first off you have to create a dgram socket,
then use ifreq structure defined in net/if.h
and fill interface and iff_flags
iff_flags can be set with IFF_UP or can be negated with the same IFF_UP to make interface down
and then close the socket.
#include <net/if.h>
....
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
goto fail;
}
struct ifreq ifreq;
strcpy(ifreq.ifr_name, "abcd0");
ifreq.iff_flags |= IFF_UP;
if (ioctl(sock, &ifreq, sizeof(ifreq) < 0) {
perror("ioctl setting interface up");
}
ifreq.iff_flags ~= IFF_UP;
if (ioctl(sock, &ifreq, sizeof(ifreq) < 0) {
perror("ioctl setting interface down");
}
close(sock);
offtopic:
will you please share your code? we can understand too about your network device :)